📄 ftpd.c
字号:
addreply_noformat(530, MSG_WHOAREYOU); return; } authresult = pw_check(account, password, &ctrlconn, &peer); { /* Clear password from memory, paranoia */ register volatile char *password_ = (volatile char *) password; while (*password_ != 0) { *password_++ = 0; } } if (authresult.auth_ok != 1) { addreply_noformat(530, MSG_AUTH_FAILED); doreply(); if (tapping >= MAX_PASSWD_TRIES) { toomanytries: logfile(LOG_ERR, MSG_AUTH_TOOMANY); _EXIT(EXIT_FAILURE); } logfile(LOG_WARNING, MSG_AUTH_FAILED_LOG, account); randomsleep: tapping++; usleep2((unsigned long) (zrand() % PASSWD_FAILURE_DELAY)); usleep2(tapping * PASSWD_FAILURE_DELAY); return; } if (authresult.uid < useruid) { logfile(LOG_WARNING, MSG_ACCOUNT_DISABLED, account); if (tapping >= MAX_PASSWD_TRIES) { goto toomanytries; } addreply_noformat(530, MSG_NOTRUST); goto randomsleep; }#ifdef PER_USER_LIMITS if (per_user_max > 0U && ftpwho_read_count(account) >= per_user_max) { addreply(421, MSG_PERUSER_MAX, (unsigned long) per_user_max); doreply(); _EXIT(1); }#endif /* Add username to the uid/name cache */ (void) getname(authresult.uid); if (#if defined(WITH_LDAP) || defined(WITH_MYSQL) || defined(WITH_PGSQL) || defined(WITH_PUREDB) || defined(WITH_EXTAUTH) doinitsupgroups(NULL, authresult.uid, authresult.gid) != 0#else doinitsupgroups(account, (uid_t) -1, authresult.gid) != 0#endif ) {#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) (void) 0;#else die(421, LOG_WARNING, MSG_NOTRUST);#endif } /* handle /home/user/./public_html form */ if ((root_directory = strdup(authresult.dir)) == NULL) { die_mem(); } hd = strstr(root_directory, "/./"); if (hd != NULL) { *++hd = 0; hd++; if (chrooted != 0) { die(421, LOG_DEBUG, MSG_CANT_DO_TWICE); } if (create_home_and_chdir(root_directory) || chroot(root_directory) || chdir(hd)) { die(421, LOG_ERR, MSG_NO_HOMEDIR); } chrooted = 1;#ifdef RATIOS if (ratio_for_non_anon == 0) { ratio_upload = ratio_download = 0U; } if (check_trustedgroup(authresult.uid, authresult.gid) != 0) { dot_write_ok = dot_read_ok = 1; ratio_upload = ratio_download = 0U; keepallfiles = 0; }#endif } else { (void) free(root_directory); root_directory = (char *) "/"; if (create_home_and_chdir(authresult.dir)) { /* non-chrooted users can see everything, so let them in anyway */ if (userchroot == 0) { addreply(0, MSG_NO_HOMEDIR2 " [%s].", authresult.dir, strerror(errno)); addreply_noformat(0, MSG_START_SLASH); chdir("/"); } else { die(421, LOG_ERR, MSG_NO_HOMEDIR); } } } if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) { wd[0] = '/'; wd[1] = 0; }#ifdef HAVE_SYS_FSUID_H setfsuid(authresult.uid);#endif#ifndef NON_ROOT_FTP if (setgid(authresult.gid) || setegid(authresult.gid)) { _EXIT(EXIT_FAILURE); }# ifndef HAVE_SYS_FSUID_H if (seteuid(authresult.uid) != 0) { _EXIT(EXIT_FAILURE); }# endif#endif if (check_trustedgroup(authresult.uid, authresult.gid) != 0) { userchroot = 0; dot_write_ok = dot_read_ok = 1; keepallfiles = 0;#ifdef RATIOS ratio_upload = ratio_download = 0U;#endif#ifdef QUOTAS user_quota_files = user_quota_size = ULONG_LONG_MAX;#endif }#ifdef QUOTAS if (hasquota() == 0) { userchroot = 1; }#endif if (loggedin == 0) { candownload = 1; /* real users can always download */ }#ifdef THROTTLING if ((throttling == 2) || (guest != 0 && throttling == 1)) { addreply_noformat(0, MSG_BANDWIDTH_RESTRICTED); nice(NICE_VALUE); } else { throttling_delay = throttling_bandwidth_dl = throttling_bandwidth_ul = 0UL; }#endif#if !defined(MINIMAL) && defined(HAVE_GETGROUPS)# ifdef SAFE_GETGROUPS_0 ngroups = getgroups(0, NULL); if (ngroups > ngroups_max) { ngroups_max = ngroups; }# elif defined(_SC_NGROUPS_MAX) /* get the run time value */ ngroups = (int) sysconf(_SC_NGROUPS_MAX); if (ngroups > ngroups_max) { ngroups_max = ngroups; } # endif if ((groups = malloc(sizeof(GETGROUPS_T) * ngroups_max)) == NULL) { die_mem(); } ngroups = getgroups(ngroups_max, groups); if (guest == 0 && ngroups > 0) { size_t p; const char *q; char reply[80]; if (SNCHECK(snprintf(reply, sizeof reply, MSG_USER_GROUP_ACCESS ": ", account), sizeof reply)) { _EXIT(EXIT_FAILURE); } p = strlen(reply); do { ngroups--; if ((ngroups != 0 && groups[ngroups] == groups[0]) || (q = getgroup(groups[ngroups])) == NULL) { continue; } if (p + strlen(q) > 75) { reply[p] = 0; addreply(0, "%s", reply); *reply = 0; p = (size_t) 0U; } reply[p++] = ' '; while (*q != 0 && p < sizeof reply) { reply[p++] = *q++; } } while (ngroups > 0); reply[p] = 0; addreply(0, "%s", reply); } free(groups);#endif if (guest == 0 && allowfxp == 1) { addreply_noformat(0, MSG_FXP_SUPPORT); }#ifdef RATIOS if (ratio_for_non_anon != 0 && ratio_upload > 0) { addreply(0, MSG_RATIO, ratio_upload, ratio_download); }#endif if (userchroot != 0 && chrooted == 0) {#ifndef NON_ROOT_FTP# ifndef HAVE_SYS_FSUID_H disablesignals(); seteuid((uid_t) 0);# endif#endif if (chdir(wd) || chroot(wd)) { /* should never fail */#ifdef WITH_PRIVSEP (void) setuid(authresult.uid); (void) seteuid(authresult.uid);#else# ifndef HAVE_SYS_FSUID_H# ifndef NON_ROOT_FTP (void) seteuid(authresult.uid);# endif# endif#endif die(421, LOG_ERR, MSG_CHROOT_FAILED); }#ifdef WITH_PRIVSEP if (setuid(authresult.uid) != 0 || seteuid(authresult.uid) != 0) { _EXIT(EXIT_FAILURE); } enablesignals(); #else# ifndef NON_ROOT_FTP# ifndef HAVE_SYS_FSUID_H if (seteuid(authresult.uid) != 0) { _EXIT(EXIT_FAILURE); } enablesignals();# endif# endif#endif#ifdef USE_CAPABILITIES drop_login_caps();#endif chrooted = 1;#ifdef RATIOS if (ratio_for_non_anon == 0) { ratio_upload = ratio_download = 0U; }#endif { const size_t rd_len = strlen(wd) + sizeof "/"; if ((root_directory = malloc(rd_len)) == NULL) { die_mem(); } snprintf(root_directory, rd_len, "%s/", wd); } wd[0] = '/'; wd[1] = 0; if (chdir(wd)) { _EXIT(EXIT_FAILURE); } addreply(230, MSG_CURRENT_RESTRICTED_DIR_IS, wd); } else { addreply(230, MSG_CURRENT_DIR_IS, wd); } logfile(LOG_INFO, MSG_IS_NOW_LOGGED_IN, account);#ifdef FTPWHO if (shm_data_cur != NULL) { ftpwho_lock(); strncpy(shm_data_cur->account, account, sizeof shm_data_cur->account - (size_t) 1U); shm_data_cur->account[sizeof shm_data_cur->account - 1U] = 0; ftpwho_unlock(); state_needs_update = 1; }#endif loggedin = 1; if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) { wd[0] = '/'; wd[1] = 0; }#ifndef MINIMAL dobanner(0);#endif#ifdef QUOTAS displayquota(NULL);#endif}void docwd(const char *dir){#ifndef MINIMAL static unsigned long failures = 0UL;#endif const char *where; char buffer[MAXPATHLEN + 256U]; if (loggedin == 0) { goto kaboom; } /* * secure and conformant tilde expansion routine. Need to be packaged in * a function so that it can be called in other commands and avoid * duplicate code in ls.c -frank. */ where = dir; if (dir == NULL || *dir == 0) { goto gohome; } if (*dir == '~') { const struct passwd *pw; if (dir[1] == 0) { /* cd ~ */ gohome: strncpy(buffer, chrooted != 0 ? "/" : authresult.dir, sizeof buffer); buffer[sizeof buffer - (size_t) 1U] = 0; where = buffer; } else { /* cd ~user or cd ~user/ */ char *bufpnt = buffer; size_t s = sizeof buffer; const char *dirscan = dir + 1; while (*dirscan != 0 && *dirscan != '/') { if (--s <= 0) { goto kaboom; /* script kiddy's playing */ } *bufpnt++ = *dirscan++; } *bufpnt = 0; if (*buffer == 0) { /* ~/... */ snprintf(buffer, sizeof buffer, "%s%s", chrooted != 0 ? "/" : authresult.dir, dirscan); where = buffer; } else if (authresult.slow_tilde_expansion == 0) { if (chrooted != 0 || guest != 0 || (pw = getpwnam(buffer)) == NULL || pw->pw_dir == NULL) { /* try with old where = dir */ } else { snprintf(buffer, sizeof buffer, "%s%s", pw->pw_dir, dirscan); where = buffer; } } } } if (checknamesanity(where, dot_read_ok) != 0) { addreply(550, MSG_SANITY_FILE_FAILURE, where); return; } if (chdir(where) != 0) { #ifdef WITH_DIRALIASES const int real_errno = errno; const char *where_alias; if ((where_alias = lookup_alias(where)) == NULL || chdir(where_alias) != 0) { errno = real_errno; } else { goto chdir_success; }#endif if (SNCHECK(snprintf(buffer, sizeof buffer, MSG_CANT_CHANGE_DIR ": %s", dir, strerror(errno)), sizeof buffer)) { _EXIT(EXIT_FAILURE); } logfile(LOG_INFO, "%s", buffer); addreply(550, "%s", buffer); #ifndef MINIMAL# ifndef NO_DIRSCAN_DELAY if (failures >= MAX_DIRSCAN_TRIES) { _EXIT(EXIT_FAILURE); } usleep2(failures * DIRSCAN_FAILURE_DELAY); failures++;# endif#endif return; } #ifdef WITH_DIRALIASES chdir_success:#endif #ifndef MINIMAL failures = 0UL; dobanner(1);#endif if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) { if (*dir == '/') { if (SNCHECK(snprintf(wd, sizeof wd, "%s", dir), sizeof wd)) { /* already checked */ _EXIT(EXIT_FAILURE); } } else { if (SNCHECK(snprintf(wd, sizeof wd, "%s/%s", wd, dir), sizeof wd)) { kaboom: die(421, LOG_ERR, MSG_PATH_TOO_LONG); } } } addreply(250, MSG_CURRENT_DIR_IS, wd);}static void iptropize(const struct sockaddr_storage *ss){ size_t t = sizeof *ss; register const unsigned char *s = (const unsigned char *) ss; iptropy = getpid(); do { iptropy += (iptropy << 5); iptropy ^= (int) *s++; } while (--t > 0U);}#ifdef PROBE_RANDOM_AT_RUNTIMEstatic void pw_zrand_probe(void){ static const char * const devices[] = { "/dev/arandom", "/dev/urandom", "/dev/random", NULL }; register const char * const *device = devices; do { if (access(*device, F_OK | R_OK) == 0) { random_device = *device; break; } device++; } while (*device != NULL);}#endifunsigned int zrand(void){ int fd; int ret; if (chrooted != 0 ||#ifdef PROBE_RANDOM_AT_RUNTIME ((fd = open(random_device, O_RDONLY | O_NONBLOCK)) == -1) #elif defined(HAVE_DEV_ARANDOM) ((fd = open("/dev/arandom", O_RDONLY | O_NONBLOCK)) == -1)#elif defined(HAVE_DEV_URANDOM) ((fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK)) == -1)#else ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) == -1)#endif ) { nax:#ifdef HAVE_RANDOM return (unsigned int) (random() ^ iptropy); #else return (unsigned int) (rand() ^ iptropy);#endif } if (read(fd, &ret, sizeof ret) != (ssize_t) sizeof ret) { (void) close(fd); goto nax; } (void) close(fd); return (unsigned int) (ret ^ iptropy);}static void keepalive(const int fd, int keep){#ifdef SO_KEEPALIVE { setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *) &keep, sizeof keep); }#endif#ifdef SO_LINGER { struct linger li; li.l_onoff = li.l_linger = 0; setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof li); }#endif}/* psvtype = 0: PASV *//* psvtype = 1: EPSV *//* psvtype = 2: SPSV */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -