--- vsftpd-2.3.2/main.c.chowngroup 2010-03-26 04:14:45.000000000 +0100 +++ vsftpd-2.3.2/main.c 2010-10-02 03:06:54.000000000 +0200 @@ -49,8 +49,8 @@ 0, INIT_MYSTR, /* Session state */ 0, - /* Userids */ - -1, -1, -1, + /* Userids / Gids */ + -1, -1, -1, -1, -1, -1, /* Pre-chroot() cache */ INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, INIT_MYSTR, 1, /* Logging */ @@ -337,6 +337,7 @@ tunable_ftp_username); } p_sess->anon_ftp_uid = vsf_sysutil_user_getuid(p_user); + p_sess->anon_ftp_gid = vsf_sysutil_user_getgid(p_user); } if (tunable_guest_enable) { @@ -348,17 +349,26 @@ tunable_guest_username); } p_sess->guest_user_uid = vsf_sysutil_user_getuid(p_user); + p_sess->guest_user_gid = vsf_sysutil_user_getgid(p_user); } if (tunable_chown_uploads) { const struct vsf_sysutil_user* p_user = vsf_sysutil_getpwnam(tunable_chown_username); + const struct vsf_sysutil_group* p_group = + vsf_sysutil_getgrnam(tunable_chown_groupname); if (p_user == 0) { die2("vsftpd: cannot locate user specified in 'chown_username':", tunable_chown_username); } + if (p_group == 0) + { + die2("vsftpd: cannot locate user specified in 'chown_groupname':", + tunable_chown_groupname); + } p_sess->anon_upload_chown_uid = vsf_sysutil_user_getuid(p_user); + p_sess->anon_upload_chown_gid = vsf_sysutil_group_getgid(p_group); } } --- vsftpd-2.3.2/parseconf.c.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/parseconf.c 2010-10-02 03:05:46.000000000 +0200 @@ -149,6 +149,7 @@ { "secure_chroot_dir", &tunable_secure_chroot_dir }, { "ftp_username", &tunable_ftp_username }, { "chown_username", &tunable_chown_username }, + { "chown_groupname", &tunable_chown_groupname }, { "xferlog_file", &tunable_xferlog_file }, { "vsftpd_log_file", &tunable_vsftpd_log_file }, { "message_file", &tunable_message_file }, --- vsftpd-2.3.2/privops.c.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/privops.c 2010-10-02 03:05:46.000000000 +0200 @@ -214,9 +214,11 @@ { 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) + /* Do nothing if it is already owned by the desired user/group. */ + if ((vsf_sysutil_statbuf_get_uid(s_p_statbuf) == + p_sess->anon_upload_chown_uid) && + (vsf_sysutil_statbuf_get_gid(s_p_statbuf) == + p_sess->anon_upload_chown_gid)) { return; } @@ -224,9 +226,12 @@ * the the anonymous ftp user */ if (p_sess->anon_upload_chown_uid == -1 || + p_sess->anon_upload_chown_gid == -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)) + vsf_sysutil_statbuf_get_uid(s_p_statbuf) != p_sess->guest_user_uid) || + (vsf_sysutil_statbuf_get_gid(s_p_statbuf) != p_sess->anon_ftp_gid && + vsf_sysutil_statbuf_get_gid(s_p_statbuf) != p_sess->guest_user_gid)) { die("invalid fd in cmd_process_chown"); } @@ -234,7 +239,7 @@ * 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); + vsf_sysutil_fchown(fd, p_sess->anon_upload_chown_uid, p_sess->anon_upload_chown_gid); } enum EVSFPrivopLoginResult --- vsftpd-2.3.2/session.h.chowngroup 2010-03-17 06:05:53.000000000 +0100 +++ vsftpd-2.3.2/session.h 2010-10-02 03:05:46.000000000 +0200 @@ -53,8 +53,11 @@ /* Details of userids which are interesting to us */ int anon_ftp_uid; + int anon_ftp_gid; int guest_user_uid; + int guest_user_gid; int anon_upload_chown_uid; + int anon_upload_chown_gid; /* Things we need to cache before we chroot() */ struct mystr banned_email_str; --- vsftpd-2.3.2/sysutil.c.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/sysutil.c 2010-10-02 03:05:46.000000000 +0200 @@ -2312,6 +2312,12 @@ return (struct vsf_sysutil_user*) getpwnam(p_user); } +struct vsf_sysutil_group* +vsf_sysutil_getgrnam(const char* p_group) +{ + return (struct vsf_sysutil_group*) getgrnam(p_group); +} + const char* vsf_sysutil_user_getname(const struct vsf_sysutil_user* p_user) { @@ -2340,6 +2346,13 @@ return p_passwd->pw_gid; } +int +vsf_sysutil_group_getgid(const struct vsf_sysutil_group* p_group) +{ + const struct group* p_grp = (const struct group*) p_group; + return p_grp->gr_gid; +} + struct vsf_sysutil_group* vsf_sysutil_getgrgid(const int gid) { --- vsftpd-2.3.2/sysutil.h.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/sysutil.h 2010-10-02 03:05:46.000000000 +0200 @@ -297,8 +297,10 @@ const struct vsf_sysutil_user* p_user); int vsf_sysutil_user_getuid(const struct vsf_sysutil_user* p_user); int vsf_sysutil_user_getgid(const struct vsf_sysutil_user* p_user); +int vsf_sysutil_group_getgid(const struct vsf_sysutil_group* p_group); struct vsf_sysutil_group* vsf_sysutil_getgrgid(const int gid); +struct vsf_sysutil_group* vsf_sysutil_getgrnam(const char* p_group); const char* vsf_sysutil_group_getname(const struct vsf_sysutil_group* p_group); /* More random things */ --- vsftpd-2.3.2/tunables.c.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/tunables.c 2010-10-02 03:05:46.000000000 +0200 @@ -112,6 +112,7 @@ const char* tunable_secure_chroot_dir; const char* tunable_ftp_username; const char* tunable_chown_username; +const char* tunable_chown_groupname; const char* tunable_xferlog_file; const char* tunable_vsftpd_log_file; const char* tunable_message_file; @@ -255,6 +256,7 @@ install_str_setting("/usr/share/empty", &tunable_secure_chroot_dir); install_str_setting("ftp", &tunable_ftp_username); install_str_setting("root", &tunable_chown_username); + install_str_setting("root", &tunable_chown_groupname); install_str_setting("/var/log/xferlog", &tunable_xferlog_file); install_str_setting("/var/log/vsftpd.log", &tunable_vsftpd_log_file); install_str_setting(".message", &tunable_message_file); --- vsftpd-2.3.2/tunables.h.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/tunables.h 2010-10-02 03:05:46.000000000 +0200 @@ -115,6 +115,7 @@ extern const char* tunable_secure_chroot_dir; extern const char* tunable_ftp_username; extern const char* tunable_chown_username; +extern const char* tunable_chown_groupname; extern const char* tunable_xferlog_file; extern const char* tunable_vsftpd_log_file; extern const char* tunable_message_file; --- vsftpd-2.3.2/vsftpd.conf.5.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/vsftpd.conf.5 2010-10-02 03:05:46.000000000 +0200 @@ -801,6 +801,14 @@ Default: root .TP +.B chown_groupname +This is the name of the group who is given ownership of anonymously uploaded +files. This option is only relevant if another option, +.BR chown_uploads , +is set. + +Default: root +.TP .B chroot_list_file The option is the name of a file containing a list of local users which will be placed in a chroot() jail in their home directory. This option is --- vsftpd-2.3.2/vsftpd.conf.chowngroup 2010-10-02 03:05:46.000000000 +0200 +++ vsftpd-2.3.2/vsftpd.conf 2010-10-02 03:05:46.000000000 +0200 @@ -45,6 +45,7 @@ # recommended! #chown_uploads=YES #chown_username=whoever +#chown_groupname=whoever # # You may override where the log file goes if you like. The default is shown # below.