void vsf_privop_do_file_chown(struct vsf_session* p_sess, int fd) { static struct vsf_sysutil_statbuf* s_p_statbuf; vsf_sysutil_fstat(fd, &s_p_statbuf); /* Do nothing if it is already owned by the desired user. */ if (vsf_sysutil_statbuf_get_uid(s_p_statbuf) == p_sess->anon_upload_chown_uid) { return; } /* Drop it like a hot potato unless it's a regular file owned by * the the anonymous ftp user */ if (p_sess->anon_upload_chown_uid == -1 || !vsf_sysutil_statbuf_is_regfile(s_p_statbuf) || (vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->anon_ftp_uid && vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid)) { die("invalid fd in cmd_process_chown"); } /* SECURITY! You need an OS which strips SUID/SGID bits on chown(), * otherwise a compromise of the FTP user will lead to compromise of * the "anon_upload_chown_uid" user (think chmod +s). */ vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, -1); }
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); }
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); } }
void vsf_parseconf_load_file(const char* p_filename, int errs_fatal) { struct mystr config_file_str = INIT_MYSTR; struct mystr config_setting_str = INIT_MYSTR; struct mystr config_value_str = INIT_MYSTR; unsigned int str_pos = 0; int retval; if (!p_filename) { p_filename = s_p_saved_filename; } else { if (s_p_saved_filename) { vsf_sysutil_free((char*)s_p_saved_filename); } s_p_saved_filename = vsf_sysutil_strdup(p_filename); } if (!p_filename) { bug("null filename in vsf_parseconf_load_file"); } retval = str_fileread(&config_file_str, p_filename, VSFTP_CONF_FILE_MAX); if (vsf_sysutil_retval_is_error(retval)) { if (errs_fatal) { die2("cannot read config file: ", p_filename); } else { str_free(&config_file_str); return; } } { struct vsf_sysutil_statbuf* p_statbuf = 0; retval = vsf_sysutil_stat(p_filename, &p_statbuf); /* Security: check current user owns the config file. These are sanity * checks for the admin, and are NOT designed to be checks safe from * race conditions. */ if (vsf_sysutil_retval_is_error(retval) || vsf_sysutil_statbuf_get_uid(p_statbuf) != vsf_sysutil_getuid() || !vsf_sysutil_statbuf_is_regfile(p_statbuf)) { die("config file not owned by correct user, or not a file"); } vsf_sysutil_free(p_statbuf); } while (str_getline(&config_file_str, &config_setting_str, &str_pos)) { if (str_isempty(&config_setting_str) || str_get_char_at(&config_setting_str, 0) == '#' || str_all_space(&config_setting_str)) { continue; } vsf_parseconf_load_setting(str_getbuf(&config_setting_str), errs_fatal); } str_free(&config_file_str); str_free(&config_setting_str); str_free(&config_value_str); }
static void build_dir_line(struct mystr* p_str, const struct mystr* p_filename_str, const struct vsf_sysutil_statbuf* p_stat, long curr_time) { static struct mystr s_tmp_str; char *tmp_filename=NULL; filesize_t size = vsf_sysutil_statbuf_get_size(p_stat); /* Permissions */ str_alloc_text(p_str, vsf_sysutil_statbuf_get_perms(p_stat)); str_append_char(p_str, ' '); /* Hard link count */ str_alloc_ulong(&s_tmp_str, vsf_sysutil_statbuf_get_links(p_stat)); str_lpad(&s_tmp_str, 4); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* User */ if (tunable_hide_ids) { str_alloc_text(&s_tmp_str, "ftp"); } else { int uid = vsf_sysutil_statbuf_get_uid(p_stat); struct vsf_sysutil_user* p_user = 0; if (tunable_text_userdb_names) { p_user = vsf_sysutil_getpwuid(uid); } if (p_user == 0) { str_alloc_ulong(&s_tmp_str, (unsigned long) uid); } else { str_alloc_text(&s_tmp_str, vsf_sysutil_user_getname(p_user)); } } str_rpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Group */ if (tunable_hide_ids) { str_alloc_text(&s_tmp_str, "ftp"); } else { int gid = vsf_sysutil_statbuf_get_gid(p_stat); struct vsf_sysutil_group* p_group = 0; if (tunable_text_userdb_names) { p_group = vsf_sysutil_getgrgid(gid); } if (p_group == 0) { str_alloc_ulong(&s_tmp_str, (unsigned long) gid); } else { str_alloc_text(&s_tmp_str, vsf_sysutil_group_getname(p_group)); } } str_rpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Size in bytes */ str_alloc_filesize_t(&s_tmp_str, size); str_lpad(&s_tmp_str, 8); str_append_str(p_str, &s_tmp_str); str_append_char(p_str, ' '); /* Date stamp */ str_append_text(p_str, vsf_sysutil_statbuf_get_date(p_stat, tunable_use_localtime, curr_time)); str_append_char(p_str, ' '); /* Filename */ tmp_filename = local2remote(str_getbuf(p_filename_str)); if (tmp_filename == NULL) str_append_str(p_str, p_filename_str); else { str_append_text(p_str, tmp_filename); vsf_sysutil_free(tmp_filename); } str_append_text(p_str, "\r\n"); }