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 }
static void vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str, int succeeded, enum EVSFLogEntryType what, const struct mystr* p_log_str) { /* Date - vsf_sysutil_get_current_date updates cached time */ str_alloc_text(p_str, vsf_sysutil_get_current_date()); /* Pid */ str_append_text(p_str, " [pid "); str_append_ulong(p_str, vsf_sysutil_getpid()); str_append_text(p_str, "] "); /* User */ if (!str_isempty(&p_sess->user_str)) { str_append_char(p_str, '['); str_append_str(p_str, &p_sess->user_str); str_append_text(p_str, "] "); } /* And the action */ if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput && what != kVSFLogEntryConnection) { if (succeeded) { str_append_text(p_str, "OK "); } else { str_append_text(p_str, "FAIL "); } } switch (what) { case kVSFLogEntryDownload: str_append_text(p_str, "DOWNLOAD"); break; case kVSFLogEntryUpload: str_append_text(p_str, "UPLOAD"); break; case kVSFLogEntryMkdir: str_append_text(p_str, "MKDIR"); break; case kVSFLogEntryLogin: str_append_text(p_str, "LOGIN"); break; case kVSFLogEntryFTPInput: str_append_text(p_str, "FTP command"); break; case kVSFLogEntryFTPOutput: str_append_text(p_str, "FTP response"); break; case kVSFLogEntryConnection: str_append_text(p_str, "CONNECT"); break; case kVSFLogEntryDelete: str_append_text(p_str, "DELETE"); break; case kVSFLogEntryRename: str_append_text(p_str, "RENAME"); break; case kVSFLogEntryRmdir: str_append_text(p_str, "RMDIR"); break; case kVSFLogEntryChmod: str_append_text(p_str, "CHMOD"); break; default: bug("bad entry_type in vsf_log_do_log"); break; } str_append_text(p_str, ": Client \""); str_append_str(p_str, &p_sess->remote_ip_str); str_append_char(p_str, '"'); if (what == kVSFLogEntryLogin && !str_isempty(&p_sess->anon_pass_str)) { str_append_text(p_str, ", anon password \""); str_append_str(p_str, &p_sess->anon_pass_str); str_append_char(p_str, '"'); } if (!str_isempty(p_log_str)) { str_append_text(p_str, ", \""); str_append_str(p_str, p_log_str); str_append_char(p_str, '"'); } if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput) { if (p_sess->transfer_size) { str_append_text(p_str, ", "); str_append_filesize_t(p_str, p_sess->transfer_size); str_append_text(p_str, " bytes"); } if (vsf_log_type_is_transfer(what)) { long delta_sec = vsf_sysutil_get_cached_time_sec() - p_sess->log_start_sec; long delta_usec = vsf_sysutil_get_cached_time_usec() - p_sess->log_start_usec; double time_delta = (double) delta_sec + ((double) delta_usec / (double) 1000000); double kbyte_rate = ((double) p_sess->transfer_size / time_delta) / (double) 1024; str_append_text(p_str, ", "); str_append_double(p_str, kbyte_rate); str_append_text(p_str, "Kbyte/sec"); } } }
void seccomp_sandbox_setup_postlogin(const struct vsf_session* p_sess) { int is_anon = p_sess->is_anonymous; int open_flag = kOpenFlags; if (tunable_write_enable) { open_flag |= O_ACCMODE; } /* Put lstat() first because it is a very hot syscall for large directory * listings. And the current BPF only allows a linear scan of allowed * syscalls. */ allow_nr(__NR_lstat); /* Allow all the simple pre-login things and then expand upon them. */ seccomp_sandbox_setup_prelogin(p_sess); /* Simple file descriptor-based operations. */ if (tunable_xferlog_enable || tunable_dual_log_enable || tunable_lock_upload_files) { allow_nr_1_arg_match(__NR_fcntl, 2, F_SETLKW); allow_nr_1_arg_match(__NR_fcntl, 2, F_SETLK); } if (tunable_async_abor_enable) { allow_nr_2_arg_match(__NR_fcntl, 2, F_SETOWN, 3, vsf_sysutil_getpid()); } allow_nr_2_arg_match(__NR_setsockopt, 2, SOL_SOCKET, 3, SO_KEEPALIVE); allow_nr_2_arg_match(__NR_setsockopt, 2, SOL_SOCKET, 3, SO_LINGER); allow_nr_2_arg_match(__NR_setsockopt, 2, IPPROTO_IP, 3, IP_TOS); allow_nr(__NR_fstat); allow_nr(__NR_lseek); /* Since we use chroot() to restrict filesystem access, we can just blanket * allow open(). */ allow_nr_1_arg_mask(__NR_open, 2, open_flag); allow_nr_1_arg_mask(__NR_openat, 3, open_flag); /* Other pathname-based metadata queries. */ allow_nr(__NR_stat); allow_nr(__NR_readlink); /* Directory handling: query, change, read. */ allow_nr(__NR_getcwd); allow_nr(__NR_chdir); allow_nr(__NR_getdents); /* Misc */ allow_nr(__NR_umask); /* Config-dependent items follow. */ if (tunable_use_sendfile) { allow_nr(__NR_sendfile); } if (tunable_idle_session_timeout > 0 || tunable_data_connection_timeout > 0 || tunable_async_abor_enable) { allow_nr(__NR_rt_sigaction); } if (tunable_idle_session_timeout > 0 || tunable_data_connection_timeout > 0) { allow_nr(__NR_alarm); } if (tunable_one_process_model) { seccomp_sandbox_setup_data_connections(); if (is_anon && tunable_chown_uploads) { allow_nr(__NR_fchmod); allow_nr(__NR_fchown); } } else { /* Need to receieve file descriptors from privileged broker. */ allow_nr_1_arg_match(__NR_recvmsg, 3, 0); if ((is_anon && tunable_chown_uploads) || tunable_ssl_enable) { /* Need to send file descriptors to privileged broker. */ allow_nr_1_arg_match(__NR_sendmsg, 3, 0); } } if (tunable_syslog_enable) { /* The ability to pass an address spec isn't needed so disable it. We ensure * the 6th arg (socklen) is 0. We could have checked the 5th arg (sockptr) * but I don't know if 64-bit compares work in the kernel filter, so we're * happy to check the socklen arg, which is 32 bits. */ allow_nr_1_arg_match(__NR_sendto, 6, 0); } if (tunable_text_userdb_names) { reject_nr(__NR_socket, EACCES); allow_nr_2_arg_match(__NR_mmap, 3, PROT_READ, 4, MAP_SHARED); } if (tunable_write_enable) { if (!is_anon || tunable_anon_mkdir_write_enable) { allow_nr(__NR_mkdir); } if (!is_anon || tunable_anon_other_write_enable || tunable_delete_failed_uploads) { allow_nr(__NR_unlink); } if (!is_anon || tunable_anon_other_write_enable) { allow_nr(__NR_rmdir); allow_nr(__NR_rename); allow_nr(__NR_ftruncate); if (tunable_mdtm_write) { allow_nr(__NR_utime); allow_nr(__NR_utimes); } } if (!is_anon && tunable_chmod_enable) { allow_nr(__NR_chmod); } } }