void snmp_stacktrace_log(void) { #if defined(HAVE_EXECINFO_H) && \ defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS) void *trace[PR_TUNABLE_CALLER_DEPTH]; char **strings; size_t tracesz; (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "-----BEGIN STACK TRACE-----"); tracesz = backtrace(trace, PR_TUNABLE_CALLER_DEPTH); strings = backtrace_symbols(trace, tracesz); if (strings != NULL) { register unsigned int i; for (i = 1; i < tracesz; i++) { (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "[%u] %s", i-1, strings[i]); } /* Prevent memory leaks. */ free(strings); } else { (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "error obtaining stacktrace symbols: %s", strerror(errno)); } (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "-----END STACK TRACE-----"); #endif }
static int forward_handle_pass_passthru(cmd_rec *cmd, struct proxy_session *proxy_sess, int *successful) { int res, xerrno; pr_response_t *resp; unsigned int resp_nlines = 0; res = proxy_ftp_ctrl_send_cmd(cmd->tmp_pool, proxy_sess->backend_ctrl_conn, cmd); if (res < 0) { xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error sending %s to backend: %s", (char *) cmd->argv[0], strerror(xerrno)); errno = xerrno; return -1; } resp = proxy_ftp_ctrl_recv_resp(cmd->tmp_pool, proxy_sess->backend_ctrl_conn, &resp_nlines); if (resp == NULL) { xerrno = errno; (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "error receiving %s response from backend: %s", (char *) cmd->argv[0], strerror(xerrno)); /* If we receive an EPERM here, it is probably because the backend * closed its control connection, yielding an EOF. To better indicate * this situation, propagate the error using EPIPE. */ if (xerrno == EPERM) { xerrno = EPIPE; } errno = xerrno; return -1; } /* XXX What about other response codes for PASS? */ if (resp->num[0] == '2') { *successful = TRUE; proxy_sess_state |= PROXY_SESS_STATE_BACKEND_AUTHENTICATED; } res = proxy_ftp_ctrl_send_resp(cmd->tmp_pool, proxy_sess->frontend_ctrl_conn, resp, resp_nlines); if (res < 0) { xerrno = errno; pr_response_block(TRUE); errno = xerrno; return -1; } return 1; }
static int filestore_verify_host_key(sftp_keystore_t *store, pool *p, const char *user, const char *host_fqdn, const char *host_user, unsigned char *key_data, uint32_t key_len) { struct filestore_key *key = NULL; struct filestore_data *store_data = store->keystore_data; int res = -1; if (!store_data->path) { errno = EPERM; return -1; } /* XXX Note that this will scan the file from the beginning, each time. * There's room for improvement; perhaps mmap() the file into memory? */ key = filestore_get_key(store, p); while (key) { int ok; pr_signals_handle(); ok = sftp_keys_compare_keys(p, key_data, key_len, key->key_data, key->key_datalen); if (ok != TRUE) { if (ok == -1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error comparing keys from '%s': %s", store_data->path, strerror(errno)); } } else { /* XXX Verify that the user and the host_user match?? */ res = 0; break; } key = filestore_get_key(store, p); } if (res == 0) { pr_trace_msg(trace_channel, 10, "found matching public key for host '%s' " "in '%s'", host_fqdn, store_data->path); } if (pr_fsio_lseek(store_data->fh, 0, SEEK_SET) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error seeking to start of '%s': %s", store_data->path, strerror(errno)); return -1; } store_data->lineno = 0; return res; }
static int counter_get_sem(pr_fh_t *fh, const char *path) { int semid; key_t key; /* Obtain a key for this path. */ key = counter_get_key(path); if (key == (key_t) -1) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "unable to get key for '%s': %s", path, strerror(errno)); return -1; } /* Try first using IPC_CREAT|IPC_EXCL, to check if there is an existing * semaphore set for this key. If there is, try again, using a flag of * zero. */ semid = semget(key, COUNTER_NSEMS, IPC_CREAT|IPC_EXCL|0666); if (semid < 0) { if (errno == EEXIST) { semid = semget(key, 0, 0); } else { return -1; } } else { /* Set the values of the newly created semaphore to the configured * CounterMaxReaders and CounterMaxWriters. */ if (counter_set_readers(semid) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error setting readers (semaphore ID %d): %s", semid, strerror(errno)); } if (counter_set_writers(semid) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error setting writers (semaphore ID %d): %s", semid, strerror(errno)); } if (counter_set_procs(semid) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error setting procs (semaphore ID %d): %s", semid, strerror(errno)); } /* Record the ID of the created semaphore in the CounterFile. */ if (counter_file_add_id(fh, semid) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error recording semaphore (semaphore ID %d) in CounterFile '%s': %s", semid, fh->fh_path, strerror(errno)); } } return semid; }
int sftp_cipher_write_data(struct ssh2_packet *pkt, unsigned char *buf, size_t *buflen) { struct sftp_cipher *cipher; EVP_CIPHER_CTX *cipher_ctx; cipher = &(write_ciphers[write_cipher_idx]); cipher_ctx = write_ctxs[write_cipher_idx]; if (cipher->key) { int res; unsigned char *data, *ptr; uint32_t datalen, datasz = sizeof(uint32_t) + pkt->packet_len; datalen = datasz; ptr = data = palloc(pkt->pool, datasz); sftp_msg_write_int(&data, &datalen, pkt->packet_len); sftp_msg_write_byte(&data, &datalen, pkt->padding_len); sftp_msg_write_data(&data, &datalen, pkt->payload, pkt->payload_len, FALSE); sftp_msg_write_data(&data, &datalen, pkt->padding, pkt->padding_len, FALSE); res = EVP_Cipher(cipher_ctx, buf, ptr, (datasz - datalen)); if (res != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error encrypting %s data for client: %s", cipher->algo, sftp_crypto_get_errors()); errno = EIO; return -1; } *buflen = (datasz - datalen); #ifdef SFTP_DEBUG_PACKET { unsigned int i; (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "encrypted packet data (len %lu):", (unsigned long) *buflen); for (i = 0; i < *buflen;) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, " %02x%02x %02x%02x %02x%02x %02x%02x", ((unsigned char *) buf)[i], ((unsigned char *) buf)[i+1], ((unsigned char *) buf)[i+2], ((unsigned char *) buf)[i+3], ((unsigned char *) buf)[i+4], ((unsigned char *) buf)[i+5], ((unsigned char *) buf)[i+6], ((unsigned char *) buf)[i+7]); i += 8; } } #endif return 0; } *buflen = 0; return 0; }
int proxy_forward_sess_init(pool *p, const char *tables_dir, struct proxy_session *proxy_sess) { config_rec *c; int allowed = FALSE; void *enabled = NULL; /* By default, only allow connections from RFC1918 addresses to use * forward proxying. Otherwise, it must be from an explicitly allowed * connection class, via the class notes. */ if (session.conn_class != NULL) { enabled = pr_table_get(session.conn_class->cls_notes, PROXY_FORWARD_ENABLED_NOTE, NULL); } if (enabled != NULL) { allowed = *((int *) enabled); if (allowed == FALSE) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "forward proxying not allowed from client address %s in <Class %s> " "(see ProxyForwardEnabled)", pr_netaddr_get_ipstr(session.c->remote_addr), session.conn_class->cls_name); } } else { if (pr_netaddr_is_rfc1918(session.c->remote_addr) == TRUE) { allowed = TRUE; } else { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "forward proxying not allowed from non-RFC1918 client address %s", pr_netaddr_get_ipstr(session.c->remote_addr)); } } if (allowed == FALSE) { errno = EPERM; return -1; } c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardMethod", FALSE); if (c != NULL) { proxy_method = *((int *) c->argv[0]); } c = find_config(main_server->conf, CONF_PARAM, "ProxyRetryCount", FALSE); if (c != NULL) { forward_retry_count = *((int *) c->argv[0]); } return 0; }
int sftp_cipher_read_data(pool *p, unsigned char *data, uint32_t data_len, unsigned char **buf, uint32_t *buflen) { struct sftp_cipher *cipher; EVP_CIPHER_CTX *cipher_ctx; size_t cipher_blocksz; cipher = &(read_ciphers[read_cipher_idx]); cipher_ctx = read_ctxs[read_cipher_idx]; cipher_blocksz = cipher_blockszs[read_cipher_idx]; if (cipher->key) { int res; unsigned char *ptr = NULL; size_t bufsz; if (*buflen % cipher_blocksz != 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "bad input length for decryption (%u bytes, %u block size)", *buflen, (unsigned int) cipher_blocksz); return -1; } if (*buf == NULL) { /* Allocate a buffer that's large enough. */ bufsz = (data_len + cipher_blocksz - 1); ptr = palloc(p, bufsz); } else { ptr = *buf; } res = EVP_Cipher(cipher_ctx, ptr, data, data_len); if (res != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error decrypting %s data from client: %s", cipher->algo, sftp_crypto_get_errors()); return -1; } *buflen = data_len; *buf = ptr; return 0; } *buf = data; *buflen = data_len; return 0; }
MODRET counter_writer_done(cmd_rec *cmd) { pr_fh_t *fh; if (counter_engine == FALSE) { return PR_DECLINED(cmd); } if (!(counter_pending & COUNTER_HAVE_WRITER)) { return PR_DECLINED(cmd); } fh = counter_get_fh(cmd->tmp_pool, counter_curr_path); if (fh == NULL) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "%s: no CounterFile found for path '%s'", (char *) cmd->argv[0], counter_curr_path); /* No CounterFile configured/available for this path. */ return PR_DECLINED(cmd); } if (counter_curr_semid == -1) { counter_curr_semid = counter_get_sem(fh, counter_curr_path); if (counter_curr_semid < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "unable to get semaphore for '%s': %s", counter_curr_path, strerror(errno)); return PR_DECLINED(cmd); } } if (counter_remove_writer(fh, counter_curr_semid) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error removing writer for '%s': %s", counter_curr_path, strerror(errno)); } else { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "removed writer counter for '%s' (semaphore ID %d)", counter_curr_path, counter_curr_semid); counter_curr_path = NULL; counter_curr_semid = -1; counter_pending &= ~COUNTER_HAVE_WRITER; } return PR_DECLINED(cmd); }
int proxy_session_check_password(pool *p, const char *user, const char *passwd) { int res; res = pr_auth_authenticate(p, user, passwd); switch (res) { case PR_AUTH_OK: break; case PR_AUTH_NOPWD: (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "password authentication for user '%s' failed: No such user", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found", user); return -1; case PR_AUTH_BADPWD: (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "password authentication for user '%s' failed: Incorrect password", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password", user); return -1; case PR_AUTH_AGEPWD: (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "password authentication for user '%s' failed: Password expired", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired", user); return -1; case PR_AUTH_DISABLEDPWD: (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "password authentication for user '%s' failed: Account disabled", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled", user); return -1; default: (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unknown authentication value (%d), returning error", res); return -1; } return 0; }
int sftp_compress_init_read(int flags) { struct sftp_compress *comp; z_stream *stream; switch_read_compress(flags); comp = &(read_compresses[read_comp_idx]); stream = &(read_streams[read_comp_idx]); if (comp->use_zlib == flags && !comp->stream_ready) { int zres; zres = inflateInit(stream); if (zres != Z_OK) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error preparing decompression stream (%d)", zres); } pr_event_generate("mod_sftp.ssh.client-compression", NULL); comp->stream_ready = TRUE; } return 0; }
static int read_service_req(struct ssh2_packet *pkt, char **service) { unsigned char *buf; char *service_name; uint32_t buflen; cmd_rec *cmd; buf = pkt->payload; buflen = pkt->payload_len; service_name = sftp_msg_read_string(pkt->pool, &buf, &buflen); pr_trace_msg(trace_channel, 10, "'%s' service requested", service_name); cmd = pr_cmd_alloc(pkt->pool, 1, pstrdup(pkt->pool, "SERVICE_REQUEST")); cmd->arg = service_name; cmd->cmd_class = CL_MISC|CL_SSH; if (strncmp(service_name, "ssh-userauth", 13) == 0 || strncmp(service_name, "ssh-connection", 14) == 0) { if (service) *service = pstrdup(service_pool, service_name); pr_cmd_dispatch_phase(cmd, LOG_CMD, 0); return 0; } (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "client requested unsupported '%s' service", service_name); pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0); return -1; }
int vroot_fsio_rmdir(pr_fs_t *fs, const char *path) { char vpath[PR_TUNABLE_PATH_MAX + 1]; if (session.curr_phase == LOG_CMD || session.curr_phase == LOG_CMD_ERR || (session.sf_flags & SF_ABORT) || vroot_path_have_base() == FALSE) { /* NOTE: once stackable FS modules are supported, have this fall through * to the next module in the stack. */ return rmdir(path); } /* Do not allow deleting of aliased files/directories; the aliases may only * exist for this user/group. */ if (vroot_path_lookup(NULL, vpath, sizeof(vpath)-1, path, VROOT_LOOKUP_FL_NO_ALIAS, NULL) < 0) { return -1; } if (vroot_alias_exists(vpath) == TRUE) { (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION, "denying delete of '%s' because it is a VRootAlias", vpath); errno = EACCES; return -1; } if (vroot_path_lookup(NULL, vpath, sizeof(vpath)-1, path, 0, NULL) < 0) { return -1; } return rmdir(vpath); }
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; }
static void log_failure_mkjson(void *json, const char *field_name, size_t field_namelen, unsigned int field_type, const void *field_value) { JsonNode *field = NULL; switch (field_type) { case LOG_FAILURE_FIELD_TYPE_STRING: field = json_mkstring((const char *) field_value); break; case LOG_FAILURE_FIELD_TYPE_NUMBER: field = json_mknumber(*((double *) field_value)); break; case LOG_FAILURE_FIELD_TYPE_BOOLEAN: field = json_mkbool(*((bool *) field_value)); break; default: (void) pr_log_writefile(log_failure_logfd, MOD_LOG_FAILURE_VERSION, "unsupported field type: %u", field_type); } if (field != NULL) { json_append_member(json, field_name, field); } }
int proxy_db_init(pool *p) { const char *version; if (p == NULL) { errno = EINVAL; return -1; } if (db_pool != NULL) { return 0; } /* Check that the SQLite headers used match the version of the SQLite * library used. * * For now, we only log if there is a difference. */ version = sqlite3_libversion(); if (strcmp(version, SQLITE_VERSION) != 0) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "compiled using SQLite version '%s' headers, but linked to " "SQLite version '%s' library", SQLITE_VERSION, version); } pr_trace_msg(trace_channel, 9, "using SQLite %s", version); db_pool = make_sub_pool(p); pr_pool_tag(db_pool, "Proxy Database Pool"); return 0; }
static void switch_read_compress(int flags) { struct sftp_compress *comp; z_stream *stream; comp = &(read_compresses[read_comp_idx]); stream = &(read_streams[read_comp_idx]); /* First we can free up the read stream, kept from rekeying. */ if (comp->use_zlib == flags && comp->stream_ready) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "done decompressing data: decompressed %" PR_LU " bytes to %" PR_LU " bytes of data (%.2f)", (pr_off_t) stream->total_in, (pr_off_t) stream->total_out, stream->total_in == 0 ? 0.0 : (float) stream->total_out / stream->total_in); inflateEnd(stream); comp->use_zlib = FALSE; comp->stream_ready = FALSE; /* Now we can switch the index. */ if (read_comp_idx == 1) { read_comp_idx = 0; return; } read_comp_idx = 1; } }
int sftp_compress_init_write(int flags) { struct sftp_compress *comp; z_stream *stream; switch_write_compress(flags); comp = &(write_compresses[write_comp_idx]); stream = &(write_streams[write_comp_idx]); if (comp->use_zlib == flags && !comp->stream_ready) { int zres; zres = deflateInit(stream, Z_DEFAULT_COMPRESSION); if (zres != Z_OK) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error preparing compression stream (%d)", zres); } pr_event_generate("mod_sftp.ssh.server-compression", NULL); comp->stream_ready = TRUE; } return 0; }
int sftp_mac_set_read_key(pool *p, const EVP_MD *hash, const BIGNUM *k, const char *h, uint32_t hlen) { const unsigned char *id = NULL; char *buf, *ptr; uint32_t buflen, bufsz, id_len; char letter; size_t blocksz; struct sftp_mac *mac; HMAC_CTX *mac_ctx; switch_read_mac(); mac = &(read_macs[read_mac_idx]); mac_ctx = &(read_ctxs[read_mac_idx]); bufsz = buflen = 1024; ptr = buf = sftp_msg_getbuf(p, bufsz); /* Need to use SSH2-style format of K for the key. */ sftp_msg_write_mpint(&buf, &buflen, k); id_len = sftp_session_get_id(&id); /* HASH(K || H || "E" || session_id) */ letter = 'E'; set_mac_key(mac, hash, ptr, (bufsz - buflen), h, hlen, &letter, id, id_len); #if OPENSSL_VERSION_NUMBER > 0x000907000L HMAC_CTX_init(mac_ctx); # if OPENSSL_VERSION_NUMBER >= 0x10000001L if (HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL) != 1) { pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error initializing HMAC: %s", sftp_crypto_get_errors()); errno = EPERM; return -1; } # else HMAC_Init_ex(mac_ctx, mac->key, mac->key_len, mac->digest, NULL); # endif /* OpenSSL-1.0.0 and later */ #else /* Reset the HMAC context. */ HMAC_Init(mac_ctx, NULL, 0, NULL); HMAC_Init(mac_ctx, mac->key, mac->key_len, mac->digest); #endif if (mac->mac_len == 0) { blocksz = EVP_MD_size(mac->digest); } else { blocksz = mac->mac_len; } pr_memscrub(ptr, bufsz); sftp_mac_set_block_size(blocksz); return 0; }
struct dirent *vroot_fsio_readdir(pr_fs_t *fs, void *dirh) { struct dirent *dent = NULL; next_dent: dent = readdir((DIR *) dirh); if (vroot_dir_aliases != NULL) { char **elts; elts = vroot_dir_aliases->elts; if (dent != NULL) { register unsigned int i; /* If this dent has the same name as an alias, the alias wins. * This is similar to a mounted filesystem, which hides any directories * underneath the mount point for the duration of the mount. */ /* Yes, this is a linear scan; it assumes that the number of configured * aliases for a site will be relatively few. Should this assumption * not be borne out by reality, then we should switch to using a * table, not an array_header, for storing the aliased paths. */ for (i = 0; i < vroot_dir_aliases->nelts; i++) { if (strcmp(dent->d_name, elts[i]) == 0) { (void) pr_log_writefile(vroot_logfd, MOD_VROOT_VERSION, "skipping directory entry '%s', as it is aliased", dent->d_name); goto next_dent; } } } else { if (vroot_dir_idx < 0 || vroot_dir_idx >= vroot_dir_aliases->nelts) { return NULL; } memset(vroot_dent, 0, vroot_dentsz); if (vroot_dent_namesz == 0) { sstrncpy(vroot_dent->d_name, elts[vroot_dir_idx++], sizeof(vroot_dent->d_name)); } else { sstrncpy(vroot_dent->d_name, elts[vroot_dir_idx++], vroot_dent_namesz); } return vroot_dent; } } return dent; }
static int sftppam_sess_init(void) { config_rec *c; c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMEngine", FALSE); if (c != NULL) { int engine; engine = *((int *) c->argv[0]); if (engine == FALSE) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION, "disabled by SFTPPAMEngine setting, unregistered 'pam' driver"); sftp_kbdint_unregister_driver("pam"); return 0; } } /* To preserve the principle of least surprise, also check for the AuthPAM * directive. */ c = find_config(main_server->conf, CONF_PARAM, "AuthPAM", FALSE); if (c != NULL) { unsigned char auth_pam; auth_pam = *((unsigned char *) c->argv[0]); if (auth_pam == FALSE) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_PAM_VERSION, "disabled by AuthPAM setting, unregistered 'pam' driver"); sftp_kbdint_unregister_driver("pam"); return 0; } } c = find_config(main_server->conf, CONF_PARAM, "SFTPPAMServiceName", FALSE); if (c != NULL) { sftppam_service = c->argv[0]; } pr_trace_msg(trace_channel, 8, "using PAM service name '%s'", sftppam_service); return 0; }
static array_header *counter_file_read(pr_fh_t *fh) { char buf[PR_TUNABLE_BUFFER_SIZE]; array_header *ids = make_array(counter_pool, 0, sizeof(int)); /* Read the list of IDs in the CounterFile into an array. */ if (counter_file_lock(fh, LOCK_SH) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error read-locking CounterFile '%s': %s", fh->fh_path, strerror(errno)); } if (pr_fsio_lseek(fh, 0, SEEK_SET) < 0) { int xerrno = errno; counter_file_lock(fh, LOCK_UN); errno = xerrno; return NULL; } memset(buf, '\0', sizeof(buf)); while (pr_fsio_gets(buf, sizeof(buf), fh) != NULL) { int id; pr_signals_handle(); id = atoi(buf); if (id < 0) { continue; } *((int *) push_array(ids)) = id; } if (counter_file_lock(fh, LOCK_UN) < 0) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "error unlocking CounterFile '%s': %s", fh->fh_path, strerror(errno)); } return ids; }
static int forward_dst_filter(pool *p, const char *hostport) { #ifdef PR_USE_REGEX config_rec *c; pr_regex_t *pre; int negated = FALSE, res; c = find_config(main_server->conf, CONF_PARAM, "ProxyForwardTo", FALSE); if (c == NULL) { return 0; } pre = c->argv[0]; negated = *((int *) c->argv[1]); res = pr_regexp_exec(pre, hostport, 0, NULL, 0, 0, 0); if (res == 0) { /* Pattern matched */ if (negated == TRUE) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "host/port '%.100s' matched ProxyForwardTo !%s, rejecting", hostport, pr_regexp_get_pattern(pre)); errno = EPERM; return -1; } } else { /* Pattern NOT matched */ if (negated == FALSE) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "host/port '%.100s' did not match ProxyForwardTo %s, rejecting", hostport, pr_regexp_get_pattern(pre)); errno = EPERM; return -1; } } #endif /* PR_USE_REGEX */ return 0; }
int sftp_tap_set_policy(const char *policy) { register unsigned int i; if (tap_pool) { /* Special case: IFF the existing policy is 'none' AND the given * policy is 'rogaway', just return. The 'none' policy must have been * explicitly configured, and it should override the automatic use of * the 'rogaway' policy. */ if (strncmp(curr_policy.policy, "none", 5) == 0 && strncasecmp(policy, "rogaway", 8) == 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "'none' traffic policy explicitly configured, ignoring '%s' policy", policy); return 0; } destroy_pool(tap_pool); if (tap_timerno > 0) { pr_timer_remove(tap_timerno, &sftp_module); tap_timerno = -1; } } tap_pool = make_sub_pool(sftp_pool); pr_pool_tag(tap_pool, "SFTP TAP Pool"); memset(&curr_policy, 0, sizeof(struct sftp_tap_policy)); for (i = 0; tap_policies[i].policy; i++) { if (strcasecmp(tap_policies[i].policy, policy) == 0) { copy_policy(&curr_policy, &(tap_policies[i])); set_policy_chance(&curr_policy); set_policy_timer(&curr_policy); return 0; } } errno = ENOENT; return -1; }
static void switch_read_cipher(void) { /* First, clear the context of the existing read cipher, if any. */ if (read_ciphers[read_cipher_idx].key) { clear_cipher(&(read_ciphers[read_cipher_idx])); if (EVP_CIPHER_CTX_cleanup(read_ctxs[read_cipher_idx]) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error clearing cipher context: %s", sftp_crypto_get_errors()); } cipher_blockszs[read_cipher_idx] = SFTP_CIPHER_DEFAULT_BLOCK_SZ; /* Now we can switch the index. */ if (read_cipher_idx == 1) { read_cipher_idx = 0; return; } read_cipher_idx = 1; } }
/* If the chosen cipher requires that we discard some of the initial bytes of * the cipher stream, then do so. (This is mostly for any RC4 ciphers.) */ static int set_cipher_discarded(struct sftp_cipher *cipher, EVP_CIPHER_CTX *cipher_ctx) { unsigned char *garbage_in, *garbage_out; if (cipher->discard_len == 0) { return 0; } garbage_in = malloc(cipher->discard_len); if (garbage_in == NULL) { pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!"); _exit(1); } garbage_out = malloc(cipher->discard_len); if (garbage_out == NULL) { pr_log_pri(PR_LOG_ALERT, MOD_SFTP_VERSION ": Out of memory!"); free(garbage_in); _exit(1); } if (EVP_Cipher(cipher_ctx, garbage_out, garbage_in, cipher->discard_len) != 1) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error ciphering discard data: %s", sftp_crypto_get_errors()); free(garbage_in); pr_memscrub(garbage_out, cipher->discard_len); free(garbage_out); return -1; } free(garbage_in); pr_memscrub(garbage_out, cipher->discard_len); free(garbage_out); return 0; }
int proxy_conn_connect_timeout_cb(CALLBACK_FRAME) { struct proxy_session *proxy_sess; pr_netaddr_t *server_addr; proxy_sess = pr_table_get(session.notes, "mod_proxy.proxy-session", NULL); server_addr = pr_table_get(session.notes, "mod_proxy.proxy-connect-address", NULL); (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "timed out connecting to %s:%d after %d %s", pr_netaddr_get_ipstr(server_addr), ntohs(pr_netaddr_get_port(server_addr)), proxy_sess->connect_timeout, proxy_sess->connect_timeout != 1 ? "seconds" : "second"); pr_event_generate("mod_proxy.timeout-connect", NULL); pr_log_pri(PR_LOG_NOTICE, "%s", "Connect timed out, disconnected"); pr_session_disconnect(&proxy_module, PR_SESS_DISCONNECT_TIMEOUT, "ProxyTimeoutConnect"); /* Do not restart the timer (should never be reached). */ return 0; }
int sftp_auth_password(struct ssh2_packet *pkt, cmd_rec *pass_cmd, const char *orig_user, const char *user, const char *service, unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) { const char *cipher_algo, *mac_algo; char *passwd; int have_new_passwd, res; struct passwd *pw; cipher_algo = sftp_cipher_get_read_algo(); mac_algo = sftp_mac_get_read_algo(); if (strncmp(cipher_algo, "none", 5) == 0 || strncmp(mac_algo, "none", 5) == 0) { if (sftp_opts & SFTP_OPT_ALLOW_INSECURE_LOGIN) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "WARNING: cipher algorithm '%s' or MAC algorithm '%s' INSECURE for " "password authentication (SFTPOption AllowInsecureLogin in effect)", cipher_algo, mac_algo); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "cipher algorithm '%s' or MAC algorithm '%s' unacceptable for " "password authentication, denying password authentication request", cipher_algo, mac_algo); *send_userauth_fail = TRUE; errno = EPERM; return 0; } } /* XXX We currently don't do anything with this. */ have_new_passwd = sftp_msg_read_bool(pkt->pool, buf, buflen); if (have_new_passwd) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "%s", "client says they have provided a new password; this functionality " "is not currently supported"); } passwd = sftp_msg_read_string(pkt->pool, buf, buflen); passwd = sftp_utf8_decode_str(pkt->pool, passwd); pass_cmd->arg = passwd; if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication request for user '%s' blocked by '%s' handler", orig_user, (char *) pass_cmd->argv[0]); pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0); pr_memscrub(passwd, strlen(passwd)); *send_userauth_fail = TRUE; errno = EPERM; return 0; } pw = pr_auth_getpwnam(pkt->pool, user); if (pw == NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "no account for user '%s' found", user); pr_log_auth(PR_LOG_NOTICE, "USER %s: no such user found from %s [%s] to %s:%d", user, session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr), pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port); pr_memscrub(passwd, strlen(passwd)); *send_userauth_fail = TRUE; errno = ENOENT; return 0; } res = pr_auth_authenticate(pkt->pool, user, passwd); pr_memscrub(passwd, strlen(passwd)); switch (res) { case PR_AUTH_OK: break; case PR_AUTH_NOPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: No such user", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): No such user found", user); *send_userauth_fail = TRUE; errno = ENOENT; return 0; case PR_AUTH_BADPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Incorrect password", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Incorrect password", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; case PR_AUTH_AGEPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Password expired", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Password expired", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; case PR_AUTH_DISABLEDPWD: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "password authentication for user '%s' failed: Account disabled", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): Account disabled", user); *send_userauth_fail = TRUE; errno = EINVAL; return 0; default: (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unknown authentication value (%d), returning error", res); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } return 1; }
/* This getline() function is quite similar to pr_fsio_getline(), except * that it a) enforces the 72-byte max line length from RFC4716, and b) * properly handles lines ending with CR, LF, or CRLF. * * Technically it allows one more byte than necessary, since the worst case * is 74 bytes (72 + CRLF); this also means 73 + CR or 73 + LF. The extra * byte is for the terminating NUL. */ static char *filestore_getline(sftp_keystore_t *store, pool *p) { char linebuf[75], *line = "", *res; struct filestore_data *store_data = store->keystore_data; while (TRUE) { size_t linelen; pr_signals_handle(); memset(&linebuf, '\0', sizeof(linebuf)); res = pr_fsio_gets(linebuf, sizeof(linebuf) - 1, store_data->fh); if (res == NULL) { if (errno == EINTR) { continue; } pr_trace_msg(trace_channel, 10, "reached end of '%s', no matching " "key found", store_data->path); errno = EOF; return NULL; } linelen = strlen(linebuf); if (linelen >= 1) { if (linebuf[linelen - 1] == '\r' || linebuf[linelen - 1] == '\n') { char *tmp; unsigned int header_taglen, header_valuelen; int have_line_continuation = FALSE; store_data->lineno++; linebuf[linelen - 1] = '\0'; line = pstrcat(p, line, linebuf, NULL); if (line[strlen(line) - 1] == '\\') { have_line_continuation = TRUE; line[strlen(line) - 1] = '\0'; } tmp = strchr(line, ':'); if (tmp == NULL) { return line; } /* We have a header. Make sure the header tag is not longer than * the specified length of 64 bytes, and that the header value is * not longer than 1024 bytes. */ header_taglen = tmp - line; if (header_taglen > 64) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "header tag too long (%u) on line %u of '%s'", header_taglen, store_data->lineno, store_data->path); errno = EINVAL; return NULL; } /* Header value starts at 2 after the ':' (one for the mandatory * space character. */ header_valuelen = strlen(line) - (header_taglen + 2); if (header_valuelen > 1024) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "header value too long (%u) on line %u of '%s'", header_valuelen, store_data->lineno, store_data->path); errno = EINVAL; return NULL; } if (!have_line_continuation) { return line; } continue; } else if (linelen >= 2 && linebuf[linelen - 2] == '\r' && linebuf[linelen - 1] == '\n') { char *tmp; unsigned int header_taglen, header_valuelen; int have_line_continuation = FALSE; store_data->lineno++; linebuf[linelen - 2] = '\0'; linebuf[linelen - 1] = '\0'; line = pstrcat(p, line, linebuf, NULL); if (line[strlen(line) - 1] == '\\') { have_line_continuation = TRUE; line[strlen(line) - 1] = '\0'; } tmp = strchr(line, ':'); if (tmp == NULL) { return line; } /* We have a header. Make sure the header tag is not longer than * the specified length of 64 bytes, and that the header value is * not longer than 1024 bytes. */ header_taglen = tmp - line; if (header_taglen > 64) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "header tag too long (%u) on line %u of '%s'", header_taglen, store_data->lineno, store_data->path); errno = EINVAL; return NULL; } /* Header value starts at 2 after the ':' (one for the mandatory * space character. */ header_valuelen = strlen(line) - (header_taglen + 2); if (header_valuelen > 1024) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "header value too long (%u) on line %u of '%s'", header_valuelen, store_data->lineno, store_data->path); errno = EINVAL; return NULL; } if (!have_line_continuation) { return line; } continue; } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "line too long (%lu) on line %u of '%s'", (unsigned long) linelen, store_data->lineno, store_data->path); (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "Make sure that '%s' is a RFC4716 formatted key", store_data->path); errno = EINVAL; break; } } } return NULL; }
int sftp_auth_hostbased(struct ssh2_packet *pkt, cmd_rec *pass_cmd, const char *orig_user, const char *user, const char *service, unsigned char **buf, uint32_t *buflen, int *send_userauth_fail) { struct passwd *pw; char *hostkey_algo, *host_fqdn, *host_user, *host_user_utf8; const char *fp = NULL; unsigned char *hostkey_data, *signature_data; unsigned char *buf2, *ptr2; const unsigned char *id; uint32_t buflen2, bufsz2, hostkey_datalen, id_len, signature_len; enum sftp_key_type_e pubkey_type; if (pr_cmd_dispatch_phase(pass_cmd, PRE_CMD, 0) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication request for user '%s' blocked by '%s' handler", orig_user, (char *) pass_cmd->argv[0]); pr_cmd_dispatch_phase(pass_cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(pass_cmd, LOG_CMD_ERR, 0); *send_userauth_fail = TRUE; errno = EPERM; return 0; } hostkey_algo = sftp_msg_read_string(pkt->pool, buf, buflen); if (hostkey_algo == NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "missing required host key algorithm, rejecting request"); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } hostkey_datalen = sftp_msg_read_int(pkt->pool, buf, buflen); hostkey_data = sftp_msg_read_data(pkt->pool, buf, buflen, hostkey_datalen); host_fqdn = sftp_msg_read_string(pkt->pool, buf, buflen); host_user_utf8 = sftp_msg_read_string(pkt->pool, buf, buflen); host_user = sftp_utf8_decode_str(pkt->pool, host_user_utf8); signature_len = sftp_msg_read_int(pkt->pool, buf, buflen); signature_data = sftp_msg_read_data(pkt->pool, buf, buflen, signature_len); pr_trace_msg(trace_channel, 9, "client sent '%s' host key, FQDN %s, and remote user '%s'", hostkey_algo, host_fqdn, host_user); if (strncmp(hostkey_algo, "ssh-rsa", 8) == 0) { pubkey_type = SFTP_KEY_RSA; } else if (strncmp(hostkey_algo, "ssh-dss", 8) == 0) { pubkey_type = SFTP_KEY_DSA; #ifdef PR_USE_OPENSSL_ECC } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_256; } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_384; } else if (strncmp(hostkey_algo, "ecdsa-sha2-nistp256", 20) == 0) { pubkey_type = SFTP_KEY_ECDSA_521; #endif /* PR_USE_OPENSSL_ECC */ /* XXX Need to support X509v3 certs here */ } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unsupported host key algorithm '%s' requested, rejecting request", hostkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } if (sftp_keys_verify_pubkey_type(pkt->pool, hostkey_data, hostkey_datalen, pubkey_type) != TRUE) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "unable to verify that given host key matches given '%s' algorithm", hostkey_algo); *send_userauth_fail = TRUE; errno = EINVAL; return 0; } #ifdef OPENSSL_FIPS if (FIPS_mode()) { fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen, SFTP_KEYS_FP_DIGEST_SHA1); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key SHA1 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key SHA1 fingerprint: %s", strerror(errno)); } } else { #endif /* OPENSSL_FIPS */ fp = sftp_keys_get_fingerprint(pkt->pool, hostkey_data, hostkey_datalen, SFTP_KEYS_FP_DIGEST_MD5); if (fp != NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "public key MD5 fingerprint: %s", fp); } else { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "error obtaining public key MD5 fingerprint: %s", strerror(errno)); } #ifdef OPENSSL_FIPS } #endif /* OPENSSL_FIPS */ pw = pr_auth_getpwnam(pkt->pool, user); if (pw == NULL) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "no account for user '%s' found", user); pr_log_auth(PR_LOG_NOTICE, "USER %s: no such user found from %s [%s] to %s:%d", user, session.c->remote_name, pr_netaddr_get_ipstr(session.c->remote_addr), pr_netaddr_get_ipstr(session.c->local_addr), session.c->local_port); *send_userauth_fail = TRUE; errno = ENOENT; return 0; } /* XXX Should we check the given FQDN here against the client's actual * DNS name and/or IP address? Or leave that up to the keystore's * verify_host_key() function? */ if (sftp_blacklist_reject_key(pkt->pool, hostkey_data, hostkey_datalen)) { *send_userauth_fail = TRUE; errno = EACCES; return 0; } /* The client signed the request as well; we need to authenticate the * host with the given key now. If that succeeds, we use the signature to * verify the request. And if that succeeds, then we're done authenticating. */ if (sftp_keystore_verify_host_key(pkt->pool, user, host_fqdn, host_user, hostkey_data, hostkey_datalen) < 0) { *send_userauth_fail = TRUE; errno = EACCES; return 0; } /* Make sure the signature matches as well. */ id_len = sftp_session_get_id(&id); /* XXX Is this buffer large enough? Too large? */ bufsz2 = buflen2 = 2048; ptr2 = buf2 = sftp_msg_getbuf(pkt->pool, bufsz2); sftp_msg_write_data(&buf2, &buflen2, id, id_len, TRUE); sftp_msg_write_byte(&buf2, &buflen2, SFTP_SSH2_MSG_USER_AUTH_REQUEST); sftp_msg_write_string(&buf2, &buflen2, orig_user); if (sftp_interop_supports_feature(SFTP_SSH2_FEAT_SERVICE_IN_HOST_SIG)) { sftp_msg_write_string(&buf2, &buflen2, service); } else { sftp_msg_write_string(&buf2, &buflen2, "ssh-userauth"); } sftp_msg_write_string(&buf2, &buflen2, "hostbased"); sftp_msg_write_string(&buf2, &buflen2, hostkey_algo); sftp_msg_write_data(&buf2, &buflen2, hostkey_data, hostkey_datalen, TRUE); sftp_msg_write_string(&buf2, &buflen2, host_fqdn); sftp_msg_write_string(&buf2, &buflen2, host_user_utf8); if (sftp_keys_verify_signed_data(pkt->pool, hostkey_algo, hostkey_data, hostkey_datalen, signature_data, signature_len, (unsigned char *) ptr2, (bufsz2 - buflen2)) < 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "failed to verify '%s' signature on hostbased auth request for " "user '%s', host %s", hostkey_algo, orig_user, host_fqdn); *send_userauth_fail = TRUE; return 0; } /* Make sure the user is authorized to login. Normally this is checked * as part of the password verification process, but in the case of * hostbased authentication, there is no password to verify. */ if (pr_auth_authorize(pkt->pool, user) != PR_AUTH_OK) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "authentication for user '%s' failed: User not authorized", user); pr_log_auth(PR_LOG_NOTICE, "USER %s (Login failed): User not authorized " "for login", user); *send_userauth_fail = TRUE; errno = EACCES; return 0; } return 1; }
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; }