1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-29 01:03:57 +03:00

known_hosts: Add ssh_dump_knownhost() function

This works similarly to ssh_write_knownhost(), but allows the caller
to get a line with the known_hosts line.

BUG: https://red.libssh.org/issues/207

Signed-off-by: Stef Walter <stefw@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Stef Walter
2015-11-09 14:24:54 +01:00
committed by Andreas Schneider
parent 1bf6c965e4
commit 857ce2376e
2 changed files with 86 additions and 58 deletions

View File

@@ -671,6 +671,7 @@ LIBSSH_API int ssh_userauth_kbdint_setanswer(ssh_session session, unsigned int i
LIBSSH_API int ssh_userauth_gssapi(ssh_session session); LIBSSH_API int ssh_userauth_gssapi(ssh_session session);
LIBSSH_API const char *ssh_version(int req_version); LIBSSH_API const char *ssh_version(int req_version);
LIBSSH_API int ssh_write_knownhost(ssh_session session); LIBSSH_API int ssh_write_knownhost(ssh_session session);
LIBSSH_API char *ssh_dump_knownhost(ssh_session session);
LIBSSH_API void ssh_string_burn(ssh_string str); LIBSSH_API void ssh_string_burn(ssh_string str);
LIBSSH_API ssh_string ssh_string_copy(ssh_string str); LIBSSH_API ssh_string ssh_string_copy(ssh_string str);

View File

@@ -514,30 +514,29 @@ int ssh_is_server_known(ssh_session session) {
} }
/** /**
* @brief Write the current server as known in the known hosts file. * @brief Output the current server as a known host line.
* *
* This will create the known hosts file if it does not exist. You generaly use * This could be placed in a known hosts file after user confirmation.
* it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN. * The return value should be passed to free() after the caller is done with it.
* *
* @param[in] session The ssh session to use. * @param[in] session The ssh session to use.
* *
* @return SSH_OK on success, SSH_ERROR on error. * @return string on success, NULL on error.
*/ */
int ssh_write_knownhost(ssh_session session) { char * ssh_dump_knownhost(ssh_session session) {
ssh_key key;
ssh_string pubkey_s; ssh_string pubkey_s;
char *b64_key; ssh_key key;
char buffer[4096] = {0};
FILE *file;
char *dir;
char *host; char *host;
char *hostport; char *hostport;
size_t len = 4096;
char *buffer;
char *b64_key;
int rc; int rc;
if (session->opts.host == NULL) { if (session->opts.host == NULL) {
ssh_set_error(session, SSH_FATAL, ssh_set_error(session, SSH_FATAL,
"Can't write host in known hosts if the hostname isn't known"); "Can't write host in known hosts if the hostname isn't known");
return SSH_ERROR; return NULL;
} }
host = ssh_lowercase(session->opts.host); host = ssh_lowercase(session->opts.host);
@@ -546,88 +545,58 @@ int ssh_write_knownhost(ssh_session session) {
hostport = ssh_hostport(host, session->opts.port); hostport = ssh_hostport(host, session->opts.port);
SAFE_FREE(host); SAFE_FREE(host);
if (hostport == NULL) { if (hostport == NULL) {
return SSH_ERROR; return NULL;
} }
host = hostport; host = hostport;
hostport = NULL; hostport = NULL;
} }
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
SAFE_FREE(host);
return SSH_ERROR;
}
}
if (session->current_crypto==NULL) { if (session->current_crypto==NULL) {
ssh_set_error(session, SSH_FATAL, "No current crypto context"); ssh_set_error(session, SSH_FATAL, "No current crypto context");
SAFE_FREE(host); SAFE_FREE(host);
return SSH_ERROR; return NULL;
} }
pubkey_s = session->current_crypto->server_pubkey; pubkey_s = session->current_crypto->server_pubkey;
if (pubkey_s == NULL){ if (pubkey_s == NULL){
ssh_set_error(session, SSH_FATAL, "No public key present"); ssh_set_error(session, SSH_FATAL, "No public key present");
SAFE_FREE(host); SAFE_FREE(host);
return SSH_ERROR; return NULL;
}
/* Check if ~/.ssh exists and create it if not */
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
SAFE_FREE(host);
return SSH_ERROR;
}
if (!ssh_file_readaccess_ok(dir)) {
if (ssh_mkdir(dir, 0700) < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory.", dir);
SAFE_FREE(dir);
SAFE_FREE(host);
return SSH_ERROR;
}
}
SAFE_FREE(dir);
file = fopen(session->opts.knownhosts, "a");
if (file == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
SAFE_FREE(host);
return SSH_ERROR;
} }
rc = ssh_pki_import_pubkey_blob(pubkey_s, &key); rc = ssh_pki_import_pubkey_blob(pubkey_s, &key);
if (rc < 0) { if (rc < 0) {
fclose(file);
SAFE_FREE(host); SAFE_FREE(host);
return -1; return NULL;
}
buffer = calloc (1, 4096);
if (!buffer) {
ssh_key_free(key);
SAFE_FREE(host);
return NULL;
} }
if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) { if (strcmp(session->current_crypto->server_pubkey_type, "ssh-rsa1") == 0) {
/* openssh uses a different format for ssh-rsa1 keys. /* openssh uses a different format for ssh-rsa1 keys.
Be compatible --kv */ Be compatible --kv */
rc = ssh_pki_export_pubkey_rsa1(key, host, buffer, sizeof(buffer)); rc = ssh_pki_export_pubkey_rsa1(key, host, buffer, len);
ssh_key_free(key); ssh_key_free(key);
SAFE_FREE(host); SAFE_FREE(host);
if (rc < 0) { if (rc < 0) {
fclose(file); SAFE_FREE(buffer);
return -1; return NULL;
} }
} else { } else {
rc = ssh_pki_export_pubkey_base64(key, &b64_key); rc = ssh_pki_export_pubkey_base64(key, &b64_key);
if (rc < 0) { if (rc < 0) {
ssh_key_free(key); ssh_key_free(key);
fclose(file); SAFE_FREE(buffer);
SAFE_FREE(host); SAFE_FREE(host);
return -1; return NULL;
} }
snprintf(buffer, sizeof(buffer), snprintf(buffer, len,
"%s %s %s\n", "%s %s %s\n",
host, host,
key->type_c, key->type_c,
@@ -638,11 +607,69 @@ int ssh_write_knownhost(ssh_session session) {
SAFE_FREE(b64_key); SAFE_FREE(b64_key);
} }
return buffer;
}
/**
* @brief Write the current server as known in the known hosts file.
*
* This will create the known hosts file if it does not exist. You generaly use
* it when ssh_is_server_known() answered SSH_SERVER_NOT_KNOWN.
*
* @param[in] session The ssh session to use.
*
* @return SSH_OK on success, SSH_ERROR on error.
*/
int ssh_write_knownhost(ssh_session session) {
FILE *file;
char *buffer;
char *dir;
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
ssh_set_error(session, SSH_FATAL, "Can't find a known_hosts file");
return SSH_ERROR;
}
}
/* Check if directory exists and create it if not */
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
return SSH_ERROR;
}
if (!ssh_file_readaccess_ok(dir)) {
if (ssh_mkdir(dir, 0700) < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory.", dir);
SAFE_FREE(dir);
return SSH_ERROR;
}
}
SAFE_FREE(dir);
file = fopen(session->opts.knownhosts, "a");
if (file == NULL) {
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s for appending: %s",
session->opts.knownhosts, strerror(errno));
return SSH_ERROR;
}
buffer = ssh_dump_knownhost(session);
if (buffer == NULL) {
fclose(file);
return SSH_ERROR;
}
if (fwrite(buffer, strlen(buffer), 1, file) != 1 || ferror(file)) { if (fwrite(buffer, strlen(buffer), 1, file) != 1 || ferror(file)) {
SAFE_FREE(buffer);
fclose(file); fclose(file);
return -1; return -1;
} }
SAFE_FREE(buffer);
fclose(file); fclose(file);
return 0; return 0;
} }