static int send_pubkey_ok(const char *algo, const char *pubkey_data, uint32_t pubkey_len) { struct ssh2_packet *pkt; char *buf, *ptr; uint32_t buflen, bufsz; int res; /* Make sure to allocate a buffer large enough to hold the publickey * data we're sending back. */ bufsz = buflen = pubkey_len + 1024; pkt = sftp_ssh2_packet_create(sftp_pool); buflen = bufsz; ptr = buf = palloc(pkt->pool, bufsz); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_PK_OK); sftp_msg_write_string(&buf, &buflen, algo); sftp_msg_write_data(&buf, &buflen, pubkey_data, pubkey_len, TRUE); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sending publickey OK"); res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt); if (res < 0) { destroy_pool(pkt->pool); return -1; } destroy_pool(pkt->pool); return 0; }
int sftp_service_handle(struct ssh2_packet *pkt) { int res; char *service = NULL; res = read_service_req(pkt, &service); if (res < 0) { destroy_pool(pkt->pool); SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE, NULL); } destroy_pool(pkt->pool); pkt = sftp_ssh2_packet_create(service_pool); res = write_service_accept(pkt, service); if (res < 0) { destroy_pool(pkt->pool); return -1; } res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt); if (res < 0) { destroy_pool(pkt->pool); return -1; } destroy_pool(pkt->pool); return 0; }
int sftp_kbdint_recv_response(pool *p, unsigned int expected_count, unsigned int *rcvd_count, const char ***responses) { register unsigned int i; unsigned char *buf; cmd_rec *cmd; array_header *list; uint32_t buflen, resp_count; struct ssh2_packet *pkt; char mesg_type; int res; if (p == NULL || rcvd_count == NULL || responses == NULL) { errno = EINVAL; return -1; } pkt = sftp_ssh2_packet_create(kbdint_pool); res = sftp_ssh2_packet_read(sftp_conn->rfd, pkt); if (res < 0) { destroy_pool(pkt->pool); return res; } mesg_type = sftp_ssh2_packet_get_mesg_type(pkt); if (mesg_type != SFTP_SSH2_MSG_USER_AUTH_INFO_RESP) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "expecting USER_AUTH_INFO_RESP message, received %s (%d)", sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type); destroy_pool(pkt->pool); errno = EPERM; return -1; } cmd = pr_cmd_alloc(pkt->pool, 2, pstrdup(pkt->pool, "USER_AUTH_INFO_RESP")); cmd->arg = "(data)"; pr_trace_msg(trace_channel, 9, "reading USER_AUTH_INFO_RESP message from client"); buf = pkt->payload; buflen = pkt->payload_len; resp_count = sftp_msg_read_int(pkt->pool, &buf, &buflen); /* Ensure that the number of responses sent by the client is the same * as the number of challenges sent, lest a malicious client attempt to * trick us into allocating too much memory (Bug#3973). */ if (resp_count != expected_count) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "sent %lu %s, but received %lu %s", (unsigned long) expected_count, expected_count != 1 ? "challenges" : "challenge", (unsigned long) resp_count, resp_count != 1 ? "responses" : "response"); destroy_pool(pkt->pool); errno = EPERM; return -1; } if (resp_count > SFTP_KBDINT_MAX_RESPONSES) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "received too many responses (%lu > max %lu), rejecting", (unsigned long) resp_count, (unsigned long) SFTP_KBDINT_MAX_RESPONSES); destroy_pool(pkt->pool); errno = EPERM; return -1; } list = make_array(p, resp_count, sizeof(char *)); for (i = 0; i < resp_count; i++) { char *resp; resp = sftp_msg_read_string(pkt->pool, &buf, &buflen); *((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp)); } *rcvd_count = (unsigned int) resp_count; *responses = ((const char **) list->elts); return 0; }
int sftp_kbdint_send_challenge(const char *user, const char *instruction, unsigned int count, sftp_kbdint_challenge_t *challenges) { register unsigned int i; unsigned char *buf, *ptr; uint32_t buflen, bufsz; struct ssh2_packet *pkt; int res; if (count == 0 || challenges == NULL) { errno = EINVAL; return -1; } pkt = sftp_ssh2_packet_create(kbdint_pool); /* XXX Is this large enough? Too large? */ buflen = bufsz = 3072; buf = ptr = palloc(pkt->pool, bufsz); /* See RFC4256, Section 3.2. */ sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_INFO_REQ); if (user) { sftp_msg_write_string(&buf, &buflen, sftp_utf8_encode_str(pkt->pool, user)); } else { /* Empty user strings are allowed. */ sftp_msg_write_string(&buf, &buflen, ""); } if (instruction) { sftp_msg_write_string(&buf, &buflen, sftp_utf8_encode_str(pkt->pool, instruction)); } else { /* Empty instruction strings are allowed. */ sftp_msg_write_string(&buf, &buflen, ""); } /* Empty language string. */ sftp_msg_write_string(&buf, &buflen, ""); sftp_msg_write_int(&buf, &buflen, count); for (i = 0; i < count; i++) { sftp_msg_write_string(&buf, &buflen, challenges[i].challenge); sftp_msg_write_bool(&buf, &buflen, challenges[i].display_response); } pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); pr_trace_msg(trace_channel, 9, "sending USER_AUTH_INFO_REQ message to client"); res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt); destroy_pool(pkt->pool); return res; }
void sftp_disconnect_send(uint32_t reason, const char *explain, const char *file, int lineno, const char *func) { struct ssh2_packet *pkt; const pr_netaddr_t *remote_addr; const char *lang = "en-US"; unsigned char *buf, *ptr; uint32_t buflen, bufsz; int sockfd; /* Send the client a DISCONNECT mesg. */ pkt = sftp_ssh2_packet_create(sftp_pool); remote_addr = pr_netaddr_get_sess_remote_addr(); buflen = bufsz = 1024; ptr = buf = palloc(pkt->pool, bufsz); if (explain == NULL) { register unsigned int i; for (i = 0; explanations[i].explain; i++) { if (explanations[i].code == reason) { explain = explanations[i].explain; lang = explanations[i].lang; if (lang == NULL) { lang = "en-US"; } break; } } if (explain == NULL) { explain = "Unknown reason"; } } else { lang = "en-US"; } if (strlen(func) > 0) { pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d:%s()]", explain, file, lineno, func); } else { pr_trace_msg(trace_channel, 9, "disconnecting (%s) [at %s:%d]", explain, file, lineno); } sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_DISCONNECT); sftp_msg_write_int(&buf, &buflen, reason); sftp_msg_write_string(&buf, &buflen, explain); sftp_msg_write_string(&buf, &buflen, lang); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "disconnecting %s (%s)", pr_netaddr_get_ipstr(remote_addr), explain); /* If we are called very early in the connection lifetime, then the * sftp_conn variable may not have been set yet, thus the conditional here. */ if (sftp_conn != NULL) { sockfd = sftp_conn->wfd; } else { sockfd = session.c->wfd; } /* Explicitly set a short poll timeout of 5 secs. */ sftp_ssh2_packet_set_poll_timeout(5); if (sftp_ssh2_packet_write(sockfd, pkt) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 12, "error writing DISCONNECT message: %s", strerror(xerrno)); } destroy_pool(pkt->pool); }
int sftp_tap_send_packet(void) { int chance; if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) { pr_trace_msg(trace_channel, 3, "unable to send TAP packet: IGNORE not supported by client"); return 0; } if (curr_policy.chance_max == 0) { /* The "none" policy is in effect; nothing to do. */ return 0; } /* Calculate our odds of sending a tap packet, based on the configured * policy. */ if (curr_policy.chance_max != 1) { chance = (int) (rand() / (RAND_MAX / curr_policy.chance_max + 1)); } else { chance = 1; } if (chance == curr_policy.chance) { unsigned char *rand_data; char *buf, *ptr; uint32_t bufsz, buflen, rand_datalen; struct ssh2_packet *pkt; unsigned int max_datalen = 8192; if (curr_policy.max_datalen) { max_datalen = curr_policy.max_datalen; } rand_datalen = (uint32_t) (curr_policy.min_datalen + rand() / (RAND_MAX / (max_datalen - curr_policy.min_datalen) + 1)); pr_trace_msg(trace_channel, 20, "sending random SSH2_MSG_IGNORE message " "(%lu bytes) based on '%s' TAP policy", (unsigned long) rand_datalen, curr_policy.policy); pkt = sftp_ssh2_packet_create(tap_pool); bufsz = buflen = rand_datalen + 32; ptr = buf = palloc(pkt->pool, bufsz); rand_data = palloc(pkt->pool, rand_datalen); /* We don't need cryptographically secure random bytes here, just * pseudo-random data. */ RAND_pseudo_bytes(rand_data, rand_datalen); sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_IGNORE); sftp_msg_write_data(&buf, &buflen, (char *) rand_data, rand_datalen, TRUE); pkt->payload = ptr; pkt->payload_len = (bufsz - buflen); if (sftp_ssh2_packet_send(sftp_conn->wfd, pkt) < 0) { int xerrno = errno; pr_trace_msg(trace_channel, 12, "error writing TAP packet: %s", strerror(xerrno)); } destroy_pool(pkt->pool); } return 0; }