/** @internal * @brief prepends a packet with the pcap header and writes packet * on file */ int ssh_pcap_file_write_packet(ssh_pcap_file pcap, ssh_buffer packet, uint32_t original_len){ ssh_buffer header=ssh_buffer_new(); struct timeval now; int err; if(header == NULL) return SSH_ERROR; gettimeofday(&now,NULL); buffer_add_u32(header,htonl(now.tv_sec)); buffer_add_u32(header,htonl(now.tv_usec)); buffer_add_u32(header,htonl(buffer_get_rest_len(packet))); buffer_add_u32(header,htonl(original_len)); buffer_add_buffer(header,packet); err=ssh_pcap_file_write(pcap,header); ssh_buffer_free(header); return err; }
int channel_write1(ssh_channel channel, const void *data, int len) { ssh_session session; int origlen = len; int effectivelen; const unsigned char *ptr=data; if (channel == NULL) { return -1; } session = channel->session; while (len > 0) { if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) { return -1; } effectivelen = len > 32000 ? 32000 : len; if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) { return -1; } ptr += effectivelen; len -= effectivelen; if (packet_send(session) == SSH_ERROR) { return -1; } ssh_handle_packets(session, SSH_TIMEOUT_NONBLOCKING); } if (ssh_blocking_flush(session,SSH_TIMEOUT_USER) == SSH_ERROR) return -1; return origlen; }
int ssh_message_channel_request_reply_success(ssh_message msg) { uint32_t channel; if (msg == NULL) { return SSH_ERROR; } if (msg->channel_request.want_reply) { channel = msg->channel_request.channel->remote_channel; SSH_LOG(SSH_LOG_PACKET, "Sending a channel_request success to channel %d", channel); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_SUCCESS) < 0) { return SSH_ERROR; } if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) { return SSH_ERROR; } return packet_send(msg->session); } SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the request succeeded"); return SSH_OK; }
int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) { SSH_LOG(SSH_LOG_FUNCTIONS, "Accepting a global request"); if (msg->global_request.want_reply) { if (buffer_add_u8(msg->session->out_buffer , SSH2_MSG_REQUEST_SUCCESS) < 0) { goto error; } if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD && msg->global_request.bind_port == 0) { if (buffer_add_u32(msg->session->out_buffer, htonl(bound_port)) < 0) { goto error; } } return packet_send(msg->session); } if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD && msg->global_request.bind_port == 0) { SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the remote port!"); } return SSH_OK; error: return SSH_ERROR; }
int channel_write1(ssh_channel channel, const void *data, int len) { ssh_session session = channel->session; int origlen = len; int effectivelen; const unsigned char *ptr=data; while (len > 0) { if (buffer_add_u8(session->out_buffer, SSH_CMSG_STDIN_DATA) < 0) { return -1; } effectivelen = len > 32000 ? 32000 : len; if (buffer_add_u32(session->out_buffer, htonl(effectivelen)) < 0 || buffer_add_data(session->out_buffer, ptr, effectivelen) < 0) { return -1; } ptr += effectivelen; len -= effectivelen; if (packet_send(session) != SSH_OK) { return -1; } } return origlen; }
/* 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; }
/* 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; }
/** @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; }
static int ssh_gssapi_send_auth_mic(ssh_session session, ssh_string *oid_set, int n_oid){ ssh_string str; int rc; int i; rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_REQUEST); if (rc < 0) { goto fail; } /* username */ str = ssh_string_from_char(session->opts.username); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } /* service */ str = ssh_string_from_char("ssh-connection"); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } /* method */ str = ssh_string_from_char("gssapi-with-mic"); if (str == NULL) { goto fail; } rc = buffer_add_ssh_string(session->out_buffer, str); ssh_string_free(str); if (rc < 0) { goto fail; } rc = buffer_add_u32(session->out_buffer, htonl(n_oid)); if (rc < 0) { goto fail; } for (i=0; i<n_oid; ++i){ rc = buffer_add_ssh_string(session->out_buffer, oid_set[i]); if (rc < 0) { goto fail; } } session->auth_state = SSH_AUTH_STATE_GSSAPI_REQUEST_SENT; return packet_send(session); fail: buffer_reinit(session->out_buffer); return SSH_ERROR; }
/* 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; }
int sftp_reply_attr(SFTP_CLIENT_MESSAGE *msg, SFTP_ATTRIBUTES *attr) { BUFFER *out=buffer_new(); int r; buffer_add_u32(out,msg->id); buffer_add_attributes(out,attr); r=sftp_packet_write(msg->sftp,SSH_FXP_ATTRS,out); buffer_free(out); return r<0; }
int sftp_reply_handle(SFTP_CLIENT_MESSAGE *msg, STRING *handle) { BUFFER *out=buffer_new(); int r; buffer_add_u32(out,msg->id); buffer_add_ssh_string(out,handle); r=sftp_packet_write(msg->sftp,SSH_FXP_HANDLE,out); buffer_free(out); return r<0; }
/** * @brief Open a TCP/IP forwarding channel. * * @param channel An allocated channel. * * @param remotehost The remote host to connected (host name or IP). * * @param remoteport The remote port. * * @param sourcehost The source host (your local computer). It's facultative * and for logging purpose. * * @param localport The source port (your local computer). It's facultative * and for logging purpose. * * @return SSH_OK on success\n * SSH_ERROR on error */ int channel_open_forward(CHANNEL *channel, const char *remotehost, int remoteport, const char *sourcehost, int localport) { SSH_SESSION *session = channel->session; BUFFER *payload = NULL; STRING *str = NULL; int rc = SSH_ERROR; enter_function(); payload = buffer_new(); if (payload == NULL) { goto error; } str = string_from_char(remotehost); if (str == NULL) { goto error; } if (buffer_add_ssh_string(payload, str) < 0 || buffer_add_u32(payload,htonl(remoteport)) < 0) { goto error; } string_free(str); str = string_from_char(sourcehost); if (str == NULL) { goto error; } if (buffer_add_ssh_string(payload, str) < 0 || buffer_add_u32(payload,htonl(localport)) < 0) { goto error; } rc = channel_open(channel, "direct-tcpip", 64000, 32000, payload); error: buffer_free(payload); string_free(str); leave_function(); return rc; }
/** * @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; }
/* Reduced version of the reply default that only reply with * SSH_MSG_UNIMPLEMENTED */ static int ssh_message_reply_default(ssh_message msg) { SSH_LOG(SSH_LOG_FUNCTIONS, "Reporting unknown packet"); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_UNIMPLEMENTED) < 0) goto error; if (buffer_add_u32(msg->session->out_buffer, htonl(msg->session->recv_seq-1)) < 0) goto error; return packet_send(msg->session); error: return SSH_ERROR; }
int channel_change_pty_size1(ssh_channel channel, int cols, int rows) { ssh_session session = channel->session; if (buffer_add_u8(session->out_buffer, SSH_CMSG_WINDOW_SIZE) < 0 || buffer_add_u32(session->out_buffer, ntohl(rows)) < 0 || buffer_add_u32(session->out_buffer, ntohl(cols)) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 || buffer_add_u32(session->out_buffer, 0) < 0) { return -1; } if (packet_send(session)) { return -1; } ssh_log(session, SSH_LOG_RARE, "Change pty size send"); if (packet_wait(session, SSH_SMSG_SUCCESS, 1) != SSH_OK) { return -1; } switch (session->in_packet.type) { case SSH_SMSG_SUCCESS: ssh_log(session, SSH_LOG_RARE, "pty size changed"); return 0; case SSH_SMSG_FAILURE: ssh_log(session, SSH_LOG_RARE, "pty size change denied"); ssh_set_error(session, SSH_REQUEST_DENIED, "pty size change denied"); return -1; } ssh_set_error(session, SSH_FATAL, "Received unexpected packet type %d", session->in_packet.type); return -1; }
/** @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; r = buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED); if (r < 0) { return SSH_ERROR; } r = buffer_add_u32(session->out_buffer, htonl(seqnum)); if (r < 0) { return SSH_ERROR; } r = packet_send(session); return r; }
/** \brief disconnect from a session (client or server) * \param session ssh session */ void ssh_disconnect(SSH_SESSION *session){ STRING *str; if(session->fd!= -1) { packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_DISCONNECT); buffer_add_u32(session->out_buffer,htonl(SSH2_DISCONNECT_BY_APPLICATION)); str=string_from_char("Bye Bye"); buffer_add_ssh_string(session->out_buffer,str); free(str); packet_send(session); close(session->fd); session->fd=-1; } session->alive=0; ssh_cleanup(session); }
static int ssh_gssapi_send_mic(ssh_session session){ OM_uint32 maj_stat, min_stat; gss_buffer_desc mic_buf = GSS_C_EMPTY_BUFFER; gss_buffer_desc mic_token_buf = GSS_C_EMPTY_BUFFER; ssh_buffer mic_buffer; int rc; SSH_LOG(SSH_LOG_PACKET,"Sending SSH_MSG_USERAUTH_GSSAPI_MIC"); mic_buffer = ssh_gssapi_build_mic(session); if (mic_buffer == NULL) { ssh_set_error_oom(session); return SSH_ERROR; } mic_buf.length = ssh_buffer_get_len(mic_buffer); mic_buf.value = ssh_buffer_get_begin(mic_buffer); maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, &mic_buf, &mic_token_buf); if (GSS_ERROR(maj_stat)){ ssh_buffer_free(mic_buffer); ssh_gssapi_log_error(0, "generating MIC", maj_stat); return SSH_ERROR; } rc = buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_GSSAPI_MIC); if (rc < 0) { ssh_buffer_free(mic_buffer); ssh_set_error_oom(session); return SSH_ERROR; } rc = buffer_add_u32(session->out_buffer, htonl(mic_token_buf.length)); if (rc < 0) { ssh_buffer_free(mic_buffer); ssh_set_error_oom(session); return SSH_ERROR; } rc = buffer_add_data(session->out_buffer, mic_token_buf.value, mic_token_buf.length); ssh_buffer_free(mic_buffer); if (rc < 0) { ssh_set_error_oom(session); return SSH_ERROR; } return packet_send(session); }
/* 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; }
/* this function only sends the predefined set of kex methods */ void ssh_send_kex(SSH_SESSION *session, int server_kex){ STRING *str; int i=0; KEX *kex=(server_kex ? &session->server_kex : &session->client_kex); packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_KEXINIT); buffer_add_data(session->out_buffer,kex->cookie,16); hashbufout_add_cookie(session); ssh_list_kex(kex); for(i=0;i<10;i++){ str=string_from_char(kex->methods[i]); buffer_add_ssh_string(session->out_hashbuf,str); buffer_add_ssh_string(session->out_buffer,str); free(str); } i=0; buffer_add_u8(session->out_buffer,0); buffer_add_u32(session->out_buffer,0); packet_send(session); }
/** * @brief Close a channel. * * This sends an end of file and then closes the channel. You won't be able * to recover any data the server was going to send or was in buffers. * * @param channel The channel to close. * * @return SSH_SUCCESS on success\n * SSH_ERROR on error * * @see channel_free() * @see channel_eof() */ int channel_close(CHANNEL *channel){ SSH_SESSION *session = channel->session; int rc = 0; enter_function(); if (channel->local_eof == 0) { rc = channel_send_eof(channel); } if (rc != SSH_OK) { leave_function(); return rc; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_CLOSE) < 0 || 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 close on client channel (%d:%d)", channel->local_channel, channel->remote_channel); if(rc == SSH_OK) { channel->open = 0; } leave_function(); return rc; error: buffer_free(session->out_buffer); leave_function(); return rc; }
static int ssh_message_channel_request_reply_default(ssh_message msg) { uint32_t channel; if (msg->channel_request.want_reply) { channel = msg->channel_request.channel->remote_channel; SSH_LOG(SSH_LOG_PACKET, "Sending a default channel_request denied to channel %d", channel); if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < 0) { return SSH_ERROR; } if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) { return SSH_ERROR; } return packet_send(msg->session); } SSH_LOG(SSH_LOG_PACKET, "The client doesn't want to know the request failed!"); return SSH_OK; }
/* sends challenge back to the server */ static int kbdauth_send(SSH_SESSION *session) { STRING *answer; u32 i; int err; enter_function(); buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE); buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts)); 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(""); buffer_add_ssh_string(session->out_buffer,answer); string_burn(answer); free(answer); } if(packet_send(session)){ leave_function(); return SSH_AUTH_ERROR; } err = wait_auth_status(session,1); leave_function(); return err; }
/** * @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; } }
int channel_request_pty_size1(ssh_channel channel, const char *terminal, int col, int row) { ssh_session session; ssh_string str = NULL; if (channel == NULL) { return SSH_ERROR; } session = channel->session; if(channel->request_state != SSH_CHANNEL_REQ_STATE_NONE){ ssh_set_error(session,SSH_REQUEST_DENIED,"Wrong request state"); return SSH_ERROR; } str = ssh_string_from_char(terminal); if (str == NULL) { ssh_set_error_oom(session); return -1; } if (buffer_add_u8(session->out_buffer, SSH_CMSG_REQUEST_PTY) < 0 || buffer_add_ssh_string(session->out_buffer, str) < 0) { ssh_string_free(str); return -1; } ssh_string_free(str); if (buffer_add_u32(session->out_buffer, ntohl(row)) < 0 || buffer_add_u32(session->out_buffer, ntohl(col)) < 0 || buffer_add_u32(session->out_buffer, 0) < 0 || /* x */ buffer_add_u32(session->out_buffer, 0) < 0 || /* y */ buffer_add_u8(session->out_buffer, 0) < 0) { /* tty things */ return -1; } ssh_log(session, SSH_LOG_FUNCTIONS, "Opening a ssh1 pty"); channel->request_state = SSH_CHANNEL_REQ_STATE_PENDING; if (packet_send(session) == SSH_ERROR) { return -1; } while (channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING) { ssh_handle_packets(session, SSH_TIMEOUT_INFINITE); } switch(channel->request_state){ case SSH_CHANNEL_REQ_STATE_ERROR: case SSH_CHANNEL_REQ_STATE_PENDING: case SSH_CHANNEL_REQ_STATE_NONE: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; return SSH_ERROR; case SSH_CHANNEL_REQ_STATE_ACCEPTED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; ssh_log(session, SSH_LOG_RARE, "PTY: Success"); return SSH_OK; case SSH_CHANNEL_REQ_STATE_DENIED: channel->request_state=SSH_CHANNEL_REQ_STATE_NONE; ssh_set_error(session, SSH_REQUEST_DENIED, "Server denied PTY allocation"); ssh_log(session, SSH_LOG_RARE, "PTY: denied\n"); return SSH_ERROR; } // Not reached return SSH_ERROR; }
ssh_string ssh_agent_sign_data(ssh_session session, const ssh_key pubkey, struct ssh_buffer_struct *data) { ssh_buffer request; ssh_buffer reply; ssh_string key_blob; ssh_string sig_blob; int type = SSH2_AGENT_FAILURE; int flags = 0; uint32_t dlen; int rc; request = ssh_buffer_new(); if (request == NULL) { return NULL; } /* create request */ if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) { return NULL; } rc = ssh_pki_export_pubkey_blob(pubkey, &key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* adds len + blob */ rc = buffer_add_ssh_string(request, key_blob); ssh_string_free(key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* Add data */ dlen = buffer_get_rest_len(data); if (buffer_add_u32(request, htonl(dlen)) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_data(request, buffer_get_rest(data), dlen) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_u32(request, htonl(flags)) < 0) { ssh_buffer_free(request); return NULL; } reply = ssh_buffer_new(); if (reply == NULL) { ssh_buffer_free(request); return NULL; } /* send the request */ if (agent_talk(session, request, reply) < 0) { ssh_buffer_free(request); return NULL; } ssh_buffer_free(request); /* check if reply is valid */ if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) { ssh_buffer_free(reply); return NULL; } if (agent_failed(type)) { SSH_LOG(session, SSH_LOG_WARN, "Agent reports failure in signing the key"); ssh_buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type); ssh_buffer_free(reply); return NULL; } sig_blob = buffer_get_ssh_string(reply); ssh_buffer_free(reply); return sig_blob; }
int ssh_get_kex1(SSH_SESSION *session) { STRING *server_exp = NULL; STRING *server_mod = NULL; STRING *host_exp = NULL; STRING *host_mod = NULL; STRING *serverkey = NULL; STRING *hostkey = NULL; STRING *enc_session = NULL; PUBLIC_KEY *srv = NULL; PUBLIC_KEY *host = NULL; u32 server_bits; u32 host_bits; u32 protocol_flags; u32 supported_ciphers_mask; u32 supported_authentications_mask; u16 bits; int rc = -1; int ko; enter_function(); ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_PUBLIC_KEY"); if (packet_wait(session, SSH_SMSG_PUBLIC_KEY, 1) != SSH_OK) { leave_function(); return -1; } ssh_log(session, SSH_LOG_PROTOCOL, "Got a SSH_SMSG_PUBLIC_KEY"); if (buffer_get_data(session->in_buffer, session->server_kex.cookie, 8) != 8) { ssh_set_error(session, SSH_FATAL, "Can't get cookie in buffer"); leave_function(); return -1; } buffer_get_u32(session->in_buffer, &server_bits); server_exp = buffer_get_mpint(session->in_buffer); if (server_exp == NULL) { goto error; } server_mod = buffer_get_mpint(session->in_buffer); if (server_mod == NULL) { goto error; } buffer_get_u32(session->in_buffer, &host_bits); host_exp = buffer_get_mpint(session->in_buffer); if (host_exp == NULL) { goto error; } host_mod = buffer_get_mpint(session->in_buffer); if (host_mod == NULL) { goto error; } buffer_get_u32(session->in_buffer, &protocol_flags); buffer_get_u32(session->in_buffer, &supported_ciphers_mask); ko = buffer_get_u32(session->in_buffer, &supported_authentications_mask); if ((ko != sizeof(u32)) || !host_mod || !host_exp || !server_mod || !server_exp) { ssh_log(session, SSH_LOG_RARE, "Invalid SSH_SMSG_PUBLIC_KEY packet"); ssh_set_error(session, SSH_FATAL, "Invalid SSH_SMSG_PUBLIC_KEY packet"); goto error; } server_bits = ntohl(server_bits); host_bits = ntohl(host_bits); protocol_flags = ntohl(protocol_flags); supported_ciphers_mask = ntohl(supported_ciphers_mask); supported_authentications_mask = ntohl(supported_authentications_mask); ssh_log(session, SSH_LOG_PROTOCOL, "Server bits: %d; Host bits: %d; Protocol flags: %.8lx; " "Cipher mask: %.8lx; Auth mask: %.8lx", server_bits, host_bits, (unsigned long int) protocol_flags, (unsigned long int) supported_ciphers_mask, (unsigned long int) supported_authentications_mask); serverkey = make_rsa1_string(server_exp, server_mod); if (serverkey == NULL) { goto error; } hostkey = make_rsa1_string(host_exp,host_mod); if (serverkey == NULL) { goto error; } if (build_session_id1(session, server_mod, host_mod) < 0) { goto error; } srv = publickey_from_string(session, serverkey); if (srv == NULL) { goto error; } host = publickey_from_string(session, hostkey); if (host == NULL) { goto error; } session->next_crypto->server_pubkey = string_copy(hostkey); if (session->next_crypto->server_pubkey == NULL) { goto error; } session->next_crypto->server_pubkey_type = "ssh-rsa1"; /* now, we must choose an encryption algo */ /* hardcode 3des */ if (!(supported_ciphers_mask & (1 << SSH_CIPHER_3DES))) { ssh_set_error(session, SSH_FATAL, "Remote server doesn't accept 3DES"); goto error; } ssh_log(session, SSH_LOG_PROTOCOL, "Sending SSH_CMSG_SESSION_KEY"); if (buffer_add_u8(session->out_buffer, SSH_CMSG_SESSION_KEY) < 0) { goto error; } if (buffer_add_u8(session->out_buffer, SSH_CIPHER_3DES) < 0) { goto error; } if (buffer_add_data(session->out_buffer, session->server_kex.cookie, 8) < 0) { goto error; } enc_session = encrypt_session_key(session, srv, host, server_bits, host_bits); if (enc_session == NULL) { goto error; } bits = string_len(enc_session) * 8 - 7; ssh_log(session, SSH_LOG_PROTOCOL, "%d bits, %zu bytes encrypted session", bits, string_len(enc_session)); bits = htons(bits); /* the encrypted mpint */ if (buffer_add_data(session->out_buffer, &bits, sizeof(u16)) < 0) { goto error; } if (buffer_add_data(session->out_buffer, enc_session->string, string_len(enc_session)) < 0) { goto error; } /* the protocol flags */ if (buffer_add_u32(session->out_buffer, 0) < 0) { goto error; } if (packet_send(session) != SSH_OK) { goto error; } /* we can set encryption */ if (crypt_set_algorithms(session)) { goto error; } session->current_crypto = session->next_crypto; session->next_crypto = NULL; ssh_log(session, SSH_LOG_PROTOCOL, "Waiting for a SSH_SMSG_SUCCESS"); if (packet_wait(session,SSH_SMSG_SUCCESS,1) != SSH_OK) { char buffer[1024] = {0}; snprintf(buffer, sizeof(buffer), "Key exchange failed: %s", ssh_get_error(session)); ssh_set_error(session, SSH_FATAL, "%s",buffer); goto error; } ssh_log(session, SSH_LOG_PROTOCOL, "received SSH_SMSG_SUCCESS\n"); rc = 0; error: string_free(host_mod); string_free(host_exp); string_free(server_mod); string_free(server_exp); string_free(serverkey); string_free(hostkey); publickey_free(srv); publickey_free(host); leave_function(); return rc; }
int ssh_message_auth_interactive_request(ssh_message msg, const char *name, const char *instruction, unsigned int num_prompts, const char **prompts, char *echo) { int r; unsigned int i = 0; ssh_string tmp = NULL; if(name == NULL || instruction == NULL) { return SSH_ERROR; } if(num_prompts > 0 && (prompts == NULL || echo == NULL)) { return SSH_ERROR; } if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_INFO_REQUEST) < 0) { return SSH_ERROR; } /* name */ tmp = ssh_string_from_char(name); if (tmp == NULL) { return SSH_ERROR; } r = buffer_add_ssh_string(msg->session->out_buffer, tmp); ssh_string_free(tmp); if (r < 0) { return SSH_ERROR; } /* instruction */ tmp = ssh_string_from_char(instruction); if (tmp == NULL) { return SSH_ERROR; } r = buffer_add_ssh_string(msg->session->out_buffer, tmp); ssh_string_free(tmp); if (r < 0) { return SSH_ERROR; } /* language tag */ tmp = ssh_string_from_char(""); if (tmp == NULL) { return SSH_ERROR; } r = buffer_add_ssh_string(msg->session->out_buffer, tmp); ssh_string_free(tmp); if (r < 0) { return SSH_ERROR; } /* num prompts */ if (buffer_add_u32(msg->session->out_buffer, ntohl(num_prompts)) < 0) { return SSH_ERROR; } for(i = 0; i < num_prompts; i++) { /* prompt[i] */ tmp = ssh_string_from_char(prompts[i]); if (tmp == NULL) { return SSH_ERROR; } r = buffer_add_ssh_string(msg->session->out_buffer, tmp); ssh_string_free(tmp); if (r < 0) { return SSH_ERROR; } /* echo[i] */ if (buffer_add_u8(msg->session->out_buffer, echo[i]) < 0) { return SSH_ERROR; } } r = packet_send(msg->session); /* fill in the kbdint structure */ if (msg->session->kbdint == NULL) { SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a " "keyboard-interactive response but it " "seems we didn't send the request."); msg->session->kbdint = ssh_kbdint_new(); if (msg->session->kbdint == NULL) { ssh_set_error_oom(msg->session); return SSH_ERROR; } } else { ssh_kbdint_clean(msg->session->kbdint); } msg->session->kbdint->name = strdup(name); if(msg->session->kbdint->name == NULL) { ssh_set_error_oom(msg->session); ssh_kbdint_free(msg->session->kbdint); msg->session->kbdint = NULL; return SSH_PACKET_USED; } msg->session->kbdint->instruction = strdup(instruction); if(msg->session->kbdint->instruction == NULL) { ssh_set_error_oom(msg->session); ssh_kbdint_free(msg->session->kbdint); msg->session->kbdint = NULL; return SSH_PACKET_USED; } msg->session->kbdint->nprompts = num_prompts; if(num_prompts > 0) { msg->session->kbdint->prompts = malloc(num_prompts * sizeof(char *)); if (msg->session->kbdint->prompts == NULL) { msg->session->kbdint->nprompts = 0; ssh_set_error_oom(msg->session); ssh_kbdint_free(msg->session->kbdint); msg->session->kbdint = NULL; return SSH_ERROR; } msg->session->kbdint->echo = malloc(num_prompts * sizeof(unsigned char)); if (msg->session->kbdint->echo == NULL) { ssh_set_error_oom(msg->session); ssh_kbdint_free(msg->session->kbdint); msg->session->kbdint = NULL; return SSH_ERROR; } for (i = 0; i < num_prompts; i++) { msg->session->kbdint->echo[i] = echo[i]; msg->session->kbdint->prompts[i] = strdup(prompts[i]); if (msg->session->kbdint->prompts[i] == NULL) { ssh_set_error_oom(msg->session); msg->session->kbdint->nprompts = i; ssh_kbdint_free(msg->session->kbdint); msg->session->kbdint = NULL; return SSH_PACKET_USED; } } } else { msg->session->kbdint->prompts = NULL; msg->session->kbdint->echo = NULL; } return r; }
static int channel_request(CHANNEL *channel, const char *request, BUFFER *buffer, int reply) { SSH_SESSION *session = channel->session; STRING *req = NULL; int rc = SSH_ERROR; enter_function(); req = string_from_char(request); if (req == NULL) { goto error; } if (buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_REQUEST) < 0 || buffer_add_u32(session->out_buffer, htonl(channel->remote_channel)) < 0 || buffer_add_ssh_string(session->out_buffer, req) < 0 || buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) { goto error; } string_free(req); if (buffer != NULL) { if (buffer_add_data(session->out_buffer, buffer_get(buffer), buffer_get_len(buffer)) < 0) { goto error; } } if (packet_send(session) != SSH_OK) { leave_function(); return rc; } ssh_log(session, SSH_LOG_RARE, "Sent a SSH_MSG_CHANNEL_REQUEST %s", request); if (reply == 0) { leave_function(); return SSH_OK; } rc = packet_wait(session, SSH2_MSG_CHANNEL_SUCCESS, 1); if (rc) { if (session->in_packet.type == SSH2_MSG_CHANNEL_FAILURE) { ssh_log(session, SSH_LOG_PACKET, "%s channel request failed", request); ssh_set_error(session, SSH_REQUEST_DENIED, "Channel request %s failed", request); } else { ssh_log(session, SSH_LOG_RARE, "Received an unexpected %d message", session->in_packet.type); } } else { ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS"); } leave_function(); return rc; error: buffer_free(session->out_buffer); string_free(req); leave_function(); return rc; }