From 2e3661a0f6eb1138644907db32de592c22c59c42 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 11 Jul 2013 03:46:02 -0400 Subject: [PATCH] Update libssh --- libssh/examples/libssh_scp.c | 18 ++- libssh/examples/sample.c | 7 +- libssh/examples/samplesshd-tty.c | 3 + libssh/examples/scp_download.c | 14 +- libssh/include/libssh/pki.h | 1 + libssh/include/libssh/server.h | 2 + libssh/include/libssh/socket.h | 4 +- libssh/src/agent.c | 30 ++++- libssh/src/auth.c | 7 +- libssh/src/channels1.c | 7 +- libssh/src/client.c | 5 +- libssh/src/connect.c | 36 +++++- libssh/src/dh.c | 10 +- libssh/src/ecdh.c | 162 +++++++++++++++++------- libssh/src/kex.c | 1 + libssh/src/kex1.c | 5 +- libssh/src/known_hosts.c | 2 +- libssh/src/messages.c | 5 +- libssh/src/packet.c | 14 +- libssh/src/packet1.c | 2 +- libssh/src/pki.c | 37 ++++-- libssh/src/pki_crypto.c | 3 + libssh/src/server.c | 40 +++++- libssh/src/socket.c | 26 ++-- libssh/tests/client/torture_session.c | 3 +- libssh/tests/torture.c | 1 + libssh/tests/unittests/torture_buffer.c | 30 +++-- libssh/tests/unittests/torture_pki.c | 4 +- 28 files changed, 347 insertions(+), 132 deletions(-) diff --git a/libssh/examples/libssh_scp.c b/libssh/examples/libssh_scp.c index d443f8f2..b7471da6 100644 --- a/libssh/examples/libssh_scp.c +++ b/libssh/examples/libssh_scp.c @@ -174,12 +174,16 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ char buffer[16384]; int total=0; int mode; - char *filename; + char *filename = NULL; /* recursive mode doesn't work yet */ (void)recursive; /* Get the file name and size*/ if(!src->is_ssh){ - fd=fileno(src->file); + fd = fileno(src->file); + if (fd < 0) { + fprintf(stderr, "Invalid file pointer, error: %s\n", strerror(errno)); + return -1; + } fstat(fd,&s); size=s.st_size; mode = s.st_mode & ~S_IFMT; @@ -201,6 +205,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ } if(r==SSH_ERROR){ fprintf(stderr,"Error: %s\n",ssh_get_error(src->session)); + ssh_string_free_char(filename); return -1; } } while(r != SSH_SCP_REQUEST_NEWFILE); @@ -211,6 +216,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ // snprintf(buffer,sizeof(buffer),"C0644 %d %s\n",size,src->path); if(r==SSH_ERROR){ fprintf(stderr,"error: %s\n",ssh_get_error(dest->session)); + ssh_string_free_char(filename); ssh_scp_free(dest->scp); return -1; } @@ -221,6 +227,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ fprintf(stderr,"Cannot open %s for writing: %s\n",filename,strerror(errno)); if(src->is_ssh) ssh_scp_deny_request(src->scp,"Cannot open local file"); + ssh_string_free_char(filename); return -1; } } @@ -233,6 +240,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ r=ssh_scp_read(src->scp,buffer,sizeof(buffer)); if(r==SSH_ERROR){ fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(src->session)); + ssh_string_free_char(filename); return -1; } if(r==0) @@ -243,6 +251,7 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ break; if(r<0){ fprintf(stderr,"Error reading file: %s\n",strerror(errno)); + ssh_string_free_char(filename); return -1; } } @@ -252,18 +261,21 @@ static int do_copy(struct location *src, struct location *dest, int recursive){ fprintf(stderr,"Error writing in scp: %s\n",ssh_get_error(dest->session)); ssh_scp_free(dest->scp); dest->scp=NULL; + ssh_string_free_char(filename); return -1; } } else { w=fwrite(buffer,r,1,dest->file); if(w<=0){ fprintf(stderr,"Error writing in local file: %s\n",strerror(errno)); + ssh_string_free_char(filename); return -1; } } total+=r; } while(total < size); + ssh_string_free_char(filename); printf("wrote %d bytes\n",total); return 0; } @@ -286,7 +298,7 @@ int main(int argc, char **argv){ break; } } - if(dest->is_ssh){ + if (dest->is_ssh && dest->scp != NULL) { r=ssh_scp_close(dest->scp); if(r == SSH_ERROR){ fprintf(stderr,"Error closing scp: %s\n",ssh_get_error(dest->session)); diff --git a/libssh/examples/sample.c b/libssh/examples/sample.c index cfe4b3a6..93634d80 100644 --- a/libssh/examples/sample.c +++ b/libssh/examples/sample.c @@ -60,9 +60,12 @@ struct ssh_callbacks_struct cb = { static void add_cmd(char *cmd){ int n; - for(n=0;cmds[n] && (nversion) { case 1: @@ -287,9 +288,14 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { /* send message to the agent requesting the list of identities */ request = ssh_buffer_new(); + if (request == NULL) { + ssh_set_error_oom(request); + return -1; + } if (buffer_add_u8(request, c1) < 0) { - ssh_set_error(session, SSH_FATAL, "Not enough space"); - return -1; + ssh_set_error_oom(request); + ssh_buffer_free(request); + return -1; } reply = ssh_buffer_new(); @@ -307,16 +313,26 @@ int ssh_agent_get_ident_count(struct ssh_session_struct *session) { ssh_buffer_free(request); /* get message type and verify the answer */ - buffer_get_u8(reply, (uint8_t *) &type); + rc = buffer_get_u8(reply, (uint8_t *) &type); + if (rc != sizeof(uint8_t)) { + ssh_set_error(session, SSH_FATAL, + "Bad authentication reply size: %d", rc); + ssh_buffer_free(reply); + return -1; + } + SSH_LOG(session, SSH_LOG_WARN, "Answer type: %d, expected answer: %d", type, c2); + if (agent_failed(type)) { - return 0; + ssh_buffer_free(reply); + return 0; } else if (type != c2) { - ssh_set_error(session, SSH_FATAL, - "Bad authentication reply message type: %d", type); - return -1; + ssh_set_error(session, SSH_FATAL, + "Bad authentication reply message type: %d", type); + ssh_buffer_free(reply); + return -1; } buffer_get_u32(reply, (uint32_t *) buf); diff --git a/libssh/src/auth.c b/libssh/src/auth.c index 5b8f748f..bdad4e42 100644 --- a/libssh/src/auth.c +++ b/libssh/src/auth.c @@ -1107,12 +1107,9 @@ int ssh_userauth_publickey_auto(ssh_session session, state = session->auth_auto_state; if (state->state == SSH_AUTH_AUTO_STATE_NONE) { #ifndef _WIN32 - /* Try authentication with ssh-agent first */ + /* Try authentication with ssh-agent first */ rc = ssh_userauth_agent(session, username); - if (rc == SSH_AUTH_SUCCESS) { - return rc; - } - if (rc == SSH_AUTH_AGAIN) + if (rc == SSH_AUTH_SUCCESS) return rc; #endif state->state = SSH_AUTH_AUTO_STATE_PUBKEY; diff --git a/libssh/src/channels1.c b/libssh/src/channels1.c index 5d0158d2..62faf4ae 100644 --- a/libssh/src/channels1.c +++ b/libssh/src/channels1.c @@ -288,6 +288,8 @@ SSH_PACKET_CALLBACK(ssh_packet_data1){ SSH_PACKET_CALLBACK(ssh_packet_close1){ ssh_channel channel = ssh_get_channel1(session); uint32_t status; + int rc; + (void)type; (void)user; @@ -305,7 +307,10 @@ SSH_PACKET_CALLBACK(ssh_packet_close1){ channel->state = SSH_CHANNEL_STATE_CLOSED; channel->remote_eof = 1; - buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION); + rc = buffer_add_u8(session->out_buffer, SSH_CMSG_EXIT_CONFIRMATION); + if (rc < 0) { + return SSH_PACKET_NOT_USED; + } packet_send(session); return SSH_PACKET_USED; diff --git a/libssh/src/client.c b/libssh/src/client.c index ac1b83db..6203bc4c 100644 --- a/libssh/src/client.c +++ b/libssh/src/client.c @@ -405,6 +405,7 @@ static void ssh_client_connection_callback(ssh_session session){ if (dh_handshake(session) == SSH_ERROR) { goto error; } + /* FALL THROUGH */ case SSH_SESSION_STATE_DH: if(session->dh_handshake_state==DH_STATE_FINISHED){ set_status(session,1.0f); @@ -617,7 +618,7 @@ void ssh_disconnect(ssh_session session) { enter_function(); - if (ssh_socket_is_open(session->socket)) { + if (session->socket != NULL && ssh_socket_is_open(session->socket)) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { goto error; } @@ -642,7 +643,7 @@ void ssh_disconnect(ssh_session session) { } error: session->alive = 0; - if(session->socket){ + if (session->socket != NULL){ ssh_socket_reset(session->socket); } session->opts.fd = SSH_INVALID_SOCKET; diff --git a/libssh/src/connect.c b/libssh/src/connect.c index ae55b140..91e6b6a7 100644 --- a/libssh/src/connect.c +++ b/libssh/src/connect.c @@ -139,6 +139,7 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, int timeout_ms; ssh_pollfd_t fds; int rc = 0; + int ret; socklen_t len = sizeof(rc); enter_function(); @@ -148,7 +149,13 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, */ timeout_ms=timeout * 1000 + usec / 1000; - ssh_socket_set_nonblocking(s); + rc = ssh_socket_set_nonblocking(s); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, + "Failed to set socket non-blocking for %s:%d", host, port); + ssh_connect_socket_close(s); + return -1; + } ssh_log(session, SSH_LOG_RARE, "Trying to connect to host: %s:%d with " "timeout %d ms", host, port, timeout_ms); @@ -181,11 +188,11 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, leave_function(); return -1; } - rc = 0; + rc = -1; /* Get connect(2) return code. Zero means no error */ - getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len); - if (rc != 0) { + ret = getsockopt(s, SOL_SOCKET, SO_ERROR,(char *) &rc, &len); + if (ret < 0 || rc != 0) { ssh_set_error(session, SSH_FATAL, "Connect to %s:%d failed: %s", host, port, strerror(rc)); ssh_connect_socket_close(s); @@ -195,7 +202,14 @@ static int ssh_connect_ai_timeout(ssh_session session, const char *host, /* s is connected ? */ ssh_log(session, SSH_LOG_PACKET, "Socket connected with timeout\n"); - ssh_socket_set_blocking(s); + ret = ssh_socket_set_blocking(s); + if (ret < 0) { + ssh_set_error(session, SSH_FATAL, + "Failed to set socket as blocking connecting to %s:%d failed: %s", + host, port, strerror(errno)); + ssh_connect_socket_close(s); + return -1; + } leave_function(); return s; @@ -344,7 +358,7 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, "Failed to resolve bind address %s (%s)", bind_addr, gai_strerror(rc)); - close(s); + ssh_connect_socket_close(s); s=-1; break; } @@ -367,7 +381,15 @@ socket_t ssh_connect_host_nonblocking(ssh_session session, const char *host, continue; } } - ssh_socket_set_nonblocking(s); + + rc = ssh_socket_set_nonblocking(s); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, + "Failed to set socket non-blocking for %s:%d", host, port); + ssh_connect_socket_close(s); + s = -1; + continue; + } connect(s, itr->ai_addr, itr->ai_addrlen); break; diff --git a/libssh/src/dh.c b/libssh/src/dh.c index e4f2062b..16c15e6f 100644 --- a/libssh/src/dh.c +++ b/libssh/src/dh.c @@ -765,8 +765,14 @@ int make_sessionid(ssh_session session) { ssh_log(session,SSH_LOG_WARNING,"ECDH parameted missing"); goto error; } - buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey); - buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey); + rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey); + if (rc < 0) { + goto error; + } + rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey); + if (rc < 0) { + goto error; + } #endif } num = make_bignum_string(session->next_crypto->k); diff --git a/libssh/src/ecdh.c b/libssh/src/ecdh.c index bc0b03ce..075810a9 100644 --- a/libssh/src/ecdh.c +++ b/libssh/src/ecdh.c @@ -38,37 +38,57 @@ * @brief Starts ecdh-sha2-nistp256 key exchange */ int ssh_client_ecdh_init(ssh_session session){ - EC_KEY *key=NULL; + EC_KEY *key; const EC_GROUP *group; const EC_POINT *pubkey; ssh_string client_pubkey; int len; int rc; - bignum_CTX ctx=BN_CTX_new(); - enter_function(); - if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT) < 0) { - goto error; + bignum_CTX ctx = BN_CTX_new(); + + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEX_ECDH_INIT); + if (rc < 0) { + BN_CTX_free(ctx); + return SSH_ERROR; } + key = EC_KEY_new_by_curve_name(NISTP256); + if (key == NULL) { + BN_CTX_free(ctx); + return SSH_ERROR; + } group = EC_KEY_get0_group(key); + EC_KEY_generate_key(key); + pubkey=EC_KEY_get0_public_key(key); len = EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED, NULL,0,ctx); - client_pubkey=ssh_string_new(len); + + client_pubkey = ssh_string_new(len); + if (client_pubkey == NULL) { + BN_CTX_free(ctx); + EC_KEY_free(key); + return SSH_ERROR; + } EC_POINT_point2oct(group,pubkey,POINT_CONVERSION_UNCOMPRESSED, ssh_string_data(client_pubkey),len,ctx); - buffer_add_ssh_string(session->out_buffer,client_pubkey); BN_CTX_free(ctx); + + rc = buffer_add_ssh_string(session->out_buffer,client_pubkey); + if (rc < 0) { + EC_KEY_free(key); + ssh_string_free(client_pubkey); + return SSH_ERROR; + } + session->next_crypto->ecdh_privkey = key; session->next_crypto->ecdh_client_pubkey = client_pubkey; + rc = packet_send(session); - leave_function(); + return rc; -error: - leave_function(); - return SSH_ERROR; } static void ecdh_import_pubkey(ssh_session session, ssh_string pubkey_string) { @@ -180,9 +200,9 @@ error: int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ /* ECDH keys */ - ssh_string q_c_string = NULL; - ssh_string q_s_string = NULL; - EC_KEY *ecdh_key=NULL; + ssh_string q_c_string; + ssh_string q_s_string; + EC_KEY *ecdh_key; const EC_GROUP *group; const EC_POINT *ecdh_pubkey; bignum_CTX ctx; @@ -192,14 +212,11 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ int len; int rc; - enter_function(); - /* Extract the client pubkey from the init packet */ - q_c_string = buffer_get_ssh_string(packet); if (q_c_string == NULL) { - ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet"); - goto error; + ssh_set_error(session,SSH_FATAL, "No Q_C ECC point in packet"); + return SSH_ERROR; } session->next_crypto->ecdh_client_pubkey = q_c_string; @@ -207,45 +224,94 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ ctx = BN_CTX_new(); ecdh_key = EC_KEY_new_by_curve_name(NISTP256); + if (ecdh_key == NULL) { + ssh_set_error_oom(session); + BN_CTX_free(ctx); + return SSH_ERROR; + } + group = EC_KEY_get0_group(ecdh_key); EC_KEY_generate_key(ecdh_key); - ecdh_pubkey=EC_KEY_get0_public_key(ecdh_key); - len = EC_POINT_point2oct(group,ecdh_pubkey,POINT_CONVERSION_UNCOMPRESSED, - NULL,0,ctx); - q_s_string=ssh_string_new(len); - EC_POINT_point2oct(group,ecdh_pubkey,POINT_CONVERSION_UNCOMPRESSED, - ssh_string_data(q_s_string),len,ctx); + ecdh_pubkey = EC_KEY_get0_public_key(ecdh_key); + len = EC_POINT_point2oct(group, + ecdh_pubkey, + POINT_CONVERSION_UNCOMPRESSED, + NULL, + 0, + ctx); + q_s_string = ssh_string_new(len); + if (q_s_string == NULL) { + EC_KEY_free(ecdh_key); + BN_CTX_free(ctx); + return SSH_ERROR; + } + + EC_POINT_point2oct(group, + ecdh_pubkey, + POINT_CONVERSION_UNCOMPRESSED, + ssh_string_data(q_s_string), + len, + ctx); BN_CTX_free(ctx); + session->next_crypto->ecdh_privkey = ecdh_key; session->next_crypto->ecdh_server_pubkey = q_s_string; - buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY); - /* build k and session_id */ - if (ecdh_build_k(session) < 0) { - ssh_set_error(session, SSH_FATAL, "Cannot build k number"); - goto error; + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_KEXDH_REPLY); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; } - if (ssh_get_key_params(session, &privkey) == SSH_ERROR) - goto error; - if (make_sessionid(session) != SSH_OK) { - ssh_set_error(session, SSH_FATAL, "Could not create a session id"); - goto error; + + /* build k and session_id */ + rc = ecdh_build_k(session); + if (rc < 0) { + ssh_set_error(session, SSH_FATAL, "Cannot build k number"); + return SSH_ERROR; + } + + /* privkey is not allocated */ + rc = ssh_get_key_params(session, &privkey); + if (rc == SSH_ERROR) { + return SSH_ERROR; + } + + rc = make_sessionid(session); + if (rc != SSH_OK) { + ssh_set_error(session, SSH_FATAL, "Could not create a session id"); + return SSH_ERROR; } /* add host's public key */ - buffer_add_ssh_string(session->out_buffer, session->next_crypto->server_pubkey); + rc = buffer_add_ssh_string(session->out_buffer, + session->next_crypto->server_pubkey); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + /* add ecdh public key */ - buffer_add_ssh_string(session->out_buffer,q_s_string); + rc = buffer_add_ssh_string(session->out_buffer, q_s_string); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; + } /* add signature blob */ sig_blob = ssh_srv_pki_do_sign_sessionid(session, privkey); if (sig_blob == NULL) { ssh_set_error(session, SSH_FATAL, "Could not sign the session id"); - goto error; + return SSH_ERROR; } - buffer_add_ssh_string(session->out_buffer, sig_blob); + + rc = buffer_add_ssh_string(session->out_buffer, sig_blob); ssh_string_free(sig_blob); + if (rc < 0) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + /* Free private keys as they should not be readable after this point */ if (session->srv.rsa_key) { ssh_key_free(session->srv.rsa_key); @@ -258,19 +324,21 @@ int ssh_server_ecdh_init(ssh_session session, ssh_buffer packet){ ssh_log(session,SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); rc = packet_send(session); - if (rc == SSH_ERROR) - goto error; + if (rc == SSH_ERROR) { + return SSH_ERROR; + } /* Send the MSG_NEWKEYS */ - if (buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { - goto error; + rc = buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); + if (rc < 0) { + return SSH_ERROR;; } - session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; - rc=packet_send(session); + + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + rc = packet_send(session); ssh_log(session, SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + return rc; - error: - return SSH_ERROR; } #endif /* WITH_SERVER */ diff --git a/libssh/src/kex.c b/libssh/src/kex.c index e900a91a..c678731e 100644 --- a/libssh/src/kex.c +++ b/libssh/src/kex.c @@ -460,6 +460,7 @@ int ssh_send_kex(ssh_session session, int server_kex) { goto error; } ssh_string_free(str); + str = NULL; } if (buffer_add_u8(session->out_buffer, 0) < 0) { diff --git a/libssh/src/kex1.c b/libssh/src/kex1.c index b11cf007..b396a719 100644 --- a/libssh/src/kex1.c +++ b/libssh/src/kex1.c @@ -47,6 +47,9 @@ static ssh_string make_rsa1_string(ssh_string e, ssh_string n){ buffer = ssh_buffer_new(); rsa = ssh_string_from_char("ssh-rsa1"); + if (rsa == NULL) { + goto error; + } if (buffer_add_ssh_string(buffer, rsa) < 0) { goto error; @@ -375,7 +378,7 @@ SSH_PACKET_CALLBACK(ssh_packet_publickey1){ goto error; } hostkey = make_rsa1_string(host_exp,host_mod); - if (serverkey == NULL) { + if (hostkey == NULL) { goto error; } if (build_session_id1(session, server_mod, host_mod) < 0) { diff --git a/libssh/src/known_hosts.c b/libssh/src/known_hosts.c index 2d281e72..a9ae38c1 100644 --- a/libssh/src/known_hosts.c +++ b/libssh/src/known_hosts.c @@ -133,7 +133,7 @@ static char **ssh_get_knownhost_line(ssh_session session, FILE **file, *ptr = '\0'; } - if (!buffer[0] || buffer[0] == '#') { + if (buffer[0] == '\0' || buffer[0] == '#') { continue; /* skip empty lines */ } diff --git a/libssh/src/messages.c b/libssh/src/messages.c index 1ef8a745..5fcdd04e 100644 --- a/libssh/src/messages.c +++ b/libssh/src/messages.c @@ -135,7 +135,9 @@ void ssh_message_queue(ssh_session session, ssh_message message){ } session->ssh_message_list = ssh_list_new(); } - ssh_list_append(session->ssh_message_list, message); + if (session->ssh_message_list != NULL) { + ssh_list_append(session->ssh_message_list, message); + } } } @@ -1252,6 +1254,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ msg = ssh_message_new(session); if (msg == NULL) { + ssh_string_free_char(request); return SSH_PACKET_NOT_USED; } msg->type = SSH_REQUEST_GLOBAL; diff --git a/libssh/src/packet.c b/libssh/src/packet.c index 2256f113..440e47c6 100644 --- a/libssh/src/packet.c +++ b/libssh/src/packet.c @@ -187,6 +187,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) /* saves the status of the current operations */ session->in_packet.len = len; session->packet_state = PACKET_STATE_SIZEREAD; + /* FALL TROUGH */ case PACKET_STATE_SIZEREAD: len = session->in_packet.len; to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize; @@ -305,10 +306,12 @@ void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){ * @brief sets the callbacks for the packet layer */ void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){ - if(session->packet_callbacks == NULL){ - session->packet_callbacks = ssh_list_new(); - } - ssh_list_append(session->packet_callbacks, callbacks); + if(session->packet_callbacks == NULL){ + session->packet_callbacks = ssh_list_new(); + } + if (session->packet_callbacks != NULL) { + ssh_list_append(session->packet_callbacks, callbacks); + } } /** @internal @@ -526,6 +529,3 @@ int packet_send(ssh_session session) { #endif return packet_send2(session); } - - -/* vim: set ts=2 sw=2 et cindent: */ diff --git a/libssh/src/packet1.c b/libssh/src/packet1.c index 5c8b81e5..56bfb346 100644 --- a/libssh/src/packet1.c +++ b/libssh/src/packet1.c @@ -144,6 +144,7 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user session->in_packet.len = len; session->packet_state = PACKET_STATE_SIZEREAD; + /* FALL THROUGH */ case PACKET_STATE_SIZEREAD: len = session->in_packet.len; /* SSH-1 has a fixed padding lenght */ @@ -158,7 +159,6 @@ int ssh_packet_socket_callback1(const void *data, size_t receivedlen, void *user packet = (char *)data + processed; if (buffer_add_data(session->in_buffer,packet,to_be_read) < 0) { - SAFE_FREE(packet); goto error; } processed += to_be_read; diff --git a/libssh/src/pki.c b/libssh/src/pki.c index 87d7e765..a3616c2f 100644 --- a/libssh/src/pki.c +++ b/libssh/src/pki.c @@ -421,8 +421,16 @@ int ssh_pki_import_privkey_file(const char *filename, return SSH_ERROR; } - rc = stat(filename, &sb); + file = fopen(filename, "rb"); + if (file == NULL) { + ssh_pki_log("Error opening %s: %s", + filename, strerror(errno)); + return SSH_EOF; + } + + rc = fstat(fileno(file), &sb); if (rc < 0) { + fclose(file); ssh_pki_log("Error getting stat of %s: %s", filename, strerror(errno)); switch (errno) { @@ -434,11 +442,10 @@ int ssh_pki_import_privkey_file(const char *filename, return SSH_ERROR; } - file = fopen(filename, "rb"); - if (file == NULL) { - ssh_pki_log("Error opening %s: %s", - filename, strerror(errno)); - return SSH_EOF; + if (sb.st_size > MAX_PRIVKEY_SIZE) { + ssh_pki_log("Private key is bigger than 4M."); + fclose(file); + return SSH_ERROR; } key_buf = malloc(sb.st_size + 1); @@ -804,8 +811,16 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) return SSH_ERROR; } - rc = stat(filename, &sb); + file = fopen(filename, "r"); + if (file == NULL) { + ssh_pki_log("Error opening %s: %s", + filename, strerror(errno)); + return SSH_EOF; + } + + rc = fstat(fileno(file), &sb); if (rc < 0) { + fclose(file); ssh_pki_log("Error gettint stat of %s: %s", filename, strerror(errno)); switch (errno) { @@ -817,16 +832,10 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) } if (sb.st_size > MAX_PUBKEY_SIZE) { + fclose(file); return SSH_ERROR; } - file = fopen(filename, "r"); - if (file == NULL) { - ssh_pki_log("Error opening %s: %s", - filename, strerror(errno)); - return SSH_EOF; - } - key_buf = malloc(sb.st_size + 1); if (key_buf == NULL) { fclose(file); diff --git a/libssh/src/pki_crypto.c b/libssh/src/pki_crypto.c index 0ec05d33..92c37c85 100644 --- a/libssh/src/pki_crypto.c +++ b/libssh/src/pki_crypto.c @@ -411,8 +411,10 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter) { switch (parameter) { case 384: nid = NID_secp384r1; + break; case 512: nid = NID_secp521r1; + break; case 256: default: nid = NID_X9_62_prime256v1; @@ -850,6 +852,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key) e = make_ecpoint_string(EC_KEY_get0_group(key->ecdsa), EC_KEY_get0_public_key(key->ecdsa)); if (e == NULL) { + ssh_buffer_free(buffer); return NULL; } diff --git a/libssh/src/server.c b/libssh/src/server.c index db8f8152..6862370f 100644 --- a/libssh/src/server.c +++ b/libssh/src/server.c @@ -927,7 +927,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, r = buffer_add_ssh_string(msg->session->out_buffer, tmp); ssh_string_free(tmp); if (r < 0) { - goto error; + return SSH_ERROR; } /* echo[i] */ @@ -1003,9 +1003,6 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, } return r; -error: - if(tmp) ssh_string_free(tmp); - return SSH_ERROR; } int ssh_message_auth_reply_success(ssh_message msg, int partial) { @@ -1200,6 +1197,41 @@ int ssh_execute_message_callbacks(ssh_session session){ return SSH_OK; } +int ssh_send_keepalive(ssh_session session) +{ + /* TODO check the reply and all that */ + struct ssh_string_struct *req; + int reply = 1; + int rc = SSH_ERROR; + + enter_function(); + req = ssh_string_from_char("keepalive@openssh.com"); + if (req == NULL) { + ssh_set_error_oom(session); + goto out; + } + + if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || + buffer_add_ssh_string(session->out_buffer, req) < 0 || + buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { + ssh_set_error_oom(session); + goto out; + } + + if (packet_send(session) == SSH_ERROR) + goto out; + + ssh_handle_packets(session, 0); + + ssh_log(session, SSH_LOG_PACKET, "Sent a keepalive"); + rc = SSH_OK; + +out: + ssh_string_free(req); + leave_function(); + return rc; +} + /** @} */ /* vim: set ts=4 sw=4 et cindent: */ diff --git a/libssh/src/socket.c b/libssh/src/socket.c index 85b87b77..0f6c0a83 100644 --- a/libssh/src/socket.c +++ b/libssh/src/socket.c @@ -230,7 +230,10 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r /* Check if we are in a connecting state */ if(s->state==SSH_SOCKET_CONNECTING){ s->state=SSH_SOCKET_ERROR; - getsockopt(fd,SOL_SOCKET,SO_ERROR,(char *)&err,&errlen); + r = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); + if (r < 0) { + err = errno; + } s->last_errno=err; ssh_socket_close(s); if(s->callbacks && s->callbacks->connected) @@ -305,7 +308,10 @@ int ssh_socket_pollcallback(struct ssh_poll_handle_struct *p, socket_t fd, int r ssh_log(s->session,SSH_LOG_PACKET,"Received POLLOUT in connecting state"); s->state = SSH_SOCKET_CONNECTED; ssh_poll_set_events(p,POLLOUT | POLLIN); - ssh_socket_set_blocking(ssh_socket_get_fd_in(s)); + r = ssh_socket_set_blocking(ssh_socket_get_fd_in(s)); + if (r < 0) { + return -1; + } if(s->callbacks && s->callbacks->connected) s->callbacks->connected(SSH_SOCKET_CONNECTED_OK,0,s->callbacks->userdata); return 0; @@ -711,23 +717,23 @@ int ssh_socket_get_status(ssh_socket s) { } #ifdef _WIN32 -void ssh_socket_set_nonblocking(socket_t fd) { +int ssh_socket_set_nonblocking(socket_t fd) { u_long nonblocking = 1; - ioctlsocket(fd, FIONBIO, &nonblocking); + return ioctlsocket(fd, FIONBIO, &nonblocking); } -void ssh_socket_set_blocking(socket_t fd) { +int ssh_socket_set_blocking(socket_t fd) { u_long nonblocking = 0; - ioctlsocket(fd, FIONBIO, &nonblocking); + return ioctlsocket(fd, FIONBIO, &nonblocking); } #else /* _WIN32 */ -void ssh_socket_set_nonblocking(socket_t fd) { - fcntl(fd, F_SETFL, O_NONBLOCK); +int ssh_socket_set_nonblocking(socket_t fd) { + return fcntl(fd, F_SETFL, O_NONBLOCK); } -void ssh_socket_set_blocking(socket_t fd) { - fcntl(fd, F_SETFL, 0); +int ssh_socket_set_blocking(socket_t fd) { + return fcntl(fd, F_SETFL, 0); } #endif /* _WIN32 */ diff --git a/libssh/tests/client/torture_session.c b/libssh/tests/client/torture_session.c index d66901da..4e2f6477 100644 --- a/libssh/tests/client/torture_session.c +++ b/libssh/tests/client/torture_session.c @@ -83,7 +83,8 @@ static void torture_channel_read_error(void **state) { assert_true(rc == SSH_OK); /* send crap and for server to send us a disconnect */ - write(ssh_get_fd(session),"AAAA", 4); + rc = write(ssh_get_fd(session),"AAAA", 4); + assert_int_equal(rc, 4); for (i=0;i<20;++i){ rc = ssh_channel_read(channel,buffer,sizeof(buffer),0); diff --git a/libssh/tests/torture.c b/libssh/tests/torture.c index a75b0a94..2a49f0d7 100644 --- a/libssh/tests/torture.c +++ b/libssh/tests/torture.c @@ -110,6 +110,7 @@ int torture_rmdirs(const char *path) { len = strlen(path) + strlen(dp->d_name) + 2; fname = malloc(len); if (fname == NULL) { + closedir(d); return -1; } snprintf(fname, len, "%s/%s", path, dp->d_name); diff --git a/libssh/tests/unittests/torture_buffer.c b/libssh/tests/unittests/torture_buffer.c index 511cdf45..dee6e7d4 100644 --- a/libssh/tests/unittests/torture_buffer.c +++ b/libssh/tests/unittests/torture_buffer.c @@ -66,22 +66,25 @@ static void torture_buffer_prepend(void **state) { buffer_add_data(buffer,"abcdef",6); buffer_prepend_data(buffer,"xyz",3); assert_int_equal(buffer_get_rest_len(buffer),9); - assert_int_equal(memcmp(buffer_get_rest(buffer), "xyzabcdef", 9), 0); -// Now remove 4 bytes and see if we can replace them + assert_memory_equal(buffer_get_rest(buffer), "xyzabcdef", 9); + + /* Now remove 4 bytes and see if we can replace them */ buffer_get_u32(buffer,&v); assert_int_equal(buffer_get_rest_len(buffer),5); - assert_int_equal(memcmp(buffer_get_rest(buffer), "bcdef", 5), 0); + assert_memory_equal(buffer_get_rest(buffer), "bcdef", 5); + buffer_prepend_data(buffer,"aris",4); assert_int_equal(buffer_get_rest_len(buffer),9); - assert_int_equal(memcmp(buffer_get_rest(buffer), "arisbcdef", 9), 0); + assert_memory_equal(buffer_get_rest(buffer), "arisbcdef", 9); + /* same thing but we add 5 bytes now */ buffer_get_u32(buffer,&v); assert_int_equal(buffer_get_rest_len(buffer),5); - assert_int_equal(memcmp(buffer_get_rest(buffer), "bcdef", 5), 0); + assert_memory_equal(buffer_get_rest(buffer), "bcdef", 5); + buffer_prepend_data(buffer,"12345",5); assert_int_equal(buffer_get_rest_len(buffer),10); - assert_int_equal(memcmp(buffer_get_rest(buffer), "12345bcdef", 10), 0); - + assert_memory_equal(buffer_get_rest(buffer), "12345bcdef", 10); } /* @@ -89,7 +92,7 @@ static void torture_buffer_prepend(void **state) { */ static void torture_buffer_get_ssh_string(void **state) { ssh_buffer buffer; - int i,j,k,l; + int i,j,k,l, rc; /* some values that can go wrong */ uint32_t values[] = {0xffffffff, 0xfffffffe, 0xfffffffc, 0xffffff00, 0x80000000, 0x80000004, 0x7fffffff}; @@ -100,13 +103,18 @@ static void torture_buffer_get_ssh_string(void **state) { for(j=0; j< (int)sizeof(data);++j){ for(k=1;k<5;++k){ buffer=buffer_new(); + assert_non_null(buffer); + for(l=0;l