?? ftpd_c.txt
字號:
union sockunion tmp_addr;
const int off = sizeof(struct in6_addr) - sizeof(struct in_addr);
tmp_addr = his_addr;
memset(&his_addr, 0, sizeof(his_addr));
his_addr.su_sin.sin_family = AF_INET;
his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
memcpy(&his_addr.su_sin.sin_addr,
&tmp_addr.su_sin6.sin6_addr.s6_addr[off],
his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
tmp_addr = ctrl_addr;
memset(&ctrl_addr, 0, sizeof(ctrl_addr));
ctrl_addr.su_sin.sin_family = AF_INET;
ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
memcpy(&ctrl_addr.su_sin.sin_addr,
&tmp_addr.su_sin6.sin6_addr.s6_addr[off],
sizeof(ctrl_addr.su_sin.sin_addr));
ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
#else
while (fgets(line, sizeof(line), fd) != NULL) {
line[strcspn(line, "\n")] = '\0';
lreply(530, "%s", line);
}
(void) fflush(stdout);
(void) close(fd);
reply(530,
"Connection from IPv4 mapped address is not supported.");
exit(0);
#endif
}
#ifdef IP_TOS
if (his_addr.su_family == AF_INET) {
tos = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, &tos,
sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
}
#endif
data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
/* Try to handle urgent data inline */
#ifdef SO_OOBINLINE
if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) < 0)
syslog(LOG_ERR, "setsockopt: %m");
#endif
dolog((struct sockaddr *)&his_addr);
/*
* Set up default state
*/
data = -1;
type = TYPE_A;
form = FORM_N;
stru = STRU_F;
mode = MODE_S;
tmpline[0] = '\0';
/* If logins are disabled, print out the message. */
if ((fp = fopen(_PATH_NOLOGIN, "r")) != NULL) {
while (fgets(line, sizeof(line), fp) != NULL) {
line[strcspn(line, "\n")] = '\0';
lreply(530, "%s", line);
}
(void) fflush(stdout);
(void) fclose(fp);
reply(530, "System not available.");
exit(0);
}
if ((fp = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
while (fgets(line, sizeof(line), fp) != NULL) {
line[strcspn(line, "\n")] = '\0';
lreply(220, "%s", line);
}
(void) fflush(stdout);
(void) fclose(fp);
/* reply(220,) must follow */
}
(void) gethostname(hostname, sizeof(hostname));
/* Make sure hostname is fully qualified. */
hp = gethostbyname(hostname);
if (hp != NULL)
strlcpy(hostname, hp->h_name, sizeof(hostname));
if (multihome) {
error = getnameinfo((struct sockaddr *)&ctrl_addr,
ctrl_addr.su_len, dhostname, sizeof(dhostname), NULL, 0, 0);
}
if (error != 0)
reply(220, "FTP server ready.");
else
reply(220, "%s FTP server ready.",
(multihome ? dhostname : hostname));
monitor_init();
for (;;)
(void) yyparse();
/* NOTREACHED */
}
/*
* Signal handlers.
*/
/*ARGSUSED*/
static void
lostconn(int signo)
{
struct syslog_data sdata = SYSLOG_DATA_INIT;
sdata.log_fac = LOG_FTP;
if (debug)
syslog_r(LOG_DEBUG, &sdata, "lost connection");
dologout(1);
}
static void
sigquit(int signo)
{
struct syslog_data sdata = SYSLOG_DATA_INIT;
sdata.log_fac = LOG_FTP;
syslog_r(LOG_DEBUG, &sdata, "got signal %s", sys_signame[signo]);
dologout(1);
}
/*
* Save the result of a getpwnam. Used for USER command, since
* the data returned must not be clobbered by any other command
* (e.g., globbing).
*/
static struct passwd *
sgetpwnam(char *name, struct passwd *pw)
{
static struct passwd *save;
struct passwd *old;
if (pw == NULL && (pw = getpwnam(name)) == NULL)
return (NULL);
old = save;
save = pw_dup(pw);
if (save == NULL) {
perror_reply(421, "Local resource failure: malloc");
dologout(1);
/* NOTREACHED */
}
if (old) {
memset(old->pw_passwd, 0, strlen(old->pw_passwd));
free(old);
}
return (save);
}
static int login_attempts; /* number of failed login attempts */
static int askpasswd; /* had user command, ask for passwd */
static char curname[MAXLOGNAME]; /* current USER name */
/*
* USER command.
* Sets global passwd pointer pw if named account exists and is acceptable;
* sets askpasswd if a PASS command is expected. If logged in previously,
* need to reset state. If name is "ftp" or "anonymous", the name is not in
* _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
* If account doesn't exist, ask for passwd anyway. Otherwise, check user
* requesting login privileges. Disallow anyone who does not have a standard
* shell as returned by getusershell(). Disallow anyone mentioned in the file
* _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
*/
void
user(char *name)
{
char *cp, *shell, *style, *host;
char *class = NULL;
if (logged_in) {
kill_slave("user already logged in");
end_login();
}
/* Close session from previous user if there was one. */
if (as) {
auth_close(as);
as = NULL;
}
if (lc) {
login_close(lc);
lc = NULL;
}
if ((style = strchr(name, ':')) != NULL)
*style++ = 0;
guest = 0;
host = multihome ? dhostname : hostname;
if (anon_ok &&
(strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0)) {
if (checkuser(_PATH_FTPUSERS, "ftp") ||
checkuser(_PATH_FTPUSERS, "anonymous"))
reply(530, "User %s access denied.", name);
else if ((pw = sgetpwnam("ftp", NULL)) != NULL) {
guest = 1;
askpasswd = 1;
lc = login_getclass(pw->pw_class);
if ((as = auth_open()) == NULL ||
auth_setpwd(as, pw) != 0 ||
auth_setoption(as, "FTPD_HOST", host) < 0) {
if (as) {
auth_close(as);
as = NULL;
}
login_close(lc);
lc = NULL;
reply(421, "Local resource failure");
return;
}
reply(331,
"Guest login ok, send your email address as password.");
} else
reply(530, "User %s unknown.", name);
if (!askpasswd && logging)
syslog(LOG_NOTICE,
"ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
return;
}
shell = _PATH_BSHELL;
if ((pw = sgetpwnam(name, NULL))) {
class = pw->pw_class;
if (pw->pw_shell != NULL && *pw->pw_shell != '\0')
shell = pw->pw_shell;
while ((cp = getusershell()) != NULL)
if (strcmp(cp, shell) == 0)
break;
shell = cp;
endusershell();
}
/* Get login class; if invalid style treat like unknown user. */
lc = login_getclass(class);
if (lc && (style = login_getstyle(lc, style, "auth-ftp")) == NULL) {
login_close(lc);
lc = NULL;
pw = NULL;
}
/* Do pre-authentication setup. */
if (lc && ((as = auth_open()) == NULL ||
(pw != NULL && auth_setpwd(as, pw) != 0) ||
auth_setitem(as, AUTHV_STYLE, style) < 0 ||
auth_setitem(as, AUTHV_CLASS, class) < 0 ||
auth_setoption(as, "login", "yes") < 0 ||
auth_setoption(as, "notickets", "yes") < 0 ||
auth_setoption(as, "FTPD_HOST", host) < 0)) {
if (as) {
auth_close(as);
as = NULL;
}
login_close(lc);
lc = NULL;
reply(421, "Local resource failure");
return;
}
if (logging)
strlcpy(curname, name, sizeof(curname));
dochroot = (lc && login_getcapbool(lc, "ftp-chroot", 0)) ||
checkuser(_PATH_FTPCHROOT, name);
if (anon_only && !dochroot) {
if (anon_ok)
reply(530, "Sorry, only anonymous ftp allowed.");
else
reply(530, "User %s access denied.", name);
return;
}
if (pw) {
if ((!shell && !dochroot) || checkuser(_PATH_FTPUSERS, name)) {
reply(530, "User %s access denied.", name);
if (logging)
syslog(LOG_NOTICE,
"FTP LOGIN REFUSED FROM %s, %s",
remotehost, name);
pw = NULL;
return;
}
}
if (as != NULL && (cp = auth_challenge(as)) != NULL)
reply(331, "%s", cp);
else
reply(331, "Password required for %s.", name);
askpasswd = 1;
/*
* Delay before reading passwd after first failed
* attempt to slow down passwd-guessing programs.
*/
if (login_attempts)
sleep((unsigned) login_attempts);
}
/*
* Check if a user is in the file "fname"
*/
static int
checkuser(char *fname, char *name)
{
FILE *fp;
int found = 0;
char *p, line[BUFSIZ];
if ((fp = fopen(fname, "r")) != NULL) {
while (fgets(line, sizeof(line), fp) != NULL)
if ((p = strchr(line, '\n')) != NULL) {
*p = '\0';
if (line[0] == '#')
continue;
if (strcmp(line, name) == 0) {
found = 1;
break;
}
}
(void) fclose(fp);
}
return (found);
}
/*
* Terminate login as previous user, if any, resetting state;
* used when USER command is given or login fails.
*/
static void
end_login(void)
{
sigprocmask (SIG_BLOCK, &allsigs, NULL);
if (logged_in) {
ftpdlogwtmp(ttyline, "", "");
if (doutmp)
ftpd_logout(utmp.ut_line);
}
reply(530, "Please reconnect to work as another user");
_exit(0);
}
enum auth_ret
pass(char *passwd)
{
int authok;
unsigned int flags;
FILE *fp;
static char homedir[MAXPATHLEN];
char *motd, *dir, rootdir[MAXPATHLEN];
size_t sz_pw_dir;
if (logged_in || askpasswd == 0) {
reply(503, "Login with USER first.");
return (AUTH_FAILED);
}
askpasswd = 0;
if (!guest) { /* "ftp" is only account allowed no password */
authok = 0;
if (pw == NULL || pw->pw_passwd[0] == '\0') {
useconds_t us;
/* Sleep between 1 and 3 seconds to emulate a crypt. */
us = arc4random_uniform(3000000);
usleep(us);
if (as != NULL) {
auth_close(as);
as = NULL;
}
} else {
authok = auth_userresponse(as, passwd, 0);
as = NULL;
}
if (authok == 0) {
reply(530, "Login incorrect.");
if (logging)
syslog(LOG_NOTICE,
"FTP LOGIN FAILED FROM %s, %s",
remotehost, curname);
pw = NULL;
if (login_attempts++ >= 5) {
syslog(LOG_NOTICE,
"repeated login failures from %s",
remotehost);
kill_slave("repeated login failures");
_exit(0);
}
return (AUTH_FAILED);
}
} else if (lc != NULL) {
/* Save anonymous' password. */
if (guestpw != NULL)
free(guestpw);
guestpw = strdup(passwd);
if (guestpw == NULL) {
kill_slave("out of mem");
fatal("Out of memory.");
}
authok = auth_approval(as, lc, pw->pw_name, "ftp");
auth_close(as);
as = NULL;
if (authok == 0) {
syslog(LOG_INFO|LOG_AUTH,
"FTP LOGIN FAILED (HOST) as %s: approval failure.",
pw->pw_name);
reply(530, "Approval failure.");
kill_slave("approval failure");
_exit(0);
}
} else {
syslog(LOG_INFO|LOG_AUTH,
"FTP LOGIN CLASS %s MISSING for %s: approval failure.",
pw->pw_class, pw->pw_name);
reply(530, "Permission denied.");
kill_slave("permission denied");
_exit(0);
}
if (monitor_post_auth() == 1) {
/* Post-auth monitor process */
logged_in = 1;
return (AUTH_MONITOR);
}
login_attempts = 0; /* this time successful */
/* set umask via setusercontext() unless -u flag was given. */
flags = LOGIN_SETGROUP|LOGIN_SETPRIORITY|LOGIN_SETRESOURCES;
if (umaskchange)
flags |= LOGIN_SETUMASK;
else
(void) umask(defumask);
if (setusercontext(lc, pw, (uid_t)0, flags) != 0) {
perror_reply(451, "Local resource failure: setusercontext");
syslog(LOG_NOTICE, "setusercontext: %m");
dologout(1);
/* NOTREACHED */
}
/* open wtmp before chroot */
ftpdlogwtmp(ttyline, pw->pw_name, remotehost);
/* open utmp before chroot */
if (doutmp) {
memset((void *)&utmp, 0, sizeof(utmp));
(void)time(&utmp.ut_time);
(void)strncpy(utmp.ut_name, pw->pw_name, sizeof(utmp.ut_name));
(void)strncpy(utmp.ut_host, remotehost, sizeof(utmp.ut_host));
(void)strncpy(utmp.ut_line, ttyline, sizeof(utmp.ut_line));
ftpd_login(&utmp);
}
/* open stats file before chroot */
if (guest && (stats == 1) && (statfd < 0))
if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0)
stats = 0;
logged_in = 1;
if ((dir = login_getcapstr(lc, "ftp-dir", NULL, NULL))) {
char *newdir;
newdir = copy_dir(dir, pw);
if (newdir == NULL) {
perror_reply(421, "Local resource failure: malloc");
dologout(1);
/* NOTREACHED */
}
pw->pw_dir = newdir;
pw = sgetpwnam(NULL, pw);
free(dir);
free(newdir);
}
/* make sure pw->pw_dir is big enough to hold "/" */
sz_pw_dir = strlen(pw->pw_dir) + 1;
if (sz_pw_dir < 2) {
pw->pw_dir = "/";
pw = sgetpwnam(NULL, pw);
sz_pw_dir = 2;
}
if (guest || dochroot) {
if (multihome && guest) {
struct stat ts;
/* Compute root directory. */
snprintf(rootdir, sizeof(rootdir), "%s/%s",
pw->pw_dir, dhostname);
if (stat(rootdir, &ts) < 0) {
snprintf(rootdir, sizeof(rootdir), "%s/%s",
pw->pw_dir, hostname);
}
} else
strlcpy(rootdir, pw->pw_dir, sizeof(rootdir));
}
if (guest) {
/*
* We MUST do a chdir() after the chroot. Otherwise
* the old current directory will be accessible as "."
* outside the new root!
*/
if (chroot(rootdir) < 0 || chdir("/") < 0) {
reply(550, "Can't set guest privileges.");
goto bad;
}
strlcpy(pw->pw_dir, "/", sz_pw_dir);
if (setenv("HOME", "/", 1) == -1) {
reply(550, "Can't setup environment.");
goto bad;
}
} else if (dochroot) {
if (chroot(rootdir) < 0 || chdir("/") < 0) {
reply(550, "Can't change root.");
goto bad;
}
strlcpy(pw->pw_dir, "/", sz_pw_dir);
if (setenv("HOME", "/", 1) == -1) {
reply(550, "Can't setup environment.");
goto bad;
}
} 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=/");
}
if (setegid(pw->pw_gid) < 0 || setgid(pw->pw_gid) < 0) {
reply(550, "Can't set gid.");
goto bad;
}
if (seteuid(pw->pw_uid) < 0 || setuid(pw->pw_uid) < 0) {
reply(550, "Can't set uid.");
goto bad;
}
sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
/*
* Set home directory so that use of ~ (tilde) works correctly.
*/
if (getcwd(homedir, MAXPATHLEN) != NULL) {
if (setenv("HOME", homedir, 1) == -1) {
reply(550, "Can't setup environment.");
goto bad;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -