|
Packit Service |
31306d |
/*
|
|
Packit Service |
31306d |
* keyfiles.c - private and public key handling for authentication.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This file is part of the SSH Library
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* Copyright (c) 2003-2009 by Aris Adamantiadis
|
|
Packit Service |
31306d |
* Copyright (c) 2009 by Andreas Schneider <asn@cryptomilk.org>
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is free software; you can redistribute it and/or modify
|
|
Packit Service |
31306d |
* it under the terms of the GNU Lesser General Public License as published by
|
|
Packit Service |
31306d |
* the Free Software Foundation; either version 2.1 of the License, or (at your
|
|
Packit Service |
31306d |
* option) any later version.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* The SSH Library is distributed in the hope that it will be useful, but
|
|
Packit Service |
31306d |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit Service |
31306d |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
Packit Service |
31306d |
* License for more details.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
31306d |
* along with the SSH Library; see the file COPYING. If not, write to
|
|
Packit Service |
31306d |
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
Packit Service |
31306d |
* MA 02111-1307, USA.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "config.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include <ctype.h>
|
|
Packit Service |
31306d |
#include <errno.h>
|
|
Packit Service |
31306d |
#include <stdio.h>
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#include "libssh/priv.h"
|
|
Packit Service |
31306d |
#include "libssh/session.h"
|
|
Packit Service |
31306d |
#include "libssh/buffer.h"
|
|
Packit Service |
31306d |
#include "libssh/misc.h"
|
|
Packit Service |
31306d |
#include "libssh/dh.h"
|
|
Packit Service |
31306d |
#include "libssh/pki.h"
|
|
Packit Service |
31306d |
#include "libssh/options.h"
|
|
Packit Service |
31306d |
#include "libssh/knownhosts.h"
|
|
Packit Service |
31306d |
/*todo: remove this include */
|
|
Packit Service |
31306d |
#include "libssh/string.h"
|
|
Packit Service |
31306d |
#include "libssh/token.h"
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#ifndef _WIN32
|
|
Packit Service |
31306d |
# include <netinet/in.h>
|
|
Packit Service |
31306d |
# include <arpa/inet.h>
|
|
Packit Service |
31306d |
#endif
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @addtogroup libssh_session
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @{
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Return one line of known host file.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* This will return a token array containing (host|ip), keytype and key.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[out] file A pointer to the known host file. Could be pointing to
|
|
Packit Service |
31306d |
* NULL at start.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] filename The file name of the known host file.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[out] found_type A pointer to a string to be set with the found key
|
|
Packit Service |
31306d |
* type.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns The found_type type of key (ie "dsa","ssh-rsa"). Don't
|
|
Packit Service |
31306d |
* free that value. NULL if no match was found or the file
|
|
Packit Service |
31306d |
* was not found.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file,
|
|
Packit Service |
31306d |
const char *filename,
|
|
Packit Service |
31306d |
const char **found_type)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
char buffer[4096] = {0};
|
|
Packit Service |
31306d |
char *ptr;
|
|
Packit Service |
31306d |
struct ssh_tokens_st *tokens;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (*file == NULL) {
|
|
Packit Service |
31306d |
*file = fopen(filename,"r");
|
|
Packit Service |
31306d |
if (*file == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
while (fgets(buffer, sizeof(buffer), *file)) {
|
|
Packit Service |
31306d |
ptr = strchr(buffer, '\n');
|
|
Packit Service |
31306d |
if (ptr) {
|
|
Packit Service |
31306d |
*ptr = '\0';
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ptr = strchr(buffer,'\r');
|
|
Packit Service |
31306d |
if (ptr) {
|
|
Packit Service |
31306d |
*ptr = '\0';
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (buffer[0] == '\0' || buffer[0] == '#') {
|
|
Packit Service |
31306d |
continue; /* skip empty lines */
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
tokens = ssh_tokenize(buffer, ' ');
|
|
Packit Service |
31306d |
if (tokens == NULL) {
|
|
Packit Service |
31306d |
fclose(*file);
|
|
Packit Service |
31306d |
*file = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (tokens->tokens[0] == NULL ||
|
|
Packit Service |
31306d |
tokens->tokens[1] == NULL ||
|
|
Packit Service |
31306d |
tokens->tokens[2] == NULL)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
/* it should have at least 3 tokens */
|
|
Packit Service |
31306d |
ssh_tokens_free(tokens);
|
|
Packit Service |
31306d |
continue;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
*found_type = tokens->tokens[1];
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return tokens;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
fclose(*file);
|
|
Packit Service |
31306d |
*file = NULL;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* we did not find anything, end of file*/
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @brief Check the public key in the known host line matches the public key of
|
|
Packit Service |
31306d |
* the currently connected server.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] session The SSH session to use.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] tokens A list of tokens in the known_hosts line.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 1 if the key matches, 0 if the key doesn't match and -1
|
|
Packit Service |
31306d |
* on error.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static int check_public_key(ssh_session session, char **tokens) {
|
|
Packit Service |
31306d |
ssh_string pubkey_blob = NULL;
|
|
Packit Service |
31306d |
ssh_buffer pubkey_buffer;
|
|
Packit Service |
31306d |
char *pubkey_64;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* ssh-dss or ssh-rsa */
|
|
Packit Service |
31306d |
pubkey_64 = tokens[2];
|
|
Packit Service |
31306d |
pubkey_buffer = base64_to_bin(pubkey_64);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (pubkey_buffer == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Verifying that server is a known host: base64 error");
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_dh_get_current_server_publickey_blob(session, &pubkey_blob);
|
|
Packit Service |
31306d |
if (rc != 0) {
|
|
Packit Service |
31306d |
ssh_buffer_free(pubkey_buffer);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (ssh_buffer_get_len(pubkey_buffer) != ssh_string_len(pubkey_blob)) {
|
|
Packit Service |
31306d |
ssh_string_free(pubkey_blob);
|
|
Packit Service |
31306d |
ssh_buffer_free(pubkey_buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* now test that they are identical */
|
|
Packit Service |
31306d |
if (memcmp(ssh_buffer_get(pubkey_buffer), ssh_string_data(pubkey_blob),
|
|
Packit Service |
31306d |
ssh_buffer_get_len(pubkey_buffer)) != 0) {
|
|
Packit Service |
31306d |
ssh_string_free(pubkey_blob);
|
|
Packit Service |
31306d |
ssh_buffer_free(pubkey_buffer);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_string_free(pubkey_blob);
|
|
Packit Service |
31306d |
ssh_buffer_free(pubkey_buffer);
|
|
Packit Service |
31306d |
return 1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @internal
|
|
Packit Service |
31306d |
* @brief Check if a hostname matches a openssh-style hashed known host.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] host The host to check.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @param[in] hashed The hashed value.
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @returns 1 if it matches, 0 otherwise.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
static int match_hashed_host(const char *host, const char *sourcehash)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
/* Openssh hash structure :
|
|
Packit Service |
31306d |
* |1|base64 encoded salt|base64 encoded hash
|
|
Packit Service |
31306d |
* hash is produced that way :
|
|
Packit Service |
31306d |
* hash := HMAC_SHA1(key=salt,data=host)
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
unsigned char buffer[256] = {0};
|
|
Packit Service |
31306d |
ssh_buffer salt;
|
|
Packit Service |
31306d |
ssh_buffer hash;
|
|
Packit Service |
31306d |
HMACCTX mac;
|
|
Packit Service |
31306d |
char *source;
|
|
Packit Service |
31306d |
char *b64hash;
|
|
Packit Service |
31306d |
int match;
|
|
Packit Service |
31306d |
unsigned int size;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (strncmp(sourcehash, "|1|", 3) != 0) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
source = strdup(sourcehash + 3);
|
|
Packit Service |
31306d |
if (source == NULL) {
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
b64hash = strchr(source, '|');
|
|
Packit Service |
31306d |
if (b64hash == NULL) {
|
|
Packit Service |
31306d |
/* Invalid hash */
|
|
Packit Service |
31306d |
SAFE_FREE(source);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
*b64hash = '\0';
|
|
Packit Service |
31306d |
b64hash++;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
salt = base64_to_bin(source);
|
|
Packit Service |
31306d |
if (salt == NULL) {
|
|
Packit Service |
31306d |
SAFE_FREE(source);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
hash = base64_to_bin(b64hash);
|
|
Packit Service |
31306d |
SAFE_FREE(source);
|
|
Packit Service |
31306d |
if (hash == NULL) {
|
|
Packit Service |
31306d |
ssh_buffer_free(salt);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
mac = hmac_init(ssh_buffer_get(salt), ssh_buffer_get_len(salt), SSH_HMAC_SHA1);
|
|
Packit Service |
31306d |
if (mac == NULL) {
|
|
Packit Service |
31306d |
ssh_buffer_free(salt);
|
|
Packit Service |
31306d |
ssh_buffer_free(hash);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
size = sizeof(buffer);
|
|
Packit Service |
31306d |
hmac_update(mac, host, strlen(host));
|
|
Packit Service |
31306d |
hmac_final(mac, buffer, &size);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (size == ssh_buffer_get_len(hash) &&
|
|
Packit Service |
31306d |
memcmp(buffer, ssh_buffer_get(hash), size) == 0) {
|
|
Packit Service |
31306d |
match = 1;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
match = 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
ssh_buffer_free(salt);
|
|
Packit Service |
31306d |
ssh_buffer_free(hash);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"Matching a hashed host: %s match=%d", host, match);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return match;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* How it's working :
|
|
Packit Service |
31306d |
* 1- we open the known host file and bitch if it doesn't exist
|
|
Packit Service |
31306d |
* 2- we need to examine each line of the file, until going on state SSH_SERVER_KNOWN_OK:
|
|
Packit Service |
31306d |
* - there's a match. if the key is good, state is SSH_SERVER_KNOWN_OK,
|
|
Packit Service |
31306d |
* else it's SSH_SERVER_KNOWN_CHANGED (or SSH_SERVER_FOUND_OTHER)
|
|
Packit Service |
31306d |
* - there's no match : no change
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @brief This function is deprecated
|
|
Packit Service |
31306d |
*
|
|
Packit Service |
31306d |
* @deprecated Please use ssh_session_is_known_server()
|
|
Packit Service |
31306d |
* @see ssh_session_is_known_server()
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_is_server_known(ssh_session session)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
FILE *file = NULL;
|
|
Packit Service |
31306d |
char *host;
|
|
Packit Service |
31306d |
char *hostport;
|
|
Packit Service |
31306d |
const char *type;
|
|
Packit Service |
31306d |
int match;
|
|
Packit Service |
31306d |
int i = 0;
|
|
Packit Service |
31306d |
char *files[3];
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
struct ssh_tokens_st *tokens;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
int ret = SSH_SERVER_NOT_KNOWN;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->opts.knownhosts == NULL) {
|
|
Packit Service |
31306d |
if (ssh_options_apply(session) < 0) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_REQUEST_DENIED,
|
|
Packit Service |
31306d |
"Can't find a known_hosts file");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_SERVER_FILE_NOT_FOUND;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->opts.host == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Can't verify host in known hosts if the hostname isn't known");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_SERVER_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->current_crypto == NULL){
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"ssh_is_host_known called without cryptographic context");
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_SERVER_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
host = ssh_lowercase(session->opts.host);
|
|
Packit Service |
31306d |
hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22);
|
|
Packit Service |
31306d |
if (host == NULL || hostport == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error_oom(session);
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
SAFE_FREE(hostport);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return SSH_SERVER_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Set the list of known hosts files */
|
|
Packit Service |
31306d |
i = 0;
|
|
Packit Service |
31306d |
if (session->opts.global_knownhosts != NULL){
|
|
Packit Service |
31306d |
files[i++] = session->opts.global_knownhosts;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
files[i++] = session->opts.knownhosts;
|
|
Packit Service |
31306d |
files[i] = NULL;
|
|
Packit Service |
31306d |
i = 0;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
do {
|
|
Packit Service |
31306d |
tokens = ssh_get_knownhost_line(&file,
|
|
Packit Service |
31306d |
files[i],
|
|
Packit Service |
31306d |
&type);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* End of file, return the current state or use next file */
|
|
Packit Service |
31306d |
if (tokens == NULL) {
|
|
Packit Service |
31306d |
++i;
|
|
Packit Service |
31306d |
if(files[i] == NULL)
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
else
|
|
Packit Service |
31306d |
continue;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
match = match_hashed_host(host, tokens->tokens[0]);
|
|
Packit Service |
31306d |
if (match == 0){
|
|
Packit Service |
31306d |
match = match_hostname(hostport, tokens->tokens[0],
|
|
Packit Service |
31306d |
strlen(tokens->tokens[0]));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (match == 0) {
|
|
Packit Service |
31306d |
match = match_hostname(host, tokens->tokens[0],
|
|
Packit Service |
31306d |
strlen(tokens->tokens[0]));
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (match == 0) {
|
|
Packit Service |
31306d |
match = match_hashed_host(hostport, tokens->tokens[0]);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
if (match) {
|
|
Packit Service |
31306d |
ssh_key pubkey = ssh_dh_get_current_server_publickey(session);
|
|
Packit Service |
31306d |
const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey));
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* We got a match. Now check the key type */
|
|
Packit Service |
31306d |
if (strcmp(pubkey_type, type) != 0) {
|
|
Packit Service |
31306d |
SSH_LOG(SSH_LOG_PACKET,
|
|
Packit Service |
31306d |
"ssh_is_server_known: server type [%s] doesn't match the "
|
|
Packit Service |
31306d |
"type [%s] in known_hosts file",
|
|
Packit Service |
31306d |
pubkey_type,
|
|
Packit Service |
31306d |
type);
|
|
Packit Service |
31306d |
/* Different type. We don't override the known_changed error which is
|
|
Packit Service |
31306d |
* more important */
|
|
Packit Service |
31306d |
if (ret != SSH_SERVER_KNOWN_CHANGED)
|
|
Packit Service |
31306d |
ret = SSH_SERVER_FOUND_OTHER;
|
|
Packit Service |
31306d |
ssh_tokens_free(tokens);
|
|
Packit Service |
31306d |
continue;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
/* so we know the key type is good. We may get a good key or a bad key. */
|
|
Packit Service |
31306d |
match = check_public_key(session, tokens->tokens);
|
|
Packit Service |
31306d |
ssh_tokens_free(tokens);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (match < 0) {
|
|
Packit Service |
31306d |
ret = SSH_SERVER_ERROR;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
} else if (match == 1) {
|
|
Packit Service |
31306d |
ret = SSH_SERVER_KNOWN_OK;
|
|
Packit Service |
31306d |
break;
|
|
Packit Service |
31306d |
} else if(match == 0) {
|
|
Packit Service |
31306d |
/* We override the status with the wrong key state */
|
|
Packit Service |
31306d |
ret = SSH_SERVER_KNOWN_CHANGED;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_tokens_free(tokens);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} while (1);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if ((ret == SSH_SERVER_NOT_KNOWN) &&
|
|
Packit Service |
31306d |
(session->opts.StrictHostKeyChecking == 0)) {
|
|
Packit Service |
31306d |
int rv = ssh_session_update_known_hosts(session);
|
|
Packit Service |
31306d |
if (rv != SSH_OK) {
|
|
Packit Service |
31306d |
ret = SSH_SERVER_ERROR;
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ret = SSH_SERVER_KNOWN_OK;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
SAFE_FREE(hostport);
|
|
Packit Service |
31306d |
if (file != NULL) {
|
|
Packit Service |
31306d |
fclose(file);
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/* Return the current state at end of file */
|
|
Packit Service |
31306d |
return ret;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @deprecated Please use ssh_session_export_known_hosts_entry()
|
|
Packit Service |
31306d |
* @brief This function is deprecated.
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
char * ssh_dump_knownhost(ssh_session session) {
|
|
Packit Service |
31306d |
ssh_key server_pubkey = NULL;
|
|
Packit Service |
31306d |
char *host;
|
|
Packit Service |
31306d |
char *hostport;
|
|
Packit Service |
31306d |
size_t len = 4096;
|
|
Packit Service |
31306d |
char *buffer;
|
|
Packit Service |
31306d |
char *b64_key;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->opts.host == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Can't write host in known hosts if the hostname isn't known");
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
host = ssh_lowercase(session->opts.host);
|
|
Packit Service |
31306d |
/* If using a nonstandard port, save the host in the [host]:port format */
|
|
Packit Service |
31306d |
if (session->opts.port > 0 && session->opts.port != 22) {
|
|
Packit Service |
31306d |
hostport = ssh_hostport(host, session->opts.port);
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
if (hostport == NULL) {
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
host = hostport;
|
|
Packit Service |
31306d |
hostport = NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->current_crypto==NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL, "No current crypto context");
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
server_pubkey = ssh_dh_get_current_server_publickey(session);
|
|
Packit Service |
31306d |
if (server_pubkey == NULL){
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL, "No public key present");
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
buffer = calloc (1, 4096);
|
|
Packit Service |
31306d |
if (!buffer) {
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_pki_export_pubkey_base64(server_pubkey, &b64_key);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
SAFE_FREE(buffer);
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
return NULL;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
snprintf(buffer, len,
|
|
Packit Service |
31306d |
"%s %s %s\n",
|
|
Packit Service |
31306d |
host,
|
|
Packit Service |
31306d |
server_pubkey->type_c,
|
|
Packit Service |
31306d |
b64_key);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(host);
|
|
Packit Service |
31306d |
SAFE_FREE(b64_key);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
return buffer;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/**
|
|
Packit Service |
31306d |
* @deprecated Please use ssh_session_update_known_hosts()
|
|
Packit Service |
31306d |
* @brief This function is deprecated
|
|
Packit Service |
31306d |
*/
|
|
Packit Service |
31306d |
int ssh_write_knownhost(ssh_session session)
|
|
Packit Service |
31306d |
{
|
|
Packit Service |
31306d |
FILE *file;
|
|
Packit Service |
31306d |
char *buffer = NULL;
|
|
Packit Service |
31306d |
char *dir;
|
|
Packit Service |
31306d |
int rc;
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (session->opts.knownhosts == NULL) {
|
|
Packit Service |
31306d |
if (ssh_options_apply(session) < 0) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
errno = 0;
|
|
Packit Service |
31306d |
file = fopen(session->opts.knownhosts, "a");
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
if (errno == ENOENT) {
|
|
Packit Service |
31306d |
dir = ssh_dirname(session->opts.knownhosts);
|
|
Packit Service |
31306d |
if (dir == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_mkdirs(dir, 0700);
|
|
Packit Service |
31306d |
if (rc < 0) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Cannot create %s directory: %s",
|
|
Packit Service |
31306d |
dir, strerror(errno));
|
|
Packit Service |
31306d |
SAFE_FREE(dir);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
SAFE_FREE(dir);
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
errno = 0;
|
|
Packit Service |
31306d |
file = fopen(session->opts.knownhosts, "a");
|
|
Packit Service |
31306d |
if (file == NULL) {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Couldn't open known_hosts file %s"
|
|
Packit Service |
31306d |
" for appending: %s",
|
|
Packit Service |
31306d |
session->opts.knownhosts, strerror(errno));
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
} else {
|
|
Packit Service |
31306d |
ssh_set_error(session, SSH_FATAL,
|
|
Packit Service |
31306d |
"Couldn't open known_hosts file %s for appending: %s",
|
|
Packit Service |
31306d |
session->opts.knownhosts, strerror(errno));
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
rc = ssh_session_export_known_hosts_entry(session, &buffer);
|
|
Packit Service |
31306d |
if (rc != SSH_OK) {
|
|
Packit Service |
31306d |
fclose(file);
|
|
Packit Service |
31306d |
return SSH_ERROR;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
if (fwrite(buffer, strlen(buffer), 1, file) != 1 || ferror(file)) {
|
|
Packit Service |
31306d |
SAFE_FREE(buffer);
|
|
Packit Service |
31306d |
fclose(file);
|
|
Packit Service |
31306d |
return -1;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
SAFE_FREE(buffer);
|
|
Packit Service |
31306d |
fclose(file);
|
|
Packit Service |
31306d |
return 0;
|
|
Packit Service |
31306d |
}
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
#define KNOWNHOSTS_MAXTYPES 10
|
|
Packit Service |
31306d |
|
|
Packit Service |
31306d |
/** @} */
|