diff options
| author | Yaroslav Tykhiy <ytykhiy@gmail.com> | 2003-01-29 10:07:27 +0000 |
|---|---|---|
| committer | Yaroslav Tykhiy <ytykhiy@gmail.com> | 2003-01-29 10:07:27 +0000 |
| commit | ce9287fc02f73645761e9cd5fbcf8f5f8246dc7a (patch) | |
| tree | 8fde0f8caa19168edffd0451d6616eaaf5c4e9b3 /libexec/ftpd/ftpd.c | |
| parent | 76499f1539799ff3150668ad4abcd7951ba58053 (diff) | |
Notes
Diffstat (limited to 'libexec/ftpd/ftpd.c')
| -rw-r--r-- | libexec/ftpd/ftpd.c | 105 |
1 files changed, 72 insertions, 33 deletions
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 8d6d1181aa7e..3d60f42bc12b 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -118,6 +118,7 @@ int data; int dataport; int logged_in; struct passwd *pw; +char *homedir; int ftpdebug; int timeout = 900; /* timeout after 15 minutes of inactivity */ int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ @@ -1349,6 +1350,7 @@ pass(char *passwd) #ifdef USE_PAM int e; #endif + char *chrootdir; char *residue = NULL; char *xpasswd; @@ -1471,50 +1473,79 @@ skip: || login_getcapbool(lc, "ftp-chroot", 0) #endif ; - if (guest) { + chrootdir = NULL; + /* + * For a chrooted local user, + * a) see whether ftpchroot(5) specifies a chroot directory, + * b) extract the directory pathname from the line, + * c) expand it to the absolute pathname if necessary. + */ + if (dochroot && residue && + (chrootdir = strtok(residue, " \t")) != NULL && + chrootdir[0] != '/') { + asprintf(&chrootdir, "%s/%s", pw->pw_dir, chrootdir); + if (chrootdir == NULL) + fatalerror("Ran out of memory."); + + } + if (guest || dochroot) { /* - * We MUST do a chdir() after the chroot. Otherwise - * the old current directory will be accessible as "." - * outside the new root! + * If no chroot directory set yet, use the login directory. + * Copy it so it can be modified while pw->pw_dir stays intact. */ - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't set guest privileges."); - goto bad; - } - } else if (dochroot) { - char *chrootdir = NULL; - - if (residue && - (chrootdir = strtok(residue, " \t")) != NULL && - chrootdir[0] != '/') { - asprintf(&chrootdir, "%s/%s", pw->pw_dir, chrootdir); - if (chrootdir == NULL) + if (chrootdir == NULL && + (chrootdir = strdup(pw->pw_dir)) == NULL) + fatalerror("Ran out of memory."); + /* + * Check for the "/chroot/./home" syntax, + * separate the chroot and home directory pathnames. + */ + if ((homedir = strstr(chrootdir, "/./")) != NULL) { + *(homedir++) = '\0'; /* wipe '/' */ + homedir++; /* skip '.' */ + /* so chrootdir can be freed later */ + if ((homedir = strdup(homedir)) == NULL) fatalerror("Ran out of memory."); - free(residue); - residue = chrootdir; + } else { + /* + * We MUST do a chdir() after the chroot. Otherwise + * the old current directory will be accessible as "." + * outside the new root! + */ + homedir = "/"; } - if (chrootdir == NULL) - chrootdir = pw->pw_dir; - if (chroot(chrootdir) < 0 || chdir("/") < 0) { + /* + * Finally, do chroot() + */ + if (chroot(chrootdir) < 0) { reply(550, "Can't change root."); - if (residue) - free(residue); goto bad; } - if (residue) - free(residue); - } else if (chdir(pw->pw_dir) < 0) { - if (chdir("/") < 0) { - reply(530, "User %s: can't change directory to %s.", - pw->pw_name, pw->pw_dir); - goto bad; - } else - lreply(230, "No directory! Logging in with home=/"); - } + } else /* real user w/o chroot */ + homedir = pw->pw_dir; + /* + * Set euid *before* doing chdir() so + * a) the user won't be carried to a directory that he couldn't reach + * on his own due to no permission to upper path components, + * b) NFS mounted homedirs w/restrictive permissions will be accessible + * (uid 0 has no root power over NFS if not mapped explicitly.) + */ if (seteuid((uid_t)pw->pw_uid) < 0) { reply(550, "Can't set uid."); goto bad; } + if (chdir(homedir) < 0) { + if (guest || dochroot) { + reply(550, "Can't change to base directory."); + goto bad; + } else { + if (chdir("/") < 0) { + reply(550, "Root is inaccessible."); + goto bad; + } + lreply(230, "No directory! Logging in with home=/"); + } + } /* * Display a login message, if it exists. @@ -1577,12 +1608,20 @@ skip: #ifdef LOGIN_CAP login_close(lc); #endif + if (chrootdir) + free(chrootdir); + if (residue) + free(residue); return; bad: /* Forget all about it... */ #ifdef LOGIN_CAP login_close(lc); #endif + if (chrootdir) + free(chrootdir); + if (residue) + free(residue); end_login(); } |
