diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f54a3bc0..dc3a62627 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME}) set(APPLICATION_VERSION_MAJOR "0") set(APPLICATION_VERSION_MINOR "7") -set(APPLICATION_VERSION_PATCH "4") +set(APPLICATION_VERSION_PATCH "5") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") @@ -19,7 +19,7 @@ set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINO # Increment AGE. Set REVISION to 0 # If the source code was changed, but there were no interface changes: # Increment REVISION. -set(LIBRARY_VERSION "4.4.1") +set(LIBRARY_VERSION "4.4.2") set(LIBRARY_SOVERSION "4") # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked diff --git a/ChangeLog b/ChangeLog index c1c38f8ea..6a111a1a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ ChangeLog ========== + +version 0.7.5 (released 2017-04-13) + * Fixed a memory allocation issue with buffers + * Fixed PKI on Windows + * Fixed some SSHv1 functions + * Fixed config hostname expansion + version 0.7.4 (released 2017-02-03) * Added id_ed25519 to the default identity list * Fixed sftp EOF packet handling diff --git a/cmake/Modules/FindGCrypt.cmake b/cmake/Modules/FindGCrypt.cmake index 5f1fe40b9..7b44408a5 100644 --- a/cmake/Modules/FindGCrypt.cmake +++ b/cmake/Modules/FindGCrypt.cmake @@ -35,6 +35,8 @@ find_path(GCRYPT_INCLUDE_DIR gcrypt.h HINTS ${_GCRYPT_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + include ) find_library(GCRYPT_LIBRARY @@ -44,6 +46,8 @@ find_library(GCRYPT_LIBRARY libgcrypt-11 HINTS ${_GCRYPT_ROOT_HINTS_AND_PATHS} + PATH_SUFFIXES + lib ) set(GCRYPT_LIBRARIES ${GCRYPT_LIBRARY}) diff --git a/include/libssh/buffer.h b/include/libssh/buffer.h index 826d0b7c3..ee3f8cc7c 100644 --- a/include/libssh/buffer.h +++ b/include/libssh/buffer.h @@ -53,6 +53,8 @@ int buffer_add_u32(ssh_buffer buffer, uint32_t data); int buffer_add_u64(ssh_buffer buffer, uint64_t data); int ssh_buffer_add_data(ssh_buffer buffer, const void *data, uint32_t len); +int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len); + int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer, const char *format, int argc, diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index d16f8c631..372148988 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -79,7 +79,7 @@ /* libssh version */ #define LIBSSH_VERSION_MAJOR 0 #define LIBSSH_VERSION_MINOR 7 -#define LIBSSH_VERSION_MICRO 4 +#define LIBSSH_VERSION_MICRO 5 #define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \ LIBSSH_VERSION_MINOR, \ diff --git a/src/buffer.c b/src/buffer.c index 0bffdfdae..566701ca6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -563,12 +563,15 @@ uint32_t buffer_pass_bytes_end(struct ssh_buffer_struct *buffer, uint32_t len){ * @returns 0 if there is not enough data in buffer, len otherwise. */ uint32_t buffer_get_data(struct ssh_buffer_struct *buffer, void *data, uint32_t len){ + int rc; + /* * Check for a integer overflow first, then check if not enough data is in * the buffer. */ - if (buffer->pos + len < len || buffer->pos + len > buffer->used) { - return 0; + rc = ssh_buffer_validate_length(buffer, len); + if (rc != SSH_OK) { + return 0; } memcpy(data,buffer->data+buffer->pos,len); buffer->pos+=len; @@ -617,6 +620,24 @@ int buffer_get_u64(struct ssh_buffer_struct *buffer, uint64_t *data){ return buffer_get_data(buffer,data,sizeof(uint64_t)); } +/** + * @brief Valdiates that the given length can be obtained from the buffer. + * + * @param[in] buffer The buffer to read from. + * + * @param[in] len The length to be checked. + * + * @return SSH_OK if the length is valid, SSH_ERROR otherwise. + */ +int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len) +{ + if (buffer->pos + len < len || buffer->pos + len > buffer->used) { + return SSH_ERROR; + } + + return SSH_OK; +} + /** * @internal * @@ -630,13 +651,15 @@ struct ssh_string_struct *buffer_get_ssh_string(struct ssh_buffer_struct *buffer uint32_t stringlen; uint32_t hostlen; struct ssh_string_struct *str = NULL; + int rc; if (buffer_get_u32(buffer, &stringlen) == 0) { return NULL; } hostlen = ntohl(stringlen); /* verify if there is enough space in buffer to get it */ - if (buffer->pos + hostlen < hostlen || buffer->pos + hostlen > buffer->used) { + rc = ssh_buffer_validate_length(buffer, hostlen); + if (rc != SSH_OK) { return NULL; /* it is indeed */ } str = ssh_string_new(hostlen); @@ -867,11 +890,13 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, char **cstring; void **data; } o; - size_t len, rlen; + size_t len, rlen, max_len; uint32_t u32len; va_list ap_copy; int count; + max_len = ssh_buffer_get_len(buffer); + /* copy the argument list in case a rollback is needed */ va_copy(ap_copy, ap); @@ -921,10 +946,16 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, break; } len = ntohl(u32len); - if (len > UINT_MAX - 1){ + if (len > max_len - 1) { rc = SSH_ERROR; break; } + + rc = ssh_buffer_validate_length(buffer, len); + if (rc != SSH_OK) { + break; + } + *o.cstring = malloc(len + 1); if (*o.cstring == NULL){ rc = SSH_ERROR; @@ -942,6 +973,15 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, break; case 'P': len = va_arg(ap, size_t); + if (len > max_len - 1) { + rc = SSH_ERROR; + break; + } + + rc = ssh_buffer_validate_length(buffer, len); + if (rc != SSH_OK) { + break; + } o.data = va_arg(ap, void **); count++; diff --git a/src/config.c b/src/config.c index 2ae29d1ec..7c03b27c4 100644 --- a/src/config.c +++ b/src/config.c @@ -50,6 +50,8 @@ enum ssh_config_opcode_e { SOC_GSSAPISERVERIDENTITY, SOC_GSSAPICLIENTIDENTITY, SOC_GSSAPIDELEGATECREDENTIALS, + + SOC_END /* Keep this one last in the list */ }; struct ssh_config_keyword_table_s { @@ -185,7 +187,7 @@ static int ssh_config_get_yesno(char **str, int notfound) { } static int ssh_config_parse_line(ssh_session session, const char *line, - unsigned int count, int *parsing) { + unsigned int count, int *parsing, int seen[]) { enum ssh_config_opcode_e opcode; const char *p; char *s, *x; @@ -216,6 +218,12 @@ static int ssh_config_parse_line(ssh_session session, const char *line, } opcode = ssh_config_get_opcode(keyword); + if (*parsing == 1 && opcode != SOC_HOST) { + if (seen[opcode] == 0) { + return 0; + } + seen[opcode] = 1; + } switch (opcode) { case SOC_HOST: { @@ -227,18 +235,12 @@ static int ssh_config_parse_line(ssh_session session, const char *line, p != NULL && p[0] != '\0'; p = ssh_config_get_str_tok(&s, NULL)) { if (ok >= 0) { - char *z = ssh_path_expand_escape(session, p); - - if (z == NULL) { - z = strdup(p); - } - ok = match_hostname(lowerhost, z, strlen(z)); + ok = match_hostname(lowerhost, p, strlen(p)); if (ok < 0) { *parsing = 0; } else if (ok > 0) { *parsing = 1; } - free(z); } } SAFE_FREE(lowerhost); @@ -247,7 +249,12 @@ static int ssh_config_parse_line(ssh_session session, const char *line, case SOC_HOSTNAME: p = ssh_config_get_str_tok(&s, NULL); if (p && *parsing) { - ssh_options_set(session, SSH_OPTIONS_HOST, p); + char *z = ssh_path_expand_escape(session, p); + if (z == NULL) { + z = strdup(p); + } + ssh_options_set(session, SSH_OPTIONS_HOST, z); + free(z); } break; case SOC_PORT: @@ -384,6 +391,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) { unsigned int count = 0; FILE *f; int parsing; + int seen[SOC_END - SOC_UNSUPPORTED] = {0}; if ((f = fopen(filename, "r")) == NULL) { return 0; @@ -394,7 +402,7 @@ int ssh_config_parse_file(ssh_session session, const char *filename) { parsing = 1; while (fgets(line, sizeof(line), f)) { count++; - if (ssh_config_parse_line(session, line, count, &parsing) < 0) { + if (ssh_config_parse_line(session, line, count, &parsing, seen) < 0) { fclose(f); return -1; } diff --git a/src/messages.c b/src/messages.c index d906e696d..8f579da84 100644 --- a/src/messages.c +++ b/src/messages.c @@ -1355,7 +1355,8 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ msg->global_request.bind_port); session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); } else { - ssh_message_reply_default(msg); + ssh_message_queue(session, msg); + return rc; } } else if (strcmp(request, "cancel-tcpip-forward") == 0) { r = ssh_buffer_unpack(packet, "sd", @@ -1374,7 +1375,8 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); } else { - ssh_message_reply_default(msg); + ssh_message_queue(session, msg); + return rc; } } else { SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply); diff --git a/src/pki.c b/src/pki.c index 5b26579db..49e10b658 100644 --- a/src/pki.c +++ b/src/pki.c @@ -955,7 +955,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) return SSH_ERROR; } - file = fopen(filename, "r"); + file = fopen(filename, "rb"); if (file == NULL) { ssh_pki_log("Error opening %s: %s", filename, strerror(errno)); @@ -1233,7 +1233,7 @@ int ssh_pki_export_pubkey_file(const ssh_key key, return SSH_ERROR; } - fp = fopen(filename, "w+"); + fp = fopen(filename, "wb+"); if (fp == NULL) { return SSH_ERROR; } diff --git a/src/session.c b/src/session.c index 9b6ea1d45..11485bab0 100644 --- a/src/session.c +++ b/src/session.c @@ -31,6 +31,9 @@ #include "libssh/crypto.h" #include "libssh/server.h" #include "libssh/socket.h" +#ifdef WITH_SSH1 +#include "libssh/ssh1.h" +#endif /* WITH_SSH1 */ #include "libssh/ssh2.h" #include "libssh/agent.h" #include "libssh/packet.h" @@ -835,13 +838,17 @@ void ssh_socket_exception_callback(int code, int errno_code, void *user){ * @return SSH_OK on success, SSH_ERROR otherwise. */ int ssh_send_ignore (ssh_session session, const char *data) { +#ifdef WITH_SSH1 + const int type = session->version == 1 ? SSH_MSG_IGNORE : SSH2_MSG_IGNORE; +#else /* WITH_SSH1 */ + const int type = SSH2_MSG_IGNORE; +#endif /* WITH_SSH1 */ int rc; if (ssh_socket_is_open(session->socket)) { - rc = ssh_buffer_pack(session->out_buffer, "bs", - SSH2_MSG_IGNORE, + type, data); if (rc != SSH_OK){ ssh_set_error_oom(session); @@ -873,12 +880,22 @@ int ssh_send_debug (ssh_session session, const char *message, int always_display int rc; if (ssh_socket_is_open(session->socket)) { - rc = ssh_buffer_pack(session->out_buffer, - "bbsd", - SSH2_MSG_DEBUG, - always_display != 0 ? 1 : 0, - message, - 0); /* empty language tag */ +#ifdef WITH_SSH1 + if (session->version == 1) { + rc = ssh_buffer_pack(session->out_buffer, + "bs", + SSH_MSG_DEBUG, + message); + } else +#endif /* WITH_SSH1 */ + { + rc = ssh_buffer_pack(session->out_buffer, + "bbsd", + SSH2_MSG_DEBUG, + always_display != 0 ? 1 : 0, + message, + 0); /* empty language tag */ + } if (rc != SSH_OK) { ssh_set_error_oom(session); goto error;