diff -uwrP wu-ftpd-2.6.2/CHANGES wu-ftpd-2.6.2/CHANGES --- wu-ftpd-2.6.2/CHANGES 2001-11-29 12:25:33.000000000 -0500 +++ wu-ftpd-2.6.2/CHANGES 2002-12-13 17:29:45.000000000 -0500 @@ -22,6 +22,18 @@ $Id: CHANGES,v 1.44.2.1 2001/11/29 17:25:33 wuftpd Exp $ +Changes in 2.6.2cu: + + o Add an option to define an alternate home directory to log real users + into if we're doing strict_homedir checking or base_homedir checking + and we fail either one of those. + + o Split up the PARANOID configuration option into individual options + for finer control. + + o Add an option to check a user's home directory against a "base" + directory and refuse the login if the former isn't below the + latter. Changes in 2.6.2: Released 29 Nov, 2001 diff -uwrP wu-ftpd-2.6.2/CONTRIBUTORS wu-ftpd-2.6.2/CONTRIBUTORS --- wu-ftpd-2.6.2/CONTRIBUTORS 2000-07-01 13:44:39.000000000 -0400 +++ wu-ftpd-2.6.2/CONTRIBUTORS 2002-12-13 17:25:52.000000000 -0500 @@ -310,6 +310,7 @@ suse@wavenet.it (Simone Castellaneta) swcxt@boco.co.gov sxk13@psu.edu +syl@alcor.concordia.ca (Sylvain Robitaille) sylvain@nasirc.hq.nasa.gov (Greg Sylvain) tchrist@jhereg.perl.com thianlengvictor.tan@bnpgroup.com diff -uwrP wu-ftpd-2.6.2/README.AUTOCONF wu-ftpd-2.6.2/README.AUTOCONF --- wu-ftpd-2.6.2/README.AUTOCONF 1999-10-01 11:04:13.000000000 -0400 +++ wu-ftpd-2.6.2/README.AUTOCONF 2002-12-13 17:25:52.000000000 -0500 @@ -29,6 +29,19 @@ --disable-dnsretry Don't retry failed DNS lookups at connection time --enable-anononly allow only anonymous ftp connections, no real user logins +--enable-delete permit deletion of files +--enable-ow-file permit overwriting of files +--disable-strict-homedir don't perform strict checking of home directory +--disable-site-umask don't support SITE UMASK +--disable-site-chmod don't support SITE CHMOD +--disable-site-idle don't support SITE IDLE +--enable-site-exec permit SITE EXEC/SITE INDEX +--disable-site-alias don't support SITE ALIAS +--disable-site-groups don't support SITE GROUPS +--disable-site-cdpath don't support SITE CDPATH +--disable-checkmethod don't support SITE CHECKMETHOD +--disable-checksum don't support SITE CHECKSUM +--disable-site don't support any SITE commands --enable-paranoid Disables some features that might possibly affect security --disable-quota Don't support disk quotas, even if your operating @@ -97,6 +110,10 @@ Use this option if you want those clients to be able to connect. See the CHANGES file for more details. +--with-base-homedir=path path under which users home directories must + reside. +--with-alt-homedir=path directory to use if real user's home fails either + strict or base tests. --with-bufsize=x Set buffer size to x [You won't usually have to adjust this value] --with-backlog=x Number of incoming processes to backlog in daemon diff -uwrP wu-ftpd-2.6.2/README.paranoid wu-ftpd-2.6.2/README.paranoid --- wu-ftpd-2.6.2/README.paranoid 1969-12-31 19:00:00.000000000 -0500 +++ wu-ftpd-2.6.2/README.paranoid 2002-12-13 17:25:52.000000000 -0500 @@ -0,0 +1,82 @@ +Wed Jul 26 01:26:48 EDT 2000 (Sylvain Robitaille ) +Sun Aug 6 22:30:14 EDT 2000 (add ALT_HOMEDIR) + +We needed to split up the --enable-paranoid configuration option to +provide additional control of which options are available. This has been +done, with defaults which render the server "somewhat paranoid". +There's a really good chance that if you're upgrading an existing FTP +server on a host with real users, the changes noted here will affect +you, so please do read this file. + +Available options for configure, which affect "paranoid" behaviour: + +--enable-paranoid: This option is actually the same as always, though + some of its effects are now default behaviour. + Provided for backwards-compatibility. + equivalent to specifying: + --enable-strict-homedir \ + --disable-delete \ + --disable-overwrite \ + --disable-site + (the first three of which are now default.) + +--enable-delete: The default behaviour no longer permits users to delete + files residing on the FTP server. To permit users to + delete files (assuming they have sufficient permission + at the filesystem level), use this option. + +--enable-overwrite: This option permits users to overwrite (with either + "put" or "rename") existing files (assuming they have + sufficient permission at the filesystem level) + residing on the FTP server. The default behaviour no + longer permits files to be overwritten. + +--disable-strict-homedir: By default, wu-ftpd now checks that a real + user's home directory, as listed in + /etc/passwd, exists and is properly accessible + to the user. If either one is not true, the + user will not be permitted to login via FTP. + + Contrast this behaviour to the old wu-ftpd + behaviour, which by default would permit the + user to log in, using "/" as the home + directory, unless PARANOID was enabled, in + which case the behaviour described above was + applicable. + + Use this option if you prefer the old, non- + paranoid behaviour. + +--with-base-homedir=path: This is a new option which causes wu-ftpd to + permit a user to login only if his/her home + directory is below the path specified by this + option. + +--with-alt-homedir=path: This is a new option which permits a real user + to login to the directory defined by this option + if the user's own home directory fails either + the strict-homedir or the base-homedir checks. + Use this option carefully. + +--disable-site: This option disables all SITE commands (they return an + error message). By default, all the SITE commands are + enabled, *except* EXEC, INDEX, NEWER, and MINFO. + +Individual SITE commands can be disabled with the following options: + + --disable-checkmethod: Disables the CHECKMETHOD command. + --disable-checksum: Disables the CHECKSUM command. + --disable-site-alias: Disables the ALIAS command. + --disable-site-cdpath: Disables the CDPATH command. + --disable-site-chmod: Disables the CHMOD command. + --disable-site-groups: Disables the GROUPS command. + --disable-site-idle: Disables the IDLE command. + --disable-site-umask: Disables the UMASK command. + +Note that by default, the SITE EXEC (and INDEX) command is disabled. For +most sites, this is desirable, but for some, that command will be +necessary. It can be enabled with eth following option: + + --enable-site-exec: Enables the EXEC and INDEX commands. + + diff -uwrP wu-ftpd-2.6.2/config.h.in wu-ftpd-2.6.2/config.h.in --- wu-ftpd-2.6.2/config.h.in 2001-11-29 12:10:57.000000000 -0500 +++ wu-ftpd-2.6.2/config.h.in 2002-12-13 17:25:52.000000000 -0500 @@ -94,6 +94,37 @@ #undef PARANOID /* + * Better PARANOID options. + * Allows finer control than PARANOID. + * See README.paranoid for more information on these options. + * + * 2000/07/15 Sylvain Robitaille: The following defaults are "somewhat + * paranoid". Defining PARANOID will + * result in the following, which + * emulates known behaviour: + * + * #undef ENABLE_DELETE + * #undef ENABLE_OVERWRITE + * #undef DISABLE_STRICT_HOMEDIR + * #define DISABLE_SITE 1 + */ + +#undef ENABLE_DELETE +#undef ENABLE_OVERWRITE +#undef DISABLE_STRICT_HOMEDIR + +#undef DISABLE_SITE_UMASK +#undef DISABLE_SITE_CHMOD +#undef DISABLE_SITE_IDLE +#undef ENABLE_SITE_EXEC +#undef DISABLE_SITE_ALIAS +#undef DISABLE_SITE_GROUPS +#undef DISABLE_SITE_CDPATH +#undef DISABLE_SITE_CHECKMETHOD +#undef DISABLE_SITE_CHECKSUM +#undef DISABLE_SITE + +/* * SKEY * Add SKEY support -- REQUIRES SKEY libraries * See FIXES-2.4-HOBBIT for more information on this option. @@ -133,6 +164,23 @@ #undef USE_RFC931 /* + * BASE_HOMEDIR + * You can specify a directory under which real users' home directories + * must reside. Logins will be refused if the home directory is not + * below the directory specified here. + */ + +#undef BASE_HOMEDIR + +/* + * ALT_HOMEDIR + * You can specify a directory to which real users may still login if + * their own home directory fails either the STRICT_HOMEDIR or the + * BASE_HOMEDIR test. + */ +#undef ALT_HOMEDIR + +/* * BUFFER_SIZE * You can specify the buffer size for binary transfers; the defaults * are often far too small for efficiency. diff -uwrP wu-ftpd-2.6.2/config.h.noac wu-ftpd-2.6.2/config.h.noac --- wu-ftpd-2.6.2/config.h.noac 2001-11-29 12:10:58.000000000 -0500 +++ wu-ftpd-2.6.2/config.h.noac 2002-12-13 17:25:52.000000000 -0500 @@ -96,6 +96,47 @@ #undef PARANOID /* + * Better PARANOID options. + * Allows finer control than PARANOID. + * See README.paranoid for more information on these options. + * + * 2000/07/15 Sylvain Robitaille: The following defaults are "somewhat + * paranoid". Defining PARANOID will + * result in the following, which + * emulates known behaviour: + * + * #undef ENABLE_DELETE + * #undef ENABLE_OVERWRITE + * #undef DISABLE_STRICT_HOMEDIR + * #define DISABLE_SITE 1 + */ + +#undef ENABLE_DELETE +#undef ENABLE_OVERWRITE +#undef DISABLE_STRICT_HOMEDIR + +#undef DISABLE_SITE_UMASK +#undef DISABLE_SITE_CHMOD +#undef DISABLE_SITE_IDLE +#undef ENABLE_SITE_EXEC +#undef DISABLE_SITE_ALIAS +#undef DISABLE_SITE_GROUPS +#undef DISABLE_SITE_CDPATH +#undef DISABLE_SITE_CHECKMETHOD +#undef DISABLE_SITE_CHECKSUM +#undef DISABLE_SITE + +/* + * 2000/07/17 Sylvain Robitaille: Defining PARANOID overrides these. + */ +#ifdef PARANOID +#undef ENABLE_DELETE +#undef ENABLE_OVERWRITE +#undef DISABLE_STRICT_HOMEDIR +#define DISABLE_SITE 1 +#endif + +/* * SKEY * Add SKEY support -- REQUIRES SKEY libraries * See FIXES-2.4-HOBBIT for more information on this option. @@ -135,10 +176,27 @@ #undef USE_RFC931 /* + * BASE_HOMEDIR + * You can specify a directory under which real users' home directories + * must reside. Logins will be refused if the home directory is not + * below the directory specified here. + */ +#undef BASE_HOMEDIR + +/* + * ALT_HOMEDIR + * You can specify a directory to which real users may still login if + * their own home directory fails either the STRICT_HOMEDIR or the + * BASE_HOMEDIR test. + */ +#undef ALT_HOMEDIR + +/* * BUFFER_SIZE * You can specify the buffer size for binary transfers; the defaults * are often far too small for efficiency. */ + #undef BUFFER_SIZE /* diff -uwrP wu-ftpd-2.6.2/configure wu-ftpd-2.6.2/configure --- wu-ftpd-2.6.2/configure 2001-11-29 18:54:27.000000000 -0500 +++ wu-ftpd-2.6.2/configure 2002-12-16 11:10:19.000000000 -0500 @@ -666,6 +666,19 @@ --disable-private don't support private files (SITE GROUP/SITE GPASS) --disable-dnsretry don't retry failed DNS lookups --enable-anononly allow only anonymous ftp connections + --enable-delete permit deletion of files" + --enable-ow-file permit overwriting of files" + --disable-strict-homedir don't perform strict checking of home directory" + --disable-site-umask don't support SITE UMASK" + --disable-site-chmod don't support SITE CHMOD" + --disable-site-idle don't support SITE IDLE" + --enable-site-exec permit SITE EXEC/SITE INDEX" + --disable-site-alias don't support SITE ALIAS" + --disable-site-groups don't support SITE GROUPS" + --disable-site-cdpath don't support SITE CDPATH" + --disable-checkmethod don't support SITE CHECKMETHOD" + --disable-checksum don't support SITE CHECKSUM" + --disable-site don't support any SITE commands" --enable-paranoid disable some "questionable" features --enable-quota add QUOTA support (if your OS supports it) --enable-pam add PAM support (needs PAM library) @@ -698,6 +711,7 @@ --disable-hidesetuid show setuid/setgid bits in internal ls --disable-mail don't allow mail on upload --enable-badclients support broken clients (see CHANGES) + --with-base-homedir=path path under which users home directories must reside" --enable-nlst-dirs allow NLST to show directories, can break mget Optional Packages: @@ -2552,6 +2566,125 @@ anononly=no fi; + +# Check whether --enable-delete or --disable-delete was given. +if test "${enable_delete+set}" = set; then + enableval="$enable_delete" + delete=$enableval +else + delete=no +fi + + +# Check whether --enable-ow-file or --disable-ow-file was given. +if test "${enable_ow_file+set}" = set; then + enableval="$enable_ow_file" + ow_file=$enableval +else + ow_file=no +fi + + +# Check whether --enable-strict-homedir or --disable-strict-homedir was given. +if test "${enable_strict_homedir+set}" = set; then + enableval="$enable_strict_homedir" + strict_homedir=$enableval +else + strict_homedir=yes +fi + + +# Check whether --enable-site-umask or --disable-site-umask was given. +if test "${enable_site_umask+set}" = set; then + enableval="$enable_site_umask" + site_umask=$enableval +else + site_umask=yes +fi + + +# Check whether --enable-site-chmod or --disable-site-chmod was given. +if test "${enable_site_chmod+set}" = set; then + enableval="$enable_site_chmod" + site_chmod=$enableval +else + site_chmod=yes +fi + + +# Check whether --enable-site-idle or --disable-site-idle was given. +if test "${enable_site_idle+set}" = set; then + enableval="$enable_site_idle" + site_idle=$enableval +else + site_idle=yes +fi + + +# Check whether --enable-site-exec or --disable-site-exec was given. +if test "${enable_site_exec+set}" = set; then + enableval="$enable_site_exec" + site_exec=$enableval +else + site_exec=no +fi + + +# Check whether --enable-site-alias or --disable-site-alias was given. +if test "${enable_site_alias+set}" = set; then + enableval="$enable_site_alias" + site_alias=$enableval +else + site_alias=yes +fi + + +# Check whether --enable-site-groups or --disable-site-groups was given. +if test "${enable_site_groups+set}" = set; then + enableval="$enable_site_groups" + site_groups=$enableval +else + site_groups=yes +fi + + +# Check whether --enable-site-cdpath or --disable-site-cdpath was given. +if test "${enable_site_cdpath+set}" = set; then + enableval="$enable_site_cdpath" + site_cdpath=$enableval +else + site_cdpath=yes +fi + + +# Check whether --enable-checkmethod or --disable-checkmethod was given. +if test "${enable_checkmethod+set}" = set; then + enableval="$enable_checkmethod" + checkmethod=$enableval +else + checkmethod=yes +fi + + +# Check whether --enable-checksum or --disable-checksum was given. +if test "${enable_checksum+set}" = set; then + enableval="$enable_checksum" + checksum=$enableval +else + checksum=yes +fi + + +# Check whether --enable-site or --disable-site was given. +if test "${enable_site+set}" = set; then + enableval="$enable_site" + site=$enableval +else + site=yes +fi + + + # Check whether --enable-paranoid or --disable-paranoid was given. if test "${enable_paranoid+set}" = set; then enableval="$enable_paranoid" @@ -2792,6 +2925,22 @@ badclients=no fi; +# Check whether --with-base-homedir or --without-base-homedir was given. +if test "${with_base_homedir+set}" = set; then + withval="$with_base_homedir" + base_homedir=$withval +else + base_homedir=no +fi + +# Check whether --with-alt-homedir or --without-alt-homedir was given. +if test "${with_alt_homedir+set}" = set; then + withval="$with_alt_homedir" + alt_homedir=$withval +else + alt_homedir=no +fi + # Check whether --with-bufsize or --without-bufsize was given. if test "${with_bufsize+set}" = set; then withval="$with_bufsize" @@ -5215,9 +5364,89 @@ EOF fi + +# 2000/07/17 Sylvain Robitaille: Ensure the "usual" paranoid behaviour. if test $paranoid = yes; then + delete=no + ow_file=no + strict_homedir=yes + site=no +fi +if test $delete = yes; then + cat >> confdefs.h <<\EOF +#define ENABLE_DELETE 1 +EOF + +fi +if test $ow_file = yes; then + cat >> confdefs.h <<\EOF +#define ENABLE_OVERWRITE 1 +EOF + +fi +if test $strict_homedir = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_STRICT_HOMEDIR 1 +EOF + +fi +if test $site_umask = no; then cat >>confdefs.h <<\EOF -#define PARANOID 1 +#define DISABLE_SITE_UMASK 1 +EOF + +fi +if test $site_chmod = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_CHMOD 1 +EOF + +fi +if test $site_idle = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_IDLE 1 +EOF + +fi +if test $site_exec = yes; then + cat >> confdefs.h <<\EOF +#define ENABLE_SITE_EXEC 1 +EOF + +fi +if test $site_alias = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_ALIAS 1 +EOF + +fi +if test $site_groups = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_GROUPS 1 +EOF + +fi +if test $site_cdpath = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_CDPATH 1 +EOF + +fi +if test $checkmethod = no; then + cat >>confdefs.h <<\EOF +#define DISABLE_SITE_CHECKMETHOD 1 +EOF + +fi +if test $checksum = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE_CHECKSUM 1 +EOF + +fi +if test $site = no; then + cat >> confdefs.h <<\EOF +#define DISABLE_SITE 1 EOF fi @@ -5896,12 +6125,24 @@ EOF fi +if test $base_homedir != no; then + cat >> confdefs.h <>confdefs.h <<\EOF #define NLST_SHOWS_DIRS 1 EOF fi +if test $alt_homedir != no; then + cat >> confdefs.h </dev/null` = x$bufsize; then cat >>confdefs.h </dev/null` = x$bufsize; then diff -uwrP wu-ftpd-2.6.2/src/extensions.c wu-ftpd-2.6.2/src/extensions.c --- wu-ftpd-2.6.2/src/extensions.c 2000-07-01 14:17:38.000000000 -0400 +++ wu-ftpd-2.6.2/src/extensions.c 2002-12-13 17:26:50.000000000 -0500 @@ -1590,7 +1590,7 @@ } /* H* fix: no deletion, period. You put a file here, I get to look at it. */ -#ifdef PARANOID +#ifndef ENABLE_DELETE pdelete = 0; #endif diff -uwrP wu-ftpd-2.6.2/src/ftpcmd.y wu-ftpd-2.6.2/src/ftpcmd.y --- wu-ftpd-2.6.2/src/ftpcmd.y 2001-11-29 12:01:38.000000000 -0500 +++ wu-ftpd-2.6.2/src/ftpcmd.y 2002-12-13 17:27:00.000000000 -0500 @@ -585,11 +585,15 @@ if (log_commands) syslog(LOG_INFO, "SITE UMASK"); +#ifndef DISABLE_SITE_UMASK if ($2) { oldmask = umask(0); (void) umask(oldmask); reply(200, "Current UMASK is %03o", oldmask); } +#else + reply(502, "%s command not implemented.", "SITE UMASK"); +#endif /* !DISABLE_SITE_UMASK */ } | SITE check_login SP UMASK SP octal_number CRLF = { @@ -599,6 +603,7 @@ if (log_commands) syslog(LOG_INFO, "SITE UMASK %03o", $6); +#ifndef DISABLE_SITE_UMASK if ($2) { /* check for umask permission */ while (getaclentry("umask", &entry) && ARG0 && ARG1 != NULL) { @@ -618,6 +623,9 @@ else reply(553, "Permission denied on server. (umask)"); } +#else + reply(502, "%s command not implemented.", "SITE UMASK"); +#endif /* !DISABLE_SITE_UMASK */ } | SITE check_login SP CHMOD SP octal_number SP pathname CRLF = { @@ -626,6 +634,7 @@ if (log_commands) syslog(LOG_INFO, "SITE CHMOD %03o %s", $6, CHECKNULL($8)); +#ifndef DISABLE_SITE_CHMOD if ($2 && $8) { /* check for chmod permission */ while (getaclentry("chmod", &entry) && ARG0 && ARG1 != NULL) { @@ -668,20 +677,28 @@ } if ($8 != NULL) free($8); +#else + reply(502, "%s command not implemented.", "SITE CHMOD"); +#endif /* !DISABLE_SITE_CHMOD */ } | SITE check_login SP IDLE CRLF = { if (log_commands) syslog(LOG_INFO, "SITE IDLE"); +#ifndef DISABLE_SITE_IDLE if ($2) reply(200, "Current IDLE time limit is %d seconds; max %d", timeout_idle, timeout_maxidle); +#else + reply(502, "%s command not implemented.", "SITE IDLE"); +#endif /* !DISABLE_SITE_IDLE */ } | SITE check_login SP IDLE SP NUMBER CRLF = { if (log_commands) syslog(LOG_INFO, "SITE IDLE %d", $6); +#ifndef DISABLE_SITE_IDLE if ($2) if ($6 < 30 || $6 > timeout_maxidle) { reply(501, @@ -692,6 +709,9 @@ timeout_idle = $6; reply(200, "Maximum IDLE time set to %d seconds", timeout_idle); } +#else + reply(502, "%s command not implemented.", "SITE IDLE"); +#endif /* !DISABLE_SITE_IDLE */ } | SITE check_login SP GROUP SP username CRLF = { @@ -778,6 +798,7 @@ } | SITE check_login SP INDEX SP STRING CRLF = { +#ifdef ENABLE_SITE_EXEC /* this is just for backward compatibility since we * thought of INDEX before we thought of EXEC */ @@ -790,14 +811,25 @@ } if ($6 != NULL) free($6); +#else + if (log_commands) + syslog(LOG_INFO, "REFUSED SITE INDEX %s", $6); + reply(502, "%s command not implemented.", "SITE INDEX"); +#endif /* ENABLE_SITE_EXEC */ } | SITE check_login SP EXEC SP STRING CRLF = { +#ifdef ENABLE_SITE_EXEC if (!restricted_user && $2 != 0 && $6 != NULL) { (void) site_exec((char *) $6); } if ($6 != NULL) free($6); +#else + if (log_commands) + syslog(LOG_INFO, "REFUSED SITE EXEC %s", $6); + reply(502, "%s command not implemented.", "SITE EXEC"); +#endif /* ENABLE_SITE_EXEC */ } | STOU check_login SP pathname CRLF @@ -927,63 +959,95 @@ = { if (log_commands) syslog(LOG_INFO, "SITE ALIAS"); +#ifndef DISABLE_SITE_ALIAS if ($2) alias((char *) NULL); +#else + reply(502, "%s command not implemented.", "SITE ALIAS"); +#endif /* !DISABLE_SITE_ALIAS */ } | SITE check_login SP ALIAS SP STRING CRLF = { if (log_commands) syslog(LOG_INFO, "SITE ALIAS %s", $6); +#ifndef DISABLE_SITE_ALIAS if ($2) alias($6); if ($6 != NULL) free($6); +#else + reply(502, "%s command not implemented.", "SITE ALIAS"); +#endif /* !DISABLE_SITE_ALIAS */ } | SITE check_login SP GROUPS CRLF = { if (log_commands) syslog(LOG_INFO, "SITE GROUPS"); +#ifndef DISABLE_SITE_GROUPS if ($2) print_groups(); +#else + reply(502, "%s command not implemented.", "SITE GROUPS"); +#endif /* !DISABLE_SITE_GROUPS */ } | SITE check_login SP CDPATH CRLF = { if (log_commands) syslog(LOG_INFO, "SITE CDPATH"); +#ifndef DISABLE_SITE_CDPATH if ($2) cdpath(); +#else + reply(502, "%s command not implemented.", "SITE CDPATH"); +#endif /* !DISABLE_SITE_CDPATH */ } | SITE check_login SP CHECKMETHOD SP method CRLF = { if (log_commands) syslog(LOG_INFO, "SITE CHECKMETHOD %s", CHECKNULL($6)); +#ifndef DISABLE_SITE_CHECKMETHOD if (($2) && ($6 != NULL)) SetCheckMethod($6); if ($6 != NULL) free($6); +#else + reply(502, "%s command not implemented.", "SITE CHECKMETHOD"); +#endif /* !DISABLE_SITE_CHECKMETHOD */ } | SITE check_login SP CHECKMETHOD CRLF = { if (log_commands) syslog(LOG_INFO, "SITE CHECKMETHOD"); +#ifndef DISABLE_SITE_CHECKMETHOD if ($2) ShowCheckMethod(); +#else + reply(502, "%s command not implemented.", "SITE CHECKMETHOD"); +#endif /* !DISABLE_SITE_CHECKMETHOD */ } | SITE check_login SP CHECKSUM SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "SITE CHECKSUM %s", CHECKNULL($6)); +#ifndef DISABLE_SITE_CHECKSUM if (($2) && ($6 != NULL) && (!restrict_check($6))) CheckSum($6); if ($6 != NULL) free($6); +#else + reply(502, "%s command not implemented.", "SITE CHECKSUM"); +#endif /* !DISABLE_SITE_CHECKSUM */ } | SITE check_login SP CHECKSUM CRLF = { if (log_commands) syslog(LOG_INFO, "SITE CHECKSUM"); +#ifndef DISABLE_SITE_CHECKSUM if ($2) CheckSumLastFile(); +#else + reply(502, "%s command not implemented.", "SITE CHECKSUM"); +#endif /* !DISABLE_SITE_CHECKSUM */ } ; @@ -1300,21 +1364,68 @@ struct tab sitetab[] = { +#ifdef DISABLE_SITE_UMASK + {"UMASK", UMASK, ARGS, 0, "[ umask ]"}, +#else {"UMASK", UMASK, ARGS, 1, "[ umask ]"}, +#endif +#ifdef DISABLE_SITE_IDLE + {"IDLE", IDLE, ARGS, 0, "[ maximum-idle-time ]"}, +#else {"IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]"}, +#endif +#ifdef DISABLE_SITE_CHMOD + {"CHMOD", CHMOD, NSTR, 0, " mode file-name"}, +#else {"CHMOD", CHMOD, NSTR, 1, " mode file-name"}, +#endif {"HELP", HELP, OSTR, 1, "[ ]"}, +#ifndef NO_PRIVATE {"GROUP", GROUP, STR1, 1, " access-group"}, {"GPASS", GPASS, OSTR, 1, " access-password"}, +#else + {"GROUP", GROUP, STR1, 0, " access-group"}, + {"GPASS", GPASS, OSTR, 0, " access-password"}, +#endif +#ifdef SITE_NEWER {"NEWER", NEWER, STR3, 1, " YYYYMMDDHHMMSS [ path-name ]"}, {"MINFO", MINFO, STR3, 1, " YYYYMMDDHHMMSS [ path-name ]"}, +#else + {"NEWER", NEWER, STR3, 0, " YYYYMMDDHHMMSS [ path-name ]"}, + {"MINFO", MINFO, STR3, 0, " YYYYMMDDHHMMSS [ path-name ]"}, +#endif +#ifdef ENABLE_SITE_EXEC {"INDEX", INDEX, STR1, 1, " pattern"}, {"EXEC", EXEC, STR1, 1, " command [ arguments ]"}, +#else + {"INDEX", INDEX, STR1, 0, " pattern"}, + {"EXEC", EXEC, STR1, 0, " command [ arguments ]"}, +#endif +#ifdef DISABLE_SITE_ALIAS + {"ALIAS", ALIAS, OSTR, 0, "[ alias ] "}, +#else {"ALIAS", ALIAS, OSTR, 1, "[ alias ] "}, +#endif +#ifdef DISABLE_SITE_CDPATH + {"CDPATH", CDPATH, OSTR, 0, "[ ] "}, +#else {"CDPATH", CDPATH, OSTR, 1, "[ ] "}, +#endif +#ifdef DISABLE_SITE_GROUPS + {"GROUPS", GROUPS, OSTR, 0, "[ ] "}, +#else {"GROUPS", GROUPS, OSTR, 1, "[ ] "}, +#endif +#ifdef DISABLE_SITE_CHECKMETHOD + {"CHECKMETHOD", CHECKMETHOD, OSTR, 0, "[ method ]"}, +#else {"CHECKMETHOD", CHECKMETHOD, OSTR, 1, "[ method ]"}, +#endif +#ifdef DISABLE_SITE_CHECKSUM + {"CHECKSUM", CHECKSUM, OSTR, 0, "[ file-name ]"}, +#else {"CHECKSUM", CHECKSUM, OSTR, 1, "[ file-name ]"}, +#endif {NULL, 0, 0, 0, 0} }; @@ -1534,14 +1645,14 @@ p = lookup(sitetab, cp); cbuf[cpos] = c; if (p != 0) { -#ifndef PARANOID /* what GOOD is SITE *, anyways?! _H */ +#ifndef DISABLE_SITE /* what GOOD is SITE *, anyways?! _H */ if (p->implemented == 0) { #else if (1) { syslog(LOG_WARNING, "refused SITE %s %s from %s of %s", p->name, &cbuf[cpos], anonymous ? guestpw : authuser, remoteident); -#endif /* PARANOID */ +#endif /* DISABLE_SITE */ state = CMD; nack(p->name); longjmp(errcatch, 0); @@ -1773,8 +1884,8 @@ register size_t i, j, w; size_t columns, lines; - lreply(214, "The following %scommands are recognized %s.", - type, "(* =>'s unimplemented)"); + lreply(214, "The following %scommands are recognized.", + type); columns = 76 / width; if (columns == 0) columns = 1; @@ -1785,6 +1896,8 @@ ptr += 3; for (j = 0; j < columns; j++) { c = ctab + j * lines + i; + if(!c->implemented) + continue; (void) sprintf(ptr, "%s%c", c->name, c->implemented ? ' ' : '*'); w = strlen(c->name) + 1; @@ -1880,8 +1993,9 @@ void site_exec(char *cmd) { -#ifdef PARANOID +#ifndef ENABLE_SITE_EXEC syslog(LOG_CRIT, "REFUSED SITE_EXEC (slipped through!!): %s", cmd); + reply(502, "%s command not implemented.", "SITE EXEC"); #else char buf[MAXPATHLEN]; char *sp = (char *) strchr(cmd, ' '), *slash, *t; @@ -1961,7 +2075,7 @@ syslog(LOG_INFO, "SITE EXEC (lines: %d): %s", lines, cmd); ftpd_pclose(cmdf); } -#endif /* PARANOID */ +#endif /* !ENABLE_SITE_EXEC */ } void alias(char *s) diff -uwrP wu-ftpd-2.6.2/src/ftpd.c wu-ftpd-2.6.2/src/ftpd.c --- wu-ftpd-2.6.2/src/ftpd.c 2001-11-29 11:56:11.000000000 -0500 +++ wu-ftpd-2.6.2/src/ftpd.c 2002-12-13 17:27:14.000000000 -0500 @@ -2157,6 +2157,44 @@ return (0); } +#ifdef BASE_HOMEDIR +/* + * 2000/07/25 Sylvain Robitaille: based on an idea and code provided by + * Gregory Lundberg. Any errors in the implementation are, of + * course, my own. + * + * check that the user's home directory is below BASE_HOMEDIR + */ + +int CheckUserHomeDirectory (const char *homedir) +{ + char base [MAXPATHLEN+1]; + char home [MAXPATHLEN]; + size_t n; + + /* + * Not likely, since we won't get called if (anonymous). + * There's no harm in redundant checking, though. + */ + if (anonymous) return 1; /* Anonymous is OK. */ + + /* Clean up so everyone's singing the same song. */ + if ((NULL == fb_realpath(BASE_HOMEDIR, base)) + || (NULL == fb_realpath(homedir, home))) + return 0; + + /* Make sure base is '/'-terminated. */ + n = strlen(base); + if ((n == 0) || (base[n-1] != '/')) { + base[n++] = '/'; + base[n] = '\0'; + } + + /* Da meat. */ + return (0 == strncmp(base, home, n)); +} +#endif + int denieduid(uid_t uid) { struct aclmember *entry = NULL; @@ -2546,7 +2584,7 @@ * this somehow a configurable item somewhere; later more on that. * * For now assume the guest (not anonymous) identity, so the site - * admins can still differentiate between the truw anonymous user and + * admins can still differentiate between the true anonymous user and * a little bit more special ones. Otherwise he wouldn't go the extra * mile to have a different user database, right? * --gaftonc */ @@ -3179,8 +3217,29 @@ } #endif if (!anonymous && !guest) { +#ifdef BASE_HOMEDIR + if (!CheckUserHomeDirectory(pw->pw_dir)) { +#ifndef ALT_HOMEDIR +#ifdef VERBOSE_ERROR_LOGING + syslog(LOG_NOTICE, "FTP LOGIN FAILED (home_base not %s) for %s, %s", + BASE_HOMEDIR, remoteident, pw->pw_name); +#endif + reply(530, "User %s: home directory %s not under %s.", + pw->pw_name, pw->pw_dir, BASE_HOMEDIR); + goto bad; +#else /* ALT_HOMEDIR defined */ +#ifdef VERBOSE_ERROR_LOGING + syslog(LOG_NOTICE, "home dir not under %s for %s, %s; using %s", + BASE_HOMEDIR, remoteident, pw->pw_name, ALT_HOMEDIR); +#endif + lreply(230, "Bad directory! Logging in with home=%s",ALT_HOMEDIR); + pw->pw_dir = ALT_HOMEDIR; +#endif /* ALT_HOMEDIR */ + } +#endif /* BASE_HOMEDIR */ if (chdir(pw->pw_dir) < 0) { -#ifdef PARANOID +#ifndef DISABLE_STRICT_HOMEDIR +#ifndef ALT_HOMEDIR #ifdef VERBOSE_ERROR_LOGING syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s", remoteident, pw->pw_name); @@ -3188,7 +3247,23 @@ reply(530, "User %s: can't change directory to %s.", pw->pw_name, pw->pw_dir); goto bad; -#else +#else /* ALT_HOMEDIR is defined */ +#ifdef VERBOSE_ERROR_LOGING + syslog(LOG_NOTICE, "Can't chdir to %s for %s, %s; using %s", + pw->pw_dir, remoteident, pw->pw_name, ALT_HOMEDIR); +#endif + lreply(230, "No directory! Logging in with home=%s",ALT_HOMEDIR); + if (chdir(ALT_HOMEDIR) < 0) { +#ifdef VERBOSE_ERROR_LOGING + syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir to %s) for %s, %s", + ALT_HOMEDIR, remoteident, pw->pw_name); +#endif + reply(530, "User %s: can't change to alternate directory %s.", + pw->pw_name, ALT_HOMEDIR); + goto bad; + } +#endif /* ALT_HOMEDIR */ +#else /* DISABLE_STRICT_HOMEDIR is defined */ if (chdir("/") < 0) { #ifdef VERBOSE_ERROR_LOGING syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s", @@ -3204,7 +3279,7 @@ home = defhome; #endif } -#endif +#endif /* !DISABLE_STRICT_HOMEDIR */ } } @@ -4420,7 +4495,7 @@ } } -#ifdef PARANOID +#ifndef ENABLE_OVERWRITE overwrite = 0; #endif if (!stat(name, &st)) @@ -5873,7 +5948,7 @@ char realfrom[MAXPATHLEN]; char realto[MAXPATHLEN]; struct aclmember *entry = NULL; -#ifdef PARANOID +#ifndef ENABLE_OVERWRITE struct stat st; #endif wu_realpath(from, realfrom, chroot_path); @@ -5918,7 +5993,7 @@ } -#ifdef PARANOID +#ifndef ENABLE_OVERWRITE /* Almost forgot about this. Don't allow renaming TO existing files -- otherwise someone can rename "trivial" to "warez", and "warez" is gone! XXX: This part really should do the same "overwrite" check as store(). */ diff -uwrP wu-ftpd-2.6.2/src/proto.h wu-ftpd-2.6.2/src/proto.h --- wu-ftpd-2.6.2/src/proto.h 2000-07-01 14:17:39.000000000 -0400 +++ wu-ftpd-2.6.2/src/proto.h 2002-12-13 17:27:21.000000000 -0500 @@ -150,6 +150,7 @@ char *skey_challenge(char *name, struct passwd *pwd, int pwok); void user(char *name); int checkuser(char *name); +int CheckUserHomeDirectory (const char *homedir); int denieduid(uid_t uid); int alloweduid(uid_t uid); int deniedgid(gid_t gid);