diff options
author | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2019-05-15 18:57:14 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-06-12 10:17:54 +0200 |
commit | bc95a517101cc2a124e35040e042ed5349696e2a (patch) | |
tree | 244a739f58ba9090611fee1af9efdd51325ec278 /src | |
parent | 2c4850cbbda69330958fd0fa66c52dac006d3bc7 (diff) | |
download | libssh-bc95a517101cc2a124e35040e042ed5349696e2a.tar.gz libssh-bc95a517101cc2a124e35040e042ed5349696e2a.tar.xz libssh-bc95a517101cc2a124e35040e042ed5349696e2a.zip |
kex, known_hosts: Use new tokens functions
Replace the old tokens handling functions usage with the new implementation.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/kex.c | 124 | ||||
-rw-r--r-- | src/known_hosts.c | 333 |
2 files changed, 181 insertions, 276 deletions
@@ -186,92 +186,6 @@ static const char *ssh_kex_descriptions[] = { NULL }; -/* tokenize will return a token of strings delimited by ",". the first element has to be freed */ -static char **tokenize(const char *chain){ - char **tokens; - size_t n=1; - size_t i=0; - char *tmp; - char *ptr; - - tmp = strdup(chain); - if (tmp == NULL) { - return NULL; - } - ptr = tmp; - while(*ptr){ - if(*ptr==','){ - n++; - *ptr=0; - } - ptr++; - } - /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */ - tokens = calloc(n + 1, sizeof(char *)); /* +1 for the null */ - if (tokens == NULL) { - SAFE_FREE(tmp); - return NULL; - } - ptr=tmp; - for(i=0;i<n;i++){ - tokens[i]=ptr; - while(*ptr) - ptr++; // find a zero - ptr++; // then go one step further - } - tokens[i]=NULL; - return tokens; -} - -/* same as tokenize(), but with spaces instead of ',' */ -/* TODO FIXME rewrite me! */ -char **ssh_space_tokenize(const char *chain){ - char **tokens; - size_t n=1; - size_t i=0; - char *tmp; - char *ptr; - - tmp = strdup(chain); - if (tmp == NULL) { - return NULL; - } - ptr = tmp; - - while(*ptr==' ') - ++ptr; /* skip initial spaces */ - while(*ptr){ - if(*ptr==' '){ - n++; /* count one token per word */ - *ptr=0; - while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */ - *(ptr++)=0; - } - } - ptr++; - } - /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */ - tokens = calloc(n + 1, sizeof(char *)); /* +1 for the null */ - if (tokens == NULL) { - SAFE_FREE(tmp); - return NULL; - } - ptr=tmp; /* we don't pass the initial spaces because the "tmp" pointer is needed by the caller */ - /* function to free the tokens. */ - for(i=0;i<n;i++){ - tokens[i]=ptr; - if(i!=n-1){ - while(*ptr) - ptr++; // find a zero - while(!*(ptr+1)) - ++ptr; /* if the zero is followed by other zeros, go through them */ - ptr++; // then go one step further - } - } - tokens[i]=NULL; - return tokens; -} - const char *ssh_kex_get_default_methods(uint32_t algo) { if (algo >= KEX_METHODS_SIZE) { @@ -306,37 +220,33 @@ const char *ssh_kex_get_description(uint32_t algo) { */ static int cmp_first_kex_algo(const char *client_str, const char *server_str) { - int is_wrong = 1; - char **server_str_tokens = NULL; - char **client_str_tokens = NULL; + size_t client_kex_len; + size_t server_kex_len; - if ((client_str == NULL) || (server_str == NULL)) { - goto out; - } + char *colon; - client_str_tokens = tokenize(client_str); + int is_wrong = 1; - if (client_str_tokens == NULL) { - goto out; + colon = strchr(client_str, ','); + if (colon == NULL) { + client_kex_len = strlen(client_str); + } else { + client_kex_len = colon - client_str; } - if (client_str_tokens[0] == NULL) { - goto freeout; + colon = strchr(server_str, ','); + if (colon == NULL) { + server_kex_len = strlen(server_str); + } else { + server_kex_len = colon - server_str; } - server_str_tokens = tokenize(server_str); - if (server_str_tokens == NULL) { - goto freeout; + if (client_kex_len != server_kex_len) { + return is_wrong; } - is_wrong = (strcmp(client_str_tokens[0], server_str_tokens[0]) != 0); + is_wrong = (strncmp(client_str, server_str, client_kex_len) != 0); - SAFE_FREE(server_str_tokens[0]); - SAFE_FREE(server_str_tokens); -freeout: - SAFE_FREE(client_str_tokens[0]); - SAFE_FREE(client_str_tokens); -out: return is_wrong; } diff --git a/src/known_hosts.c b/src/known_hosts.c index 093188ec..80520907 100644 --- a/src/known_hosts.c +++ b/src/known_hosts.c @@ -38,6 +38,7 @@ #include "libssh/knownhosts.h" /*todo: remove this include */ #include "libssh/string.h" +#include "libssh/token.h" #ifndef _WIN32 # include <netinet/in.h> @@ -53,23 +54,6 @@ /** * @internal * - * @brief Free a token array. - */ -static void tokens_free(char **tokens) { - if (tokens == NULL) { - return; - } - - SAFE_FREE(tokens[0]); - /* It's not needed to free other pointers because tokens generated by - * space_tokenize fit all in one malloc - */ - SAFE_FREE(tokens); -} - -/** - * @internal - * * @brief Return one line of known host file. * * This will return a token array containing (host|ip), keytype and key. @@ -86,58 +70,63 @@ static void tokens_free(char **tokens) { * free that value. NULL if no match was found or the file * was not found. */ -static char **ssh_get_knownhost_line(FILE **file, const char *filename, - const char **found_type) { - char buffer[4096] = {0}; - char *ptr; - char **tokens; - - if(*file == NULL){ - *file = fopen(filename,"r"); +static struct ssh_tokens_st *ssh_get_knownhost_line(FILE **file, + const char *filename, + const char **found_type) +{ + char buffer[4096] = {0}; + char *ptr; + struct ssh_tokens_st *tokens; + if (*file == NULL) { - return NULL; + *file = fopen(filename,"r"); + if (*file == NULL) { + return NULL; + } } - } - while (fgets(buffer, sizeof(buffer), *file)) { - ptr = strchr(buffer, '\n'); - if (ptr) { - *ptr = '\0'; - } + while (fgets(buffer, sizeof(buffer), *file)) { + ptr = strchr(buffer, '\n'); + if (ptr) { + *ptr = '\0'; + } - ptr = strchr(buffer,'\r'); - if (ptr) { - *ptr = '\0'; - } + ptr = strchr(buffer,'\r'); + if (ptr) { + *ptr = '\0'; + } - if (buffer[0] == '\0' || buffer[0] == '#') { - continue; /* skip empty lines */ - } + if (buffer[0] == '\0' || buffer[0] == '#') { + continue; /* skip empty lines */ + } - tokens = ssh_space_tokenize(buffer); - if (tokens == NULL) { - fclose(*file); - *file = NULL; + tokens = ssh_tokenize(buffer, ' '); + if (tokens == NULL) { + fclose(*file); + *file = NULL; - return NULL; - } + return NULL; + } - if(tokens[0] == NULL || tokens[1] == NULL || tokens[2] == NULL) { - /* it should have at least 3 tokens */ - tokens_free(tokens); - continue; - } + if (tokens->tokens[0] == NULL || + tokens->tokens[1] == NULL || + tokens->tokens[2] == NULL) + { + /* it should have at least 3 tokens */ + ssh_tokens_free(tokens); + continue; + } - *found_type = tokens[1]; + *found_type = tokens->tokens[1]; - return tokens; - } + return tokens; + } - fclose(*file); - *file = NULL; + fclose(*file); + *file = NULL; - /* we did not find anything, end of file*/ - return NULL; + /* we did not find anything, end of file*/ + return NULL; } /** @@ -291,137 +280,143 @@ static int match_hashed_host(const char *host, const char *sourcehash) */ /** - * @brief This function is depcrecated + * @brief This function is deprecated * * @deprecated Please use ssh_session_is_known_server() * @see ssh_session_is_known_server() */ -int ssh_is_server_known(ssh_session session) { - FILE *file = NULL; - char **tokens; - char *host; - char *hostport; - const char *type; - int match; - int i=0; - char * files[3]; - int ret = SSH_SERVER_NOT_KNOWN; +int ssh_is_server_known(ssh_session session) +{ + FILE *file = NULL; + char *host; + char *hostport; + const char *type; + int match; + int i = 0; + char *files[3]; - if (session->opts.knownhosts == NULL) { - if (ssh_options_apply(session) < 0) { - ssh_set_error(session, SSH_REQUEST_DENIED, - "Can't find a known_hosts file"); + struct ssh_tokens_st *tokens; - return SSH_SERVER_FILE_NOT_FOUND; - } - } + int ret = SSH_SERVER_NOT_KNOWN; - if (session->opts.host == NULL) { - ssh_set_error(session, SSH_FATAL, - "Can't verify host in known hosts if the hostname isn't known"); + if (session->opts.knownhosts == NULL) { + if (ssh_options_apply(session) < 0) { + ssh_set_error(session, SSH_REQUEST_DENIED, + "Can't find a known_hosts file"); - return SSH_SERVER_ERROR; - } + return SSH_SERVER_FILE_NOT_FOUND; + } + } - if (session->current_crypto == NULL){ - ssh_set_error(session, SSH_FATAL, - "ssh_is_host_known called without cryptographic context"); + if (session->opts.host == NULL) { + ssh_set_error(session, SSH_FATAL, + "Can't verify host in known hosts if the hostname isn't known"); - return SSH_SERVER_ERROR; - } - host = ssh_lowercase(session->opts.host); - hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22); - if (host == NULL || hostport == NULL) { - ssh_set_error_oom(session); - SAFE_FREE(host); - SAFE_FREE(hostport); + return SSH_SERVER_ERROR; + } - return SSH_SERVER_ERROR; - } + if (session->current_crypto == NULL){ + ssh_set_error(session, SSH_FATAL, + "ssh_is_host_known called without cryptographic context"); - /* set the list of known hosts */ - i = 0; - if (session->opts.global_knownhosts != NULL){ - files[i++]=session->opts.global_knownhosts; - } - files[i++] = session->opts.knownhosts; - files[i] = NULL; - i = 0; - - do { - tokens = ssh_get_knownhost_line(&file, - files[i], - &type); - - /* End of file, return the current state or use next file */ - if (tokens == NULL) { - ++i; - if(files[i] == NULL) - break; - else - continue; - } - match = match_hashed_host(host, tokens[0]); - if (match == 0){ - match = match_hostname(hostport, tokens[0], strlen(tokens[0])); + return SSH_SERVER_ERROR; } - if (match == 0) { - match = match_hostname(host, tokens[0], strlen(tokens[0])); + + host = ssh_lowercase(session->opts.host); + hostport = ssh_hostport(host, session->opts.port > 0 ? session->opts.port : 22); + if (host == NULL || hostport == NULL) { + ssh_set_error_oom(session); + SAFE_FREE(host); + SAFE_FREE(hostport); + + return SSH_SERVER_ERROR; } - if (match == 0) { - match = match_hashed_host(hostport, tokens[0]); + + /* Set the list of known hosts files */ + i = 0; + if (session->opts.global_knownhosts != NULL){ + files[i++] = session->opts.global_knownhosts; } - if (match) { - ssh_key pubkey = ssh_dh_get_current_server_publickey(session); - const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey)); - - /* We got a match. Now check the key type */ - if (strcmp(pubkey_type, type) != 0) { - SSH_LOG(SSH_LOG_PACKET, - "ssh_is_server_known: server type [%s] doesn't match the " - "type [%s] in known_hosts file", - pubkey_type, - type); - /* Different type. We don't override the known_changed error which is - * more important */ - if (ret != SSH_SERVER_KNOWN_CHANGED) - ret = SSH_SERVER_FOUND_OTHER; - tokens_free(tokens); - continue; - } - /* so we know the key type is good. We may get a good key or a bad key. */ - match = check_public_key(session, tokens); - tokens_free(tokens); - - if (match < 0) { - ret = SSH_SERVER_ERROR; - break; - } else if (match == 1) { + files[i++] = session->opts.knownhosts; + files[i] = NULL; + i = 0; + + do { + tokens = ssh_get_knownhost_line(&file, + files[i], + &type); + + /* End of file, return the current state or use next file */ + if (tokens == NULL) { + ++i; + if(files[i] == NULL) + break; + else + continue; + } + match = match_hashed_host(host, tokens->tokens[0]); + if (match == 0){ + match = match_hostname(hostport, tokens->tokens[0], + strlen(tokens->tokens[0])); + } + if (match == 0) { + match = match_hostname(host, tokens->tokens[0], + strlen(tokens->tokens[0])); + } + if (match == 0) { + match = match_hashed_host(hostport, tokens->tokens[0]); + } + if (match) { + ssh_key pubkey = ssh_dh_get_current_server_publickey(session); + const char *pubkey_type = ssh_key_type_to_char(ssh_key_type(pubkey)); + + /* We got a match. Now check the key type */ + if (strcmp(pubkey_type, type) != 0) { + SSH_LOG(SSH_LOG_PACKET, + "ssh_is_server_known: server type [%s] doesn't match the " + "type [%s] in known_hosts file", + pubkey_type, + type); + /* Different type. We don't override the known_changed error which is + * more important */ + if (ret != SSH_SERVER_KNOWN_CHANGED) + ret = SSH_SERVER_FOUND_OTHER; + ssh_tokens_free(tokens); + continue; + } + /* so we know the key type is good. We may get a good key or a bad key. */ + match = check_public_key(session, tokens->tokens); + ssh_tokens_free(tokens); + + if (match < 0) { + ret = SSH_SERVER_ERROR; + break; + } else if (match == 1) { + ret = SSH_SERVER_KNOWN_OK; + break; + } else if(match == 0) { + /* We override the status with the wrong key state */ + ret = SSH_SERVER_KNOWN_CHANGED; + } + } else { + ssh_tokens_free(tokens); + } + } while (1); + + if ((ret == SSH_SERVER_NOT_KNOWN) && + (session->opts.StrictHostKeyChecking == 0)) { + ssh_write_knownhost(session); ret = SSH_SERVER_KNOWN_OK; - break; - } else if(match == 0) { - /* We override the status with the wrong key state */ - ret = SSH_SERVER_KNOWN_CHANGED; - } - } else { - tokens_free(tokens); } - } while (1); - if ((ret == SSH_SERVER_NOT_KNOWN) && - (session->opts.StrictHostKeyChecking == 0)) { - ssh_write_knownhost(session); - ret = SSH_SERVER_KNOWN_OK; - } - - SAFE_FREE(host); - SAFE_FREE(hostport); - if (file != NULL) { - fclose(file); - } + SAFE_FREE(host); + SAFE_FREE(hostport); + if (file != NULL) { + fclose(file); + } - /* Return the current state at end of file */ - return ret; + /* Return the current state at end of file */ + return ret; } /** |