/** * @internal * * @brief Pop a message from the message list and dequeue it. * * @param[in] session The SSH session to pop the message. * * @returns The head message or NULL if it doesn't exist. */ ssh_message ssh_message_pop_head(ssh_session session){ ssh_message msg=NULL; struct ssh_iterator *i; if(session->ssh_message_list == NULL) return NULL; i=ssh_list_get_iterator(session->ssh_message_list); if(i != NULL){ msg=ssh_iterator_value(ssh_message,i); ssh_list_remove(session->ssh_message_list,i); } return msg; }
/** * @brief Remove a session object from an event context. * * @param event The ssh_event object. * @param session The session to remove. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_remove_session(ssh_event event, ssh_session session) { ssh_poll_handle p; register size_t i, used; int rc = SSH_ERROR; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } used = event->ctx->polls_used; for(i = 0; i < used; i++) { p = event->ctx->pollptrs[i]; if(p->session == session){ /* * ssh_poll_ctx_remove() decrements * event->ctx->polls_used */ ssh_poll_ctx_remove(event->ctx, p); p->session = NULL; ssh_poll_ctx_add(session->default_poll_ctx, p); rc = SSH_OK; /* * Restart the loop! * A session can initially have two pollhandlers. */ used = event->ctx->polls_used; i = 0; } } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { ssh_list_remove(event->sessions, iterator); /* there should be only one instance of this session */ break; } iterator = iterator->next; } #endif return rc; }
int ssh_remove_channel_callbacks(ssh_channel channel, ssh_channel_callbacks cb) { struct ssh_iterator *it; if (channel == NULL || channel->callbacks == NULL){ return SSH_ERROR; } it = ssh_list_find(channel->callbacks, cb); if (it == NULL){ return SSH_ERROR; } ssh_list_remove(channel->callbacks, it); return SSH_OK; }
/** * @brief Remove a session object from an event context. * * @param event The ssh_event object. * @param session The session to remove. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_remove_session(ssh_event event, ssh_session session) { ssh_poll_handle p; register size_t i, used; int rc = SSH_ERROR; socket_t session_fd; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } session_fd = ssh_get_fd(session); used = event->ctx->polls_used; for(i = 0; i < used; i++) { if(session_fd == event->ctx->pollfds[i].fd) { p = event->ctx->pollptrs[i]; ssh_poll_ctx_remove(event->ctx, p); ssh_poll_ctx_add(session->default_poll_ctx, p); rc = SSH_OK; } } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { ssh_list_remove(event->sessions, iterator); /* there should be only one instance of this session */ break; } iterator = iterator->next; } #endif return rc; }
/** * @brief Disconnect from a session (client or server). * The session can then be reused to open a new session. * * @param[in] session The SSH session to use. */ void ssh_disconnect(ssh_session session) { ssh_string str = NULL; struct ssh_iterator *it; if (session == NULL) { return; } if (session->socket != NULL && ssh_socket_is_open(session->socket)) { if (buffer_add_u8(session->out_buffer, SSH2_MSG_DISCONNECT) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(SSH2_DISCONNECT_BY_APPLICATION)) < 0) { goto error; } str = ssh_string_from_char("Bye Bye"); if (str == NULL) { goto error; } if (buffer_add_ssh_string(session->out_buffer,str) < 0) { ssh_string_free(str); goto error; } ssh_string_free(str); packet_send(session); ssh_socket_close(session->socket); } error: session->alive = 0; if (session->socket != NULL){ ssh_socket_reset(session->socket); } session->opts.fd = SSH_INVALID_SOCKET; session->session_state=SSH_SESSION_STATE_DISCONNECTED; while ((it=ssh_list_get_iterator(session->channels)) != NULL) { ssh_channel_do_free(ssh_iterator_value(ssh_channel,it)); ssh_list_remove(session->channels, it); } if(session->current_crypto){ crypto_free(session->current_crypto); session->current_crypto=NULL; } if (session->in_buffer) { ssh_buffer_reinit(session->in_buffer); } if (session->out_buffer) { ssh_buffer_reinit(session->out_buffer); } if (session->in_hashbuf) { ssh_buffer_reinit(session->in_hashbuf); } if (session->out_hashbuf) { ssh_buffer_reinit(session->out_hashbuf); } session->auth_methods = 0; SAFE_FREE(session->serverbanner); SAFE_FREE(session->clientbanner); if(session->ssh_message_list){ ssh_message msg; while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list)) != NULL){ ssh_message_free(msg); } ssh_list_free(session->ssh_message_list); session->ssh_message_list=NULL; } if (session->packet_callbacks){ ssh_list_free(session->packet_callbacks); session->packet_callbacks=NULL; } }
/** * @brief Deallocate a SSH session handle. * * @param[in] session The SSH session to free. * * @see ssh_disconnect() * @see ssh_new() */ void ssh_free(ssh_session session) { int i; struct ssh_iterator *it; if (session == NULL) { return; } /* * Delete all channels * * This needs the first thing we clean up cause if there is still an open * channel we call ssh_channel_close() first. So we need a working socket * and poll context for it. */ for (it = ssh_list_get_iterator(session->channels); it != NULL; it = ssh_list_get_iterator(session->channels)) { ssh_channel_do_free(ssh_iterator_value(ssh_channel,it)); ssh_list_remove(session->channels, it); } ssh_list_free(session->channels); session->channels = NULL; #ifdef WITH_PCAP if (session->pcap_ctx) { ssh_pcap_context_free(session->pcap_ctx); session->pcap_ctx = NULL; } #endif ssh_socket_free(session->socket); session->socket = NULL; if (session->default_poll_ctx) { ssh_poll_ctx_free(session->default_poll_ctx); } ssh_buffer_free(session->in_buffer); ssh_buffer_free(session->out_buffer); session->in_buffer = session->out_buffer = NULL; if (session->in_hashbuf != NULL) { ssh_buffer_free(session->in_hashbuf); } if (session->out_hashbuf != NULL) { ssh_buffer_free(session->out_hashbuf); } crypto_free(session->current_crypto); crypto_free(session->next_crypto); #ifndef _WIN32 agent_free(session->agent); #endif /* _WIN32 */ ssh_key_free(session->srv.dsa_key); ssh_key_free(session->srv.rsa_key); if (session->ssh_message_list) { ssh_message msg; for (msg = ssh_list_pop_head(ssh_message, session->ssh_message_list); msg != NULL; msg = ssh_list_pop_head(ssh_message, session->ssh_message_list)) { ssh_message_free(msg); } ssh_list_free(session->ssh_message_list); } if (session->packet_callbacks) { ssh_list_free(session->packet_callbacks); } /* options */ if (session->opts.identity) { char *id; for (id = ssh_list_pop_head(char *, session->opts.identity); id != NULL; id = ssh_list_pop_head(char *, session->opts.identity)) { SAFE_FREE(id); } ssh_list_free(session->opts.identity); }
static void torture_knownhosts_precheck(void **state) { struct torture_state *s = *state; ssh_session session = s->ssh.session; struct ssh_list *algo_list = NULL; struct ssh_iterator *it = NULL; size_t algo_count; const char *algo = NULL; char known_hosts_file[1024] = {0}; FILE *file; int rc; snprintf(known_hosts_file, sizeof(known_hosts_file), "%s/%s", s->socket_dir, TORTURE_KNOWN_HOSTS_FILE); file = fopen(known_hosts_file, "w"); assert_non_null(file); fprintf(file, "127.0.0.10 %s\n", torture_get_testkey_pub(SSH_KEYTYPE_RSA)); fprintf(file, "127.0.0.10 %s\n", torture_get_testkey_pub(SSH_KEYTYPE_ED25519)); fprintf(file, "127.0.0.10 %s\n", torture_get_testkey_pub(SSH_KEYTYPE_ECDSA_P521)); fclose(file); rc = ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, known_hosts_file); assert_ssh_return_code(session, rc); algo_list = ssh_known_hosts_get_algorithms(session); assert_non_null(algo_list); algo_count = ssh_list_count(algo_list); assert_int_equal(algo_count, 3); it = ssh_list_get_iterator(algo_list); assert_non_null(it); algo = ssh_iterator_value(const char *, it); assert_string_equal(algo, "ssh-rsa"); ssh_list_remove(algo_list, it); it = ssh_list_get_iterator(algo_list); assert_non_null(it); algo = ssh_iterator_value(const char *, it); assert_string_equal(algo, "ssh-ed25519"); ssh_list_remove(algo_list, it); it = ssh_list_get_iterator(algo_list); assert_non_null(it); algo = ssh_iterator_value(const char *, it); assert_string_equal(algo, "ecdsa-sha2-nistp521"); ssh_list_free(algo_list); }
/** * @brief Disconnect from a session (client or server). * The session can then be reused to open a new session. * * @param[in] session The SSH session to use. */ void ssh_disconnect(ssh_session session) { struct ssh_iterator *it; int rc; if (session == NULL) { return; } if (session->socket != NULL && ssh_socket_is_open(session->socket)) { rc = ssh_buffer_pack(session->out_buffer, "bdss", SSH2_MSG_DISCONNECT, SSH2_DISCONNECT_BY_APPLICATION, "Bye Bye", ""); /* language tag */ if (rc != SSH_OK){ ssh_set_error_oom(session); goto error; } ssh_packet_send(session); ssh_socket_close(session->socket); } error: session->recv_seq = 0; session->send_seq = 0; session->alive = 0; if (session->socket != NULL){ ssh_socket_reset(session->socket); } session->opts.fd = SSH_INVALID_SOCKET; session->session_state=SSH_SESSION_STATE_DISCONNECTED; while ((it=ssh_list_get_iterator(session->channels)) != NULL) { ssh_channel_do_free(ssh_iterator_value(ssh_channel,it)); ssh_list_remove(session->channels, it); } if(session->current_crypto){ crypto_free(session->current_crypto); session->current_crypto=NULL; } if (session->next_crypto) { crypto_free(session->next_crypto); session->next_crypto = crypto_new(); if (session->next_crypto == NULL) { ssh_set_error_oom(session); } } if (session->in_buffer) { ssh_buffer_reinit(session->in_buffer); } if (session->out_buffer) { ssh_buffer_reinit(session->out_buffer); } if (session->in_hashbuf) { ssh_buffer_reinit(session->in_hashbuf); } if (session->out_hashbuf) { ssh_buffer_reinit(session->out_hashbuf); } session->auth.supported_methods = 0; SAFE_FREE(session->serverbanner); SAFE_FREE(session->clientbanner); if(session->ssh_message_list){ ssh_message msg; while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list)) != NULL){ ssh_message_free(msg); } ssh_list_free(session->ssh_message_list); session->ssh_message_list=NULL; } if (session->packet_callbacks){ ssh_list_free(session->packet_callbacks); session->packet_callbacks=NULL; } }