static int grow_window(SSH_SESSION *session, CHANNEL *channel, int minimumsize) { u32 new_window = minimumsize > WINDOWBASE ? minimumsize : WINDOWBASE; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_WINDOW_ADJUST) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_u32(session->out_buffer, htonl(new_window)) < 0) { goto error; } if (packet_send(session) != SSH_OK) { /* FIXME should we fail here or not? */ leave_function(); return 1; } ssh_log(session, SSH_LOG_PROTOCOL, "growing window (channel %d:%d) to %d bytes", channel->local_channel, channel->remote_channel, channel->local_window + new_window); channel->local_window += new_window; leave_function(); return 0; error: buffer_free(session->out_buffer); leave_function(); return -1; }
/** * @brief Change the size of the terminal associated to a channel. * * @param channel The channel to change the size. * * @param cols The new number of columns. * * @param rows The new number of rows. * * @warning Do not call it from a signal handler if you are not * sure any other libssh function using the same channel/session * is running at same time (not 100% threadsafe). */ int channel_change_pty_size(CHANNEL *channel, int cols, int rows) { SSH_SESSION *session = channel->session; BUFFER *buffer = NULL; int rc = SSH_ERROR; enter_function(); #ifdef HAVE_SSH1 if (channel->version == 1) { rc = channel_change_pty_size1(channel,cols,rows); leave_function(); return rc; } #endif buffer = buffer_new(); if (buffer == NULL) { goto error; } if (buffer_add_u32(buffer, htonl(cols)) < 0 || buffer_add_u32(buffer, htonl(rows)) < 0 || buffer_add_u32(buffer, 0) < 0 || buffer_add_u32(buffer, 0) < 0) { goto error; } rc = channel_request(channel, "window-change", buffer, 0); error: buffer_free(buffer); leave_function(); return rc; }
static void channel_rcv_change_window(SSH_SESSION *session) { CHANNEL *channel; u32 bytes; int rc; enter_function(); channel = channel_from_msg(session); if (channel == NULL) { ssh_log(session, SSH_LOG_FUNCTIONS, ssh_get_error(session)); } rc = buffer_get_u32(session->in_buffer, &bytes); if (channel == NULL || rc != sizeof(u32)) { ssh_log(session, SSH_LOG_PACKET, "Error getting a window adjust message: invalid packet"); leave_function(); return; } bytes = ntohl(bytes); ssh_log(session, SSH_LOG_PROTOCOL, "Adding %d bytes to channel (%d:%d) (from %d bytes)", bytes, channel->local_channel, channel->remote_channel, channel->remote_window); channel->remote_window += bytes; leave_function(); }
/** * @brief Close and free a channel. * * @param channel The channel to free. * * @warning Any data unread on this channel will be lost. */ void channel_free(CHANNEL *channel) { SSH_SESSION *session = channel->session; enter_function(); if (channel == NULL) { leave_function(); return; } if (session->alive && channel->open) { channel_close(channel); } /* handle the "my channel is first on session list" case */ if (session->channels == channel) { session->channels = channel->next; } /* handle the "my channel is the only on session list" case */ if (channel->next == channel) { session->channels = NULL; } else { channel->prev->next = channel->next; channel->next->prev = channel->prev; } buffer_free(channel->stdout_buffer); buffer_free(channel->stderr_buffer); /* debug trick to catch use after frees */ memset(channel, 'X', sizeof(CHANNEL)); SAFE_FREE(channel); leave_function(); }
/** * @brief Send an end of file on the channel. * * This doesn't close the channel. You may still read from it but not write. * * @param channel The channel to send the eof to. * * @return SSH_SUCCESS on success\n * SSH_ERROR on error\n * * @see channel_close() * @see channel_free() */ int channel_send_eof(CHANNEL *channel){ SSH_SESSION *session = channel->session; int rc = SSH_ERROR; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_EOF) < 0) { goto error; } if (buffer_add_u32(session->out_buffer,htonl(channel->remote_channel)) < 0) { goto error; } rc = packet_send(session); ssh_log(session, SSH_LOG_PACKET, "Sent a EOF on client channel (%d:%d)", channel->local_channel, channel->remote_channel); channel->local_eof = 1; leave_function(); return rc; error: buffer_free(session->out_buffer); leave_function(); return rc; }
/** @internal * @brief Starts ecdh-sha2-nistp256 key exchange */ int ssh_client_ecdh_init(ssh_session session){ EC_KEY *key=NULL; 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; } key = EC_KEY_new_by_curve_name(NISTP256); 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); 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); 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; }
/* this function sends the first packet as explained in section 3.1 * of the draft */ static int kbdauth_init(SSH_SESSION *session, const char *user, const char *submethods){ STRING *user_s=string_from_char(user); STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char("")); STRING *service=string_from_char("ssh-connection"); STRING *method=string_from_char("keyboard-interactive"); int err; enter_function(); buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); buffer_add_ssh_string(session->out_buffer,user_s); buffer_add_ssh_string(session->out_buffer,service); buffer_add_ssh_string(session->out_buffer,method); buffer_add_u32(session->out_buffer,0); // language tag buffer_add_ssh_string(session->out_buffer,submethods_s); free(user_s); free(service); free(method); free(submethods_s); if(packet_send(session)){ leave_function(); return SSH_AUTH_ERROR; } err=wait_auth_status(session,1); leave_function(); return err; }
/* this function sends the first packet as explained in section 3.1 * of the draft */ static int kbdauth_init(ssh_session session, const char *user, const char *submethods) { ssh_string usr = NULL; ssh_string sub = NULL; ssh_string service = NULL; ssh_string method = NULL; int rc = SSH_AUTH_ERROR; enter_function(); usr = string_from_char(user); if (usr == NULL) { goto error; } sub = (submethods ? string_from_char(submethods) : string_from_char("")); if (sub == NULL) { goto error; } service = string_from_char("ssh-connection"); if (service == NULL) { goto error; } method = string_from_char("keyboard-interactive"); if (method == NULL) { goto error; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST) < 0 || buffer_add_ssh_string(session->out_buffer, usr) < 0 || buffer_add_ssh_string(session->out_buffer, service) < 0 || buffer_add_ssh_string(session->out_buffer, method) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 || buffer_add_ssh_string(session->out_buffer, sub) < 0) { goto error; } string_free(usr); string_free(service); string_free(method); string_free(sub); if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session,1); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_free(usr); string_free(service); string_free(method); string_free(sub); leave_function(); return rc; }
/* TODO: make this function accept a ssh_channel */ ssh_channel ssh_message_channel_request_open_reply_accept(ssh_message msg) { ssh_session session; ssh_channel chan = NULL; enter_function(); if (msg == NULL) { leave_function(); return NULL; } session = msg->session; chan = ssh_channel_new(session); if (chan == NULL) { leave_function(); return NULL; } chan->local_channel = ssh_channel_new_id(session); chan->local_maxpacket = 35000; chan->local_window = 32000; chan->remote_channel = msg->channel_request_open.sender; chan->remote_maxpacket = msg->channel_request_open.packet_size; chan->remote_window = msg->channel_request_open.window; chan->state = SSH_CHANNEL_STATE_OPEN; if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(chan->remote_channel)) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(chan->local_channel)) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(chan->local_window)) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, htonl(chan->local_maxpacket)) < 0) { goto error; } ssh_log(session, SSH_LOG_PACKET, "Accepting a channel request_open for chan %d", chan->remote_channel); if (packet_send(session) == SSH_ERROR) { goto error; } leave_function(); return chan; error: ssh_channel_free(chan); leave_function(); return NULL; }
/* this function only sends the predefined set of kex methods */ int ssh_send_kex(ssh_session session, int server_kex) { struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex : &session->next_crypto->client_kex); ssh_string str = NULL; int i; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { goto error; } if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { goto error; } if (hashbufout_add_cookie(session) < 0) { goto error; } ssh_list_kex(session, kex); for (i = 0; i < KEX_METHODS_SIZE; i++) { str = ssh_string_from_char(kex->methods[i]); if (str == NULL) { goto error; } if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) { goto error; } if (buffer_add_ssh_string(session->out_buffer, str) < 0) { goto error; } ssh_string_free(str); } if (buffer_add_u8(session->out_buffer, 0) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, 0) < 0) { goto error; } if (packet_send(session) == SSH_ERROR) { leave_function(); return -1; } leave_function(); return 0; error: buffer_reinit(session->out_buffer); buffer_reinit(session->out_hashbuf); ssh_string_free(str); leave_function(); return -1; }
/* this function only sends the predefined set of kex methods */ int ssh_send_kex(SSH_SESSION *session, int server_kex) { KEX *kex = (server_kex ? &session->server_kex : &session->client_kex); STRING *str = NULL; int i; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) { goto error; } if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) { goto error; } if (hashbufout_add_cookie(session) < 0) { goto error; } ssh_list_kex(session, kex); for (i = 0; i < 10; i++) { str = string_from_char(kex->methods[i]); if (str == NULL) { goto error; } if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) { goto error; } if (buffer_add_ssh_string(session->out_buffer, str) < 0) { goto error; } string_free(str); } if (buffer_add_u8(session->out_buffer, 0) < 0) { goto error; } if (buffer_add_u32(session->out_buffer, 0) < 0) { goto error; } if (packet_send(session) != SSH_OK) { leave_function(); return -1; } leave_function(); return 0; error: buffer_free(session->out_buffer); buffer_free(session->out_hashbuf); string_free(str); leave_function(); return -1; }
static int kbdauth_info_get(SSH_SESSION *session){ STRING *name; /* name of the "asking" window showed to client */ STRING *instruction; STRING *tmp; u32 nprompts; u32 i; enter_function(); name=buffer_get_ssh_string(session->in_buffer); instruction=buffer_get_ssh_string(session->in_buffer); tmp=buffer_get_ssh_string(session->in_buffer); buffer_get_u32(session->in_buffer,&nprompts); if(!name || !instruction || !tmp){ if(name) free(name); if(instruction) free(instruction); // tmp must be empty if we got here ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg"); leave_function(); return SSH_AUTH_ERROR; } if(tmp) free(tmp); // no use if(!session->kbdint) session->kbdint=kbdint_new(); else kbdint_clean(session->kbdint); session->kbdint->name=string_to_char(name); free(name); session->kbdint->instruction=string_to_char(instruction); free(instruction); nprompts=ntohl(nprompts); if(nprompts>KBDINT_MAX_PROMPT){ ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts); leave_function(); return SSH_AUTH_ERROR; } session->kbdint->nprompts=nprompts; session->kbdint->prompts=malloc(nprompts*sizeof(char *)); memset(session->kbdint->prompts,0,nprompts*sizeof(char *)); session->kbdint->echo=malloc(nprompts); memset(session->kbdint->echo,0,nprompts); for(i=0;i<nprompts;++i){ tmp=buffer_get_ssh_string(session->in_buffer); buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]); if(!tmp){ ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet"); leave_function(); return SSH_AUTH_ERROR; } session->kbdint->prompts[i]=string_to_char(tmp); free(tmp); } leave_function(); return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */ }
/** \internal * \brief starts a nonblocking flush of the output buffer * */ int ssh_socket_nonblocking_flush(ssh_socket s) { ssh_session session = s->session; uint32_t len; int w; enter_function(); if (!ssh_socket_is_open(s)) { session->alive = 0; /* FIXME use ssh_socket_get_errno */ ssh_set_error(session, SSH_FATAL, "Writing packet: error on socket (or connection closed): %s", strerror(s->last_errno)); leave_function(); return SSH_ERROR; } len = buffer_get_rest_len(s->out_buffer); if (!s->write_wontblock && s->poll_out && len > 0) { /* force the poll system to catch pollout events */ ssh_poll_add_events(s->poll_out, POLLOUT); leave_function(); return SSH_AGAIN; } if (s->write_wontblock && len > 0) { w = ssh_socket_unbuffered_write(s, buffer_get_rest(s->out_buffer), len); if (w < 0) { session->alive = 0; ssh_socket_close(s); /* FIXME use ssh_socket_get_errno() */ /* FIXME use callback for errors */ ssh_set_error(session, SSH_FATAL, "Writing packet: error on socket (or connection closed): %s", strerror(s->last_errno)); leave_function(); return SSH_ERROR; } buffer_pass_bytes(s->out_buffer, w); } /* Is there some data pending? */ len = buffer_get_rest_len(s->out_buffer); if (s->poll_out && len > 0) { /* force the poll system to catch pollout events */ ssh_poll_add_events(s->poll_out, POLLOUT); leave_function(); return SSH_AGAIN; } /* all data written */ leave_function(); return SSH_OK; }
/** * @internal * * @brief Gets the banner from socket and saves it in session. * Updates the session state * * @param data pointer to the beginning of header * @param len size of the banner * @param user is a pointer to session * @returns Number of bytes processed, or zero if the banner is not complete. */ static int callback_receive_banner(const void *data, size_t len, void *user) { char *buffer = (char *) data; ssh_session session = (ssh_session) user; char *str = NULL; size_t i; int ret=0; enter_function(); for (i = 0; i < len; i++) { #ifdef WITH_PCAP if(session->pcap_ctx && buffer[i] == '\n') { ssh_pcap_context_write(session->pcap_ctx, SSH_PCAP_DIR_IN, buffer, i + 1, i + 1); } #endif if (buffer[i] == '\r') { buffer[i]='\0'; } if (buffer[i] == '\n') { buffer[i]='\0'; str = strdup(buffer); /* number of bytes read */ ret = i + 1; session->clientbanner = str; session->session_state = SSH_SESSION_STATE_BANNER_RECEIVED; ssh_log(session, SSH_LOG_PACKET, "Received banner: %s", str); session->ssh_connection_callback(session); leave_function(); return ret; } if(i > 127) { /* Too big banner */ session->session_state = SSH_SESSION_STATE_ERROR; ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner"); leave_function(); return 0; } } leave_function(); return ret; }
int ssh_userauth_pubkey(SSH_SESSION *session, const char *username, STRING *publickey, PRIVATE_KEY *privatekey){ STRING *user; STRING *service; STRING *method; STRING *algo; STRING *sign; int err=SSH_AUTH_ERROR; enter_function(); // if(session->version==1) // return ssh_userauth1_pubkey(session,username,publickey,privatekey); if(!username) if(!(username=session->options->username)){ if(ssh_options_default_username(session->options)){ leave_function(); return err; } else username=session->options->username; } if(ask_userauth(session)){ leave_function(); return err; } user=string_from_char(username); service=string_from_char("ssh-connection"); method=string_from_char("publickey"); algo=string_from_char(ssh_type_to_char(privatekey->type)); /* we said previously the public key was accepted */ buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); buffer_add_ssh_string(session->out_buffer,user); buffer_add_ssh_string(session->out_buffer,service); buffer_add_ssh_string(session->out_buffer,method); buffer_add_u8(session->out_buffer,1); buffer_add_ssh_string(session->out_buffer,algo); buffer_add_ssh_string(session->out_buffer,publickey); sign=ssh_do_sign(session,session->out_buffer,privatekey); if(sign){ buffer_add_ssh_string(session->out_buffer,sign); free(sign); packet_send(session); err=wait_auth_status(session,0); } free(user); free(service); free(method); free(algo); leave_function(); return err; }
int ssh_userauth_password(SSH_SESSION *session, const char *username, const char *password){ STRING *user; STRING *service; STRING *method; STRING *password_s; int err; enter_function(); #ifdef HAVE_SSH1 if(session->version==1){ err = ssh_userauth1_password(session,username,password); leave_function(); return err; } #endif if(!username) if(!(username=session->options->username)){ if(ssh_options_default_username(session->options)){ err = SSH_AUTH_ERROR; leave_function(); return err; } else username=session->options->username; } if(ask_userauth(session)){ leave_function(); return SSH_AUTH_ERROR; } user=string_from_char(username); service=string_from_char("ssh-connection"); method=string_from_char("password"); password_s=string_from_char(password); buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); buffer_add_ssh_string(session->out_buffer,user); buffer_add_ssh_string(session->out_buffer,service); buffer_add_ssh_string(session->out_buffer,method); buffer_add_u8(session->out_buffer,0); buffer_add_ssh_string(session->out_buffer,password_s); free(user); free(service); free(method); memset(password_s,0,strlen(password)+4); free(password_s); packet_send(session); err=wait_auth_status(session,0); leave_function(); return err; }
static int ssh_message_auth_reply_default(ssh_message msg,int partial) { ssh_session session = msg->session; char methods_c[128] = {0}; ssh_string methods = NULL; int rc = SSH_ERROR; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) { return rc; } if (session->auth_methods == 0) { session->auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PASSWORD; } if (session->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { strcat(methods_c, "publickey,"); } if (session->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { strcat(methods_c, "keyboard-interactive,"); } if (session->auth_methods & SSH_AUTH_METHOD_PASSWORD) { strcat(methods_c, "password,"); } if (session->auth_methods & SSH_AUTH_METHOD_HOSTBASED) { strcat(methods_c, "hostbased,"); } /* Strip the comma. */ methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure there is at ssh_log(session, SSH_LOG_PACKET, "Sending a auth failure. methods that can continue: %s", methods_c); methods = ssh_string_from_char(methods_c); if (methods == NULL) { goto error; } if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) { goto error; } if (partial) { if (buffer_add_u8(session->out_buffer, 1) < 0) { goto error; } } else { if (buffer_add_u8(session->out_buffer, 0) < 0) { goto error; } } rc = packet_send(msg->session); error: ssh_string_free(methods); leave_function(); return rc; }
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("*****@*****.**"); 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; }
/** @internal * @brief dispatch the call of packet handlers callbacks for a received packet * @param type type of packet */ void ssh_packet_process(ssh_session session, uint8_t type){ struct ssh_iterator *i; int r=SSH_PACKET_NOT_USED; ssh_packet_callbacks cb; enter_function(); ssh_log(session,SSH_LOG_PACKET, "Dispatching handler for packet type %d",type); if(session->packet_callbacks == NULL){ ssh_log(session,SSH_LOG_RARE,"Packet callback is not initialized !"); goto error; } i=ssh_list_get_iterator(session->packet_callbacks); while(i != NULL){ cb=ssh_iterator_value(ssh_packet_callbacks,i); i=i->next; if(!cb) continue; if(cb->start > type) continue; if(cb->start + cb->n_callbacks <= type) continue; if(cb->callbacks[type - cb->start]==NULL) continue; r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user); if(r==SSH_PACKET_USED) break; } if(r==SSH_PACKET_NOT_USED){ ssh_log(session,SSH_LOG_RARE,"Couldn't do anything with packet type %d",type); ssh_packet_send_unimplemented(session, session->recv_seq-1); } error: leave_function(); }
/** @brief Select the different methods on basis of client's and * server's kex messages, and watches out if a match is possible. */ int ssh_kex_select_methods (ssh_session session){ struct ssh_kex_struct *server = &session->next_crypto->server_kex; struct ssh_kex_struct *client = &session->next_crypto->client_kex; int rc = SSH_ERROR; int i; enter_function(); for (i = 0; i < KEX_METHODS_SIZE; i++) { session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]); if(session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){ ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]", ssh_kex_descriptions[i],server->methods[i],client->methods[i]); goto error; } else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) { /* we can safely do that for languages */ session->next_crypto->kex_methods[i] = strdup(""); } } if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){ session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1; } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){ session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1; } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){ session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256; } rc = SSH_OK; error: leave_function(); return rc; }
/** @internal * @brief Sends a SSH banner to the server. * * @param session The SSH session to use. * * @param server Send client or server banner. * * @return 0 on success, < 0 on error. */ int ssh_send_banner(ssh_session session, int server) { const char *banner = NULL; char buffer[128] = {0}; int err=SSH_ERROR; enter_function(); banner = session->version == 1 ? CLIENTBANNER1 : CLIENTBANNER2; if (server) { session->serverbanner = strdup(banner); if (session->serverbanner == NULL) { goto end; } } else { session->clientbanner = strdup(banner); if (session->clientbanner == NULL) { goto end; } } snprintf(buffer, 128, "%s\n", banner); if (ssh_socket_write(session->socket, buffer, strlen(buffer)) == SSH_ERROR) { goto end; } #ifdef WITH_PCAP if(session->pcap_ctx) ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,buffer,strlen(buffer),strlen(buffer)); #endif err=SSH_OK; end: leave_function(); return err; }
/* * channel_handle() is called by packet_wait(), for example when there is * channel informations to handle. */ void channel_handle(SSH_SESSION *session, int type){ enter_function(); ssh_log(session, SSH_LOG_PROTOCOL, "Channel_handle(%d)", type); switch(type) { case SSH2_MSG_CHANNEL_WINDOW_ADJUST: channel_rcv_change_window(session); break; case SSH2_MSG_CHANNEL_DATA: channel_rcv_data(session,0); break; case SSH2_MSG_CHANNEL_EXTENDED_DATA: channel_rcv_data(session,1); break; case SSH2_MSG_CHANNEL_EOF: channel_rcv_eof(session); break; case SSH2_MSG_CHANNEL_CLOSE: channel_rcv_close(session); break; case SSH2_MSG_CHANNEL_REQUEST: channel_rcv_request(session); break; default: ssh_log(session, SSH_LOG_FUNCTIONS, "Unexpected message %d", type); } leave_function(); }
/** @internal * @brief launches the DH handshake state machine * @param session session handle * @returns SSH_OK or SSH_ERROR * @warning this function returning is no proof that DH handshake is * completed */ static int dh_handshake(ssh_session session) { int rc = SSH_AGAIN; enter_function(); switch (session->dh_handshake_state) { case DH_STATE_INIT: switch(session->next_crypto->kex_type){ case SSH_KEX_DH_GROUP1_SHA1: case SSH_KEX_DH_GROUP14_SHA1: rc = ssh_client_dh_init(session); break; #ifdef HAVE_ECDH case SSH_KEX_ECDH_SHA2_NISTP256: rc = ssh_client_ecdh_init(session); break; #endif default: rc=SSH_ERROR; goto error; } if (rc == SSH_ERROR) { goto error; } session->dh_handshake_state = DH_STATE_INIT_SENT; case DH_STATE_INIT_SENT: /* wait until ssh_packet_dh_reply is called */ break; case DH_STATE_NEWKEYS_SENT: /* wait until ssh_packet_newkeys is called */ break; case DH_STATE_FINISHED: leave_function(); return SSH_OK; default: ssh_set_error(session, SSH_FATAL, "Invalid state in dh_handshake(): %d", session->dh_handshake_state); leave_function(); return SSH_ERROR; } error: leave_function(); return rc; }
int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username,int type, STRING *publickey){ STRING *user; STRING *service; STRING *method; STRING *algo; int err=SSH_AUTH_ERROR; enter_function(); #ifdef HAVE_SSH1 if(session->version==1){ err= ssh_userauth1_offer_pubkey(session,username,type,publickey); leave_function(); return err; } #endif if(!username) if(!(username=session->options->username)){ if(ssh_options_default_username(session->options)){ leave_function(); return SSH_AUTH_ERROR; } else username=session->options->username; } if(ask_userauth(session)){ leave_function(); return SSH_AUTH_ERROR; } user=string_from_char(username); service=string_from_char("ssh-connection"); method=string_from_char("publickey"); algo=string_from_char(ssh_type_to_char(type)); buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); buffer_add_ssh_string(session->out_buffer,user); buffer_add_ssh_string(session->out_buffer,service); buffer_add_ssh_string(session->out_buffer,method); buffer_add_u8(session->out_buffer,0); buffer_add_ssh_string(session->out_buffer,algo); buffer_add_ssh_string(session->out_buffer,publickey); packet_send(session); err=wait_auth_status(session,0); free(user); free(method); free(service); free(algo); leave_function(); return err; }
/* sends challenge back to the server */ static int kbdauth_send(ssh_session session) { ssh_string answer = NULL; int rc = SSH_AUTH_ERROR; uint32_t i; enter_function(); if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_INFO_RESPONSE) < 0 || buffer_add_u32(session->out_buffer, htonl(session->kbdint->nprompts)) < 0) { goto error; } for (i = 0; i < session->kbdint->nprompts; i++) { if (session->kbdint->answers[i]) { answer = string_from_char(session->kbdint->answers[i]); } else { answer = string_from_char(""); } if (answer == NULL) { goto error; } if (buffer_add_ssh_string(session->out_buffer, answer) < 0) { goto error; } string_burn(answer); string_free(answer); } if (packet_send(session) != SSH_OK) { leave_function(); return rc; } rc = wait_auth_status(session,1); leave_function(); return rc; error: buffer_reinit(session->out_buffer); string_burn(answer); string_free(answer); leave_function(); return rc; }
/** @internal * @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet * @param session the SSH session * @param seqnum the sequence number of the unknown packet * @return SSH_ERROR on error, else SSH_OK */ int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){ int r; enter_function(); buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED); buffer_add_u32(session->out_buffer, htonl(seqnum)); r = packet_send(session); leave_function(); return r; }
int signature_verify(ssh_session session, ssh_string signature) { ssh_public_key pubkey = NULL; SIGNATURE *sign = NULL; int err; enter_function(); pubkey = publickey_from_string(session,session->next_crypto->server_pubkey); if(pubkey == NULL) { leave_function(); return -1; } if (session->wanted_methods[SSH_HOSTKEYS]) { if(!match(session->wanted_methods[SSH_HOSTKEYS],pubkey->type_c)) { ssh_set_error(session, SSH_FATAL, "Public key from server (%s) doesn't match user preference (%s)", pubkey->type_c, session->wanted_methods[SSH_HOSTKEYS]); publickey_free(pubkey); leave_function(); return -1; } } sign = signature_from_string(session, signature, pubkey, pubkey->type); if (sign == NULL) { ssh_set_error(session, SSH_FATAL, "Invalid signature blob"); publickey_free(pubkey); leave_function(); return -1; } ssh_log(session, SSH_LOG_FUNCTIONS, "Going to verify a %s type signature", pubkey->type_c); err = sig_verify(session,pubkey,sign, session->next_crypto->session_id,SHA_DIGEST_LEN); signature_free(sign); session->next_crypto->server_pubkey_type = pubkey->type_c; publickey_free(pubkey); leave_function(); return err; }
/** * @internal * @brief Callback to be called when the socket is connected or had a * connection error. Changes the state of the session and updates the error * message. * @param code one of SSH_SOCKET_CONNECTED_OK or SSH_SOCKET_CONNECTED_ERROR * @param user is a pointer to session */ static void socket_callback_connected(int code, int errno_code, void *user){ ssh_session session=(ssh_session)user; enter_function(); if(session->session_state != SSH_SESSION_STATE_CONNECTING){ ssh_set_error(session,SSH_FATAL, "Wrong state in socket_callback_connected : %d", session->session_state); leave_function(); return; } ssh_log(session,SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code); if(code == SSH_SOCKET_CONNECTED_OK) session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED; else { session->session_state=SSH_SESSION_STATE_ERROR; ssh_set_error(session,SSH_FATAL,"%s",strerror(errno_code)); } session->ssh_connection_callback(session); leave_function(); }
/** * @brief Request a pty with a specific type and size. * * @param channel The channel to sent the request. * * @param terminal The terminal type ("vt100, xterm,..."). * * @param col The number of columns. * * @param row The number of rows. * * @return SSH_SUCCESS on success, SSH_ERROR on error. */ int channel_request_pty_size(CHANNEL *channel, const char *terminal, int col, int row) { SSH_SESSION *session = channel->session; STRING *term = NULL; BUFFER *buffer = NULL; int rc = SSH_ERROR; enter_function(); #ifdef HAVE_SSH1 if (channel->version==1) { channel_request_pty_size1(channel,terminal, col, row); leave_function(); return rc; } #endif buffer = buffer_new(); if (buffer == NULL) { goto error; } term = string_from_char(terminal); if (term == NULL) { goto error; } if (buffer_add_ssh_string(buffer, term) < 0 || buffer_add_u32(buffer, htonl(col)) < 0 || buffer_add_u32(buffer, htonl(row)) < 0 || buffer_add_u32(buffer, 0) < 0 || buffer_add_u32(buffer, 0) < 0 || buffer_add_u32(buffer, htonl(1)) < 0 || /* Add a 0byte string */ buffer_add_u8(buffer, 0) < 0) { goto error; } rc = channel_request(channel, "pty-req", buffer, 1); error: buffer_free(buffer); string_free(term); leave_function(); return rc; }
/** \internal * \todo implement ssh1 public key */ int ssh_userauth1_offer_pubkey(ssh_session session, const char *username, int type, ssh_string pubkey) { (void) session; (void) username; (void) type; (void) pubkey; enter_function(); leave_function(); return SSH_AUTH_DENIED; }