static void handle_stat(struct vsf_session* p_sess) { vsf_cmdio_write_hyphen(p_sess, FTP_STATOK, "FTP server status:"); vsf_cmdio_write_raw(p_sess, " Connected to "); vsf_cmdio_write_raw(p_sess, str_getbuf(&p_sess->remote_ip_str)); vsf_cmdio_write_raw(p_sess, "\r\n"); vsf_cmdio_write_raw(p_sess, " Logged in as "); vsf_cmdio_write_raw(p_sess, str_getbuf(&p_sess->user_str)); vsf_cmdio_write_raw(p_sess, "\r\n"); vsf_cmdio_write_raw(p_sess, " TYPE: "); if (p_sess->is_ascii) { vsf_cmdio_write_raw(p_sess, "ASCII\r\n"); } else { vsf_cmdio_write_raw(p_sess, "BINARY\r\n"); } if (p_sess->bw_rate_max == 0) { vsf_cmdio_write_raw(p_sess, " No session bandwidth limit\r\n"); } else { vsf_cmdio_write_raw(p_sess, " Session bandwidth limit in byte/s is "); vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(p_sess->bw_rate_max)); vsf_cmdio_write_raw(p_sess, "\r\n"); } if (tunable_idle_session_timeout == 0) { vsf_cmdio_write_raw(p_sess, " No session timeout\r\n"); } else { vsf_cmdio_write_raw(p_sess, " Session timeout in seconds is "); vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(tunable_idle_session_timeout)); vsf_cmdio_write_raw(p_sess, "\r\n"); } if (p_sess->num_clients > 0) { vsf_cmdio_write_raw(p_sess, " At session startup, client count was "); vsf_cmdio_write_raw(p_sess, vsf_sysutil_ulong_to_str(p_sess->num_clients)); vsf_cmdio_write_raw(p_sess, "\r\n"); } vsf_cmdio_write_raw(p_sess, " vsFTPd - secure, fast, stable\r\n"); vsf_cmdio_write(p_sess, FTP_STATOK, "End of status"); }
static void calculate_chdir_dir(int anon_login, struct mystr* p_userdir_str, struct mystr* p_chroot_str, struct mystr* p_chdir_str, const struct mystr* p_user_str, const struct mystr* p_orig_user_str) { if (!anon_login) { const struct vsf_sysutil_user* p_user = str_getpwnam(p_user_str); if (p_user == 0) { die2("cannot locate user entry:", str_getbuf(p_user_str)); } str_alloc_text(p_userdir_str, vsf_sysutil_user_get_homedir(p_user)); if (tunable_user_sub_token) { str_replace_text(p_userdir_str, tunable_user_sub_token, str_getbuf(p_orig_user_str)); } } if (anon_login && tunable_anon_root) { str_alloc_text(p_chroot_str, tunable_anon_root); } else if (!anon_login && tunable_local_root) { str_alloc_text(p_chroot_str, tunable_local_root); if (tunable_user_sub_token) { str_replace_text(p_chroot_str, tunable_user_sub_token, str_getbuf(p_orig_user_str)); } } /* If enabled, the chroot() location embedded in the HOMEDIR takes * precedence. */ if (!anon_login && tunable_passwd_chroot_enable) { struct str_locate_result loc_result; loc_result = str_locate_text(p_userdir_str, "/./"); if (loc_result.found) { str_split_text(p_userdir_str, p_chdir_str, "/./"); str_copy(p_chroot_str, p_userdir_str); } } }
void vsf_sysutil_setproctitle_internal(const char* p_buf) { struct mystr proctitle_str = INIT_MYSTR; unsigned int to_copy; if (!s_proctitle_inited) { bug("vsf_sysutil_setproctitle: not initialized"); } vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space); if (s_proctitle_space < 32) { return; } str_alloc_text(&proctitle_str, "vsftpd: "); str_append_text(&proctitle_str, p_buf); to_copy = str_getlen(&proctitle_str); if (to_copy > s_proctitle_space - 1) { to_copy = s_proctitle_space - 1; } vsf_sysutil_memcpy(s_p_proctitle, str_getbuf(&proctitle_str), to_copy); str_free(&proctitle_str); s_p_proctitle[to_copy] = '\0'; }
static void handle_per_user_config(const struct mystr* p_user_str) { struct mystr filename_str = INIT_MYSTR; struct vsf_sysutil_statbuf* p_statbuf = 0; struct str_locate_result loc_result; int retval; if (!tunable_user_config_dir) { return; } /* Security paranoia - ignore if user has a / in it. */ loc_result = str_locate_char(p_user_str, '/'); if (loc_result.found) { return; } str_alloc_text(&filename_str, tunable_user_config_dir); str_append_char(&filename_str, '/'); str_append_str(&filename_str, p_user_str); retval = str_stat(&filename_str, &p_statbuf); if (!vsf_sysutil_retval_is_error(retval)) { /* Security - file ownership check now in vsf_parseconf_load_file() */ vsf_parseconf_load_file(str_getbuf(&filename_str), 1); } else if (vsf_sysutil_get_error() != kVSFSysUtilErrNOENT) { die("error opening per-user config file"); } str_free(&filename_str); vsf_sysutil_free(p_statbuf); }
int str_getline(const struct mystr* p_str, struct mystr* p_line_str, unsigned int* p_pos) { unsigned int start_pos = *p_pos; unsigned int curr_pos = start_pos; unsigned int buf_len = str_getlen(p_str); const char* p_buf = str_getbuf(p_str); unsigned int out_len; if (start_pos > buf_len) { bug("p_pos out of range in str_getline"); } str_empty(p_line_str); if (start_pos == buf_len) { return 0; } while (curr_pos < buf_len && p_buf[curr_pos] != '\n') { curr_pos++; } out_len = curr_pos - start_pos; /* If we ended on a \n - skip it */ if (curr_pos < buf_len && p_buf[curr_pos] == '\n') { curr_pos++; } private_str_alloc_memchunk(p_line_str, p_buf + start_pos, out_len); *p_pos = curr_pos; return 1; }
static int ssl_cert_digest(SSL* p_ssl, struct vsf_session* p_sess, struct mystr* p_str) { X509* p_cert = SSL_get_peer_certificate(p_ssl); unsigned int num_bytes = 0; if (p_cert == NULL) { return 0; } str_reserve(p_str, EVP_MAX_MD_SIZE); str_empty(p_str); str_rpad(p_str, EVP_MAX_MD_SIZE); if (!X509_digest(p_cert, EVP_sha256(), (unsigned char*) str_getbuf(p_str), &num_bytes)) { die("X509_digest failed"); } X509_free(p_cert); if (tunable_debug_ssl) { unsigned int i; str_alloc_text(&debug_str, "Cert digest:"); for (i = 0; i < num_bytes; ++i) { str_append_char(&debug_str, ' '); str_append_ulong( &debug_str, (unsigned long) (unsigned char) str_get_char_at(p_str, i)); } vsf_log_line(p_sess, kVSFLogEntryDebug, &debug_str); } str_trunc(p_str, num_bytes); return 1; }
void str_empty(struct mystr* p_str) { /* Ensure a buffer is allocated. */ (void) str_getbuf(p_str); str_trunc(p_str, 0); }
static void handle_per_user_config(const struct mystr* p_user_str) { struct mystr filename_str = INIT_MYSTR; struct vsf_sysutil_statbuf* p_statbuf = 0; struct str_locate_result loc_result; int retval; if (!tunable_user_config_dir) { return; } /* Security paranoia - ignore if user has a / in it. */ loc_result = str_locate_char(p_user_str, '/'); if (loc_result.found) { return; } str_alloc_text(&filename_str, tunable_user_config_dir); str_append_char(&filename_str, '/'); str_append_str(&filename_str, p_user_str); retval = str_stat(&filename_str, &p_statbuf); /* Security - ignore unless owned by root */ if (!vsf_sysutil_retval_is_error(retval) && vsf_sysutil_statbuf_get_uid(p_statbuf) == VSFTP_ROOT_UID) { vsf_parseconf_load_file(str_getbuf(&filename_str), 1); } str_free(&filename_str); vsf_sysutil_free(p_statbuf); }
void die2(const char* p_text1, const char* p_text2) { struct mystr die_str = INIT_MYSTR; str_alloc_text(&die_str, p_text1); str_append_text(&die_str, p_text2); die(str_getbuf(&die_str)); }
void vsf_sysutil_setproctitle_internal(const char* p_buf) { struct mystr proctitle_str = INIT_MYSTR; union pstun p; str_alloc_text(&proctitle_str, "vsftpd: "); str_append_text(&proctitle_str, p_buf); p.pst_command = str_getbuf(&proctitle_str); pstat(PSTAT_SETCMD, p, 0, 0, 0); str_free(&proctitle_str); }
int ssl_write_str(void* p_ssl, const struct mystr* p_str) { unsigned int len = str_getlen(p_str); int ret = SSL_write((SSL*) p_ssl, str_getbuf(p_str), len); if ((unsigned int) ret != len) { return -1; } return 0; }
void vsf_insert_uwtmp(const struct mystr* p_user_str, const struct mystr* p_host_str) { if (sizeof(s_utent.ut_line) < 16) { return; } if (s_uwtmp_inserted) { bug("vsf_insert_uwtmp"); } { struct mystr line_str = INIT_MYSTR; str_alloc_text(&line_str, VSF_PROJECT ":"); str_append_ulong(&line_str, vsf_sysutil_getpid()); if (str_getlen(&line_str) >= sizeof(s_utent.ut_line)) { str_free(&line_str); return; } vsf_sysutil_strcpy(s_utent.ut_line, str_getbuf(&line_str), sizeof(s_utent.ut_line)); str_free(&line_str); } s_uwtmp_inserted = 1; s_utent.ut_type = USER_PROCESS; s_utent.ut_pid = vsf_sysutil_getpid(); vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str), sizeof(s_utent.ut_user)); vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str), sizeof(s_utent.ut_host)); s_utent.ut_tv.tv_sec = vsf_sysutil_get_time_sec(); setutxent(); (void) pututxline(&s_utent); endutxent(); #ifdef VSF_SYSDEP_HAVE_UPDWTMPX updwtmpx(WTMPX_FILE, &s_utent); #endif }
void vsf_sysutil_setproctitle(const char* p_text) { struct mystr proctitle_str = INIT_MYSTR; str_copy(&proctitle_str, &s_proctitle_prefix_str); if (!str_isempty(&proctitle_str)) { str_append_text(&proctitle_str, ": "); } str_append_text(&proctitle_str, p_text); vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str)); str_free(&proctitle_str); }
void die2(const char* p_text1, const char* p_text2) { struct mystr die_str = INIT_MYSTR; str_alloc_text(&die_str, p_text1); if (p_text2) { str_append_text(&die_str, p_text2); } else { str_append_text(&die_str, "(null)"); } die(str_getbuf(&die_str)); }
int ssl_read_into_str(struct vsf_session* p_sess, void* p_ssl, struct mystr* p_str) { unsigned int len = str_getlen(p_str); int ret = ssl_read(p_sess, p_ssl, (char*) str_getbuf(p_str), len); if (ret >= 0) { str_trunc(p_str, (unsigned int) ret); } else { str_empty(p_str); } return ret; }
int str_open(const struct mystr* p_str, const enum EVSFSysStrOpenMode mode) { enum EVSFSysUtilOpenMode open_mode = kVSFSysStrOpenUnknown; switch (mode) { case kVSFSysStrOpenReadOnly: open_mode = kVSFSysUtilOpenReadOnly; break; default: bug("unknown mode value in str_open"); break; } return vsf_sysutil_open_file(str_getbuf(p_str), open_mode); }
int str_readlink(struct mystr* p_str, const struct mystr* p_filename_str) { static char* p_readlink_buf; int retval; if (p_readlink_buf == 0) { vsf_secbuf_alloc(&p_readlink_buf, VSFTP_PATH_MAX); } /* In case readlink() fails */ str_empty(p_str); /* Note: readlink(2) does not NULL terminate, but our wrapper does */ retval = vsf_sysutil_readlink(str_getbuf(p_filename_str), p_readlink_buf, VSFTP_PATH_MAX); if (vsf_sysutil_retval_is_error(retval)) { return retval; } str_alloc_text(p_str, p_readlink_buf); return 0; }
static void handle_per_user_config(const struct mystr* p_user_str) { if (tunable_user_config_dir) { struct mystr filename_str = INIT_MYSTR; struct vsf_sysutil_statbuf* p_statbuf = 0; int retval; str_alloc_text(&filename_str, tunable_user_config_dir); str_append_char(&filename_str, '/'); str_append_str(&filename_str, p_user_str); retval = str_stat(&filename_str, &p_statbuf); /* Security - ignore unless owned by root */ if (!vsf_sysutil_retval_is_error(retval) && vsf_sysutil_statbuf_get_uid(p_statbuf) == VSFTP_ROOT_UID) { vsf_parseconf_load_file(str_getbuf(&filename_str)); } str_free(&filename_str); vsf_sysutil_free(p_statbuf); } }
static void calculate_chdir_dir(int anon, struct mystr* p_chroot_str, const struct mystr* p_user_str) { if (anon && tunable_anon_root) { str_alloc_text(p_chroot_str, tunable_anon_root); } else if (!anon && tunable_local_root) { str_alloc_text(p_chroot_str, tunable_local_root); } /* If enabled, the chroot() location embedded in the HOMEDIR takes * precedence. */ if (!anon && tunable_passwd_chroot_enable) { struct mystr homedir_str = INIT_MYSTR; const struct vsf_sysutil_user* p_user = str_getpwnam(p_user_str); struct str_locate_result loc_result; if (p_user == 0) { struct mystr death_str = INIT_MYSTR; str_alloc_text(&death_str, "str_getpwnam: "); str_append_str(&death_str, p_user_str); die(str_getbuf(&death_str)); } str_alloc_text(&homedir_str, vsf_sysutil_user_get_homedir(p_user)); loc_result = str_locate_text(&homedir_str, "/./"); if (loc_result.found) { struct mystr tmp_str = INIT_MYSTR; str_split_text(&homedir_str, &tmp_str, "/./"); str_free(&tmp_str); str_copy(p_chroot_str, &homedir_str); } str_free(&homedir_str); } }
const unsigned char* vsf_sysutil_parse_ipv6(const struct mystr* p_str) { static struct mystr s_ret; static struct mystr s_rhs_ret; static struct mystr s_lhs_str; static struct mystr s_rhs_str; unsigned int lhs_len; unsigned int rhs_len; str_empty(&s_ret); str_empty(&s_rhs_ret); str_copy(&s_lhs_str, p_str); str_split_text(&s_lhs_str, &s_rhs_str, "::"); if (!ipv6_parse_main(&s_ret, &s_lhs_str)) { return 0; } if (!ipv6_parse_main(&s_rhs_ret, &s_rhs_str)) { return 0; } lhs_len = str_getlen(&s_ret); rhs_len = str_getlen(&s_rhs_ret); if (lhs_len + rhs_len > 16) { return 0; } if (rhs_len > 0) { unsigned int add_nulls = 16 - (lhs_len + rhs_len); while (add_nulls--) { str_append_char(&s_ret, '\0'); } str_append_str(&s_ret, &s_rhs_ret); } return (const unsigned char*) str_getbuf(&s_ret); }
int str_create(const struct mystr* p_str) { return vsf_sysutil_create_file(str_getbuf(p_str)); }
int str_lstat(const struct mystr* p_str, struct vsf_sysutil_statbuf** p_ptr) { return vsf_sysutil_lstat(str_getbuf(p_str), p_ptr); }
int str_chdir(const struct mystr* p_str) { return vsf_sysutil_chdir(str_getbuf(p_str)); }
int str_unlink(const struct mystr* p_str) { return vsf_sysutil_unlink(str_getbuf(p_str)); }
int str_mkdir(const struct mystr* p_str, const unsigned int mode) { return vsf_sysutil_mkdir(str_getbuf(p_str), mode); }
int str_write_loop(const struct mystr* p_str, const int fd) { return vsf_sysutil_write_loop(fd, str_getbuf(p_str), str_getlen(p_str)); }
struct vsf_sysutil_user* str_getpwnam(const struct mystr* p_user_str) { return vsf_sysutil_getpwnam(str_getbuf(p_user_str)); }
struct vsf_sysutil_dir* str_opendir(const struct mystr* p_str) { return vsf_sysutil_opendir(str_getbuf(p_str)); }
int str_rename(const struct mystr* p_from_str, const struct mystr* p_to_str) { return vsf_sysutil_rename(str_getbuf(p_from_str), str_getbuf(p_to_str)); }
int str_chmod(const struct mystr* p_str, unsigned int mode) { return vsf_sysutil_chmod(str_getbuf(p_str), mode); }