📄 ftpd.c
字号:
#define MLST_BEGIN "Begin" CRLFvoid domlst(const char * const file){ char line[MAXPATHLEN + 256U] = MLST_BEGIN; if (modernformat(file, line + (sizeof MLST_BEGIN - 1U), sizeof line - (sizeof MLST_BEGIN - 1U)) >= 0) { addreply_noformat(0, line); addreply_noformat(250, "End."); } else { addreply_noformat(550, MSG_STAT_FAILURE2); }}void donoop(void){#ifdef BORING_MODE addreply_noformat(200, "dc.w $4E71");#else addreply_noformat(200, MSG_SLEEPING);#endif}#endifvoid dositetime(void){ char tmp[64]; const struct tm *tm; time_t now; if ((now = time(NULL)) == (time_t) -1 || (tm = localtime(&now)) == NULL) { addreply_noformat(550, "time()"); return; } strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S", tm); addreply_noformat(211, tmp);}static int doinitsupgroups(const char *user, const uid_t uid, const gid_t gid){#ifndef NON_ROOT_FTP# ifdef HAVE_SETGROUPS if (setgroups(1U, &gid) != 0) { return -1; }# else (void) gid;# endif# ifdef HAVE_INITGROUPS if (user == NULL) { const struct passwd * const lpwd = getpwuid(uid); if (lpwd != NULL && lpwd->pw_name != NULL) { user = lpwd->pw_name; } else { return 0; } } initgroups(user, gid);# else (void) user; (void) uid;# endif#else (void) user; (void) uid; (void) gid; #endif return 0;}void douser(const char *username){ struct passwd *pw; if (loggedin) { if (username) { if (!guest) { addreply_noformat(530, MSG_ALREADY_LOGGED); } else if (broken_client_compat) { addreply_noformat(331, MSG_ANY_PASSWORD); } else { addreply_noformat(230, MSG_ANONYMOUS_LOGGED); dot_read_ok = dot_read_anon_ok; dot_write_ok = 0; } } return; } if (anon_only <= 0 && username != NULL && *username != 0 && strcasecmp(username, "ftp") && strcasecmp(username, "anonymous")) { strncpy(account, username, sizeof(account) - 1); account[sizeof(account) - (size_t) 1U] = 0; addreply(331, MSG_USER_OK, account); loggedin = 0; } else if (anon_only < 0) { /* anonymous, but -E */ if (broken_client_compat != 0) { addreply(331, MSG_USER_OK, username); return; } else { die(530, LOG_DEBUG, MSG_NO_ANONYMOUS_LOGIN); } } else {#ifdef WITH_VIRTUAL_HOSTS char name[MAXPATHLEN]; char hbuf[NI_MAXHOST];#endif if (chrooted != 0) { die(421, LOG_DEBUG, MSG_CANT_DO_TWICE); } #ifdef PER_USER_LIMITS if (per_anon_max > 0U && ftpwho_read_count("ftp") >= per_anon_max) { addreply(421, MSG_PERUSER_MAX, (unsigned long) per_anon_max); doreply(); _EXIT(1); }#endif #ifdef NON_ROOT_FTP { static struct passwd pw_; char s[MAXPATHLEN + 1U]; if (getcwd(s, sizeof s - (size_t) 1U) == NULL) { cantsec: die(421, LOG_ERR, MSG_UNABLE_SECURE_ANON); } pw_.pw_uid = geteuid(); pw_.pw_gid = getegid();# if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) if ((pw_.pw_dir = getenv("WIN32_ANON_DIR")) == NULL) { pw_.pw_dir = WIN32_ANON_DIR; }# else pw_.pw_dir = strdup(s); /* checked for == NULL later */# endif pw = &pw_; }#else if ((pw = getpwnam("ftp")) == NULL || pw->pw_uid == 0 || pw->pw_gid == 0 || doinitsupgroups("ftp", (uid_t) -1, pw->pw_gid) != 0 || setgid(pw->pw_gid) || setegid(pw->pw_gid)) { cantsec: die(421, LOG_ERR, MSG_UNABLE_SECURE_ANON); }#endif#ifdef WITH_VIRTUAL_HOSTS if (getnameinfo((struct sockaddr *) &ctrlconn, STORAGE_LEN(ctrlconn), hbuf, sizeof hbuf, NULL, (size_t) 0U, NI_NUMERICHOST) != 0 || SNCHECK(snprintf(name, sizeof name, VHOST_PATH "/%s", hbuf), sizeof name)) { _EXIT(EXIT_FAILURE); } if (chdir(name) != 0) /* non-virtual */#endif { char *hd; size_t rd_len; if (pw->pw_dir == NULL || *pw->pw_dir != '/') { goto cantsec; } if ((hd = strstr(pw->pw_dir, "/./")) != NULL) { rd_len = (size_t) (hd - pw->pw_dir) + sizeof "/"; if ((root_directory = malloc(rd_len)) == NULL) { goto cantsec; } memcpy(root_directory, pw->pw_dir, rd_len); root_directory[rd_len - (size_t) 1U] = 0; hd += 2; } else { rd_len = strlen(pw->pw_dir) + sizeof "/"; if ((root_directory = malloc(rd_len)) == NULL) { goto cantsec; } snprintf(root_directory, rd_len, "%s/", pw->pw_dir); hd = (char *) "/"; } if (chdir(root_directory) || chroot(root_directory) || chdir(hd)) { goto cantsec; } logfile(LOG_INFO, MSG_ANONYMOUS_LOGGED); }#ifdef WITH_VIRTUAL_HOSTS else { /* virtual host */ const size_t rd_len = strlen(hbuf) + sizeof ":/"; if ((root_directory = malloc(rd_len)) == NULL || chdir(name) || chroot(name) || chdir("/") || SNCHECK(snprintf(root_directory, rd_len, "%s:/", hbuf), rd_len)) { goto cantsec; } logfile(LOG_INFO, MSG_ANONYMOUS_LOGGED_VIRTUAL ": %s", hbuf); }#endif chrooted = 1; authresult.uid = pw->pw_uid; authresult.gid = pw->pw_gid; if ((authresult.dir = strdup(pw->pw_dir)) == NULL) { die_mem(); }#ifdef THROTTLING if (throttling != 0) { addreply_noformat(0, MSG_BANDWIDTH_RESTRICTED); nice(NICE_VALUE); } else { throttling_delay = throttling_bandwidth_ul = throttling_bandwidth_dl = 0UL; }#endif#ifndef NON_ROOT_FTP if (authresult.uid > (uid_t) 0) {# ifdef WITH_PRIVSEP if (setuid(authresult.uid) != 0 || seteuid(authresult.uid) != 0) { goto cantsec; }# else# ifdef HAVE_SYS_FSUID_H setfsgid(authresult.gid); setfsuid(authresult.uid);# else if (seteuid(authresult.uid) != 0) { goto cantsec; }# endif# endif }#endif#ifdef USE_CAPABILITIES drop_login_caps();#endif#ifndef MINIMAL dobanner(0);#endif if (broken_client_compat) { addreply_noformat(331, MSG_ANONYMOUS_ANY_PASSWORD); } else { addreply_noformat(230, MSG_ANONYMOUS_LOGGED); } dot_write_ok = 0; dot_read_ok = dot_read_anon_ok; strncpy(account, "ftp", sizeof account - (size_t) 1U); account[(sizeof account) - 1U] = 0;#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 = guest = 1;#ifdef QUOTAS user_quota_size = user_quota_files = ULONG_LONG_MAX;#endif } if (getcwd(wd, sizeof wd - (size_t) 1U) == NULL) { wd[0] = '/'; wd[1] = 0; }}static AuthResult pw_check(const char *account, const char *password, const struct sockaddr_storage * const sa, const struct sockaddr_storage * const peer){ Authentications *auth_scan = first_authentications; AuthResult result; result.auth_ok = -1; while (auth_scan != NULL) {#ifdef THROTTLING result.throttling_bandwidth_ul = throttling_bandwidth_ul; result.throttling_bandwidth_dl = throttling_bandwidth_dl; result.throttling_ul_changed = result.throttling_dl_changed = 0;#endif#ifdef QUOTAS result.user_quota_size = user_quota_size; result.user_quota_files = user_quota_files; result.quota_size_changed = result.quota_files_changed = 0;#endif#ifdef RATIOS result.ratio_upload = ratio_upload; result.ratio_download = ratio_download; result.ratio_ul_changed = result.ratio_dl_changed = 0;#endif#ifdef PER_USER_LIMITS result.per_user_max = per_user_max;#endif auth_scan->auth->check(&result, account, password, sa, peer); if (result.auth_ok < 0) { break; } else if (result.auth_ok > 0) {#ifdef THROTTLING if ((result.throttling_ul_changed | result.throttling_dl_changed) != 0) { if (result.throttling_ul_changed != 0 && result.throttling_bandwidth_ul > 0UL) { throttling_bandwidth_ul = result.throttling_bandwidth_ul; ul_chunk_size = throttling_bandwidth_ul; if (ul_chunk_size > MAX_UL_CHUNK_SIZE) { ul_chunk_size = MAX_UL_CHUNK_SIZE; } } if (result.throttling_dl_changed != 0 && result.throttling_bandwidth_dl > 0UL) { throttling_bandwidth_dl = result.throttling_bandwidth_dl; dl_chunk_size = throttling_bandwidth_dl & ~(map_size - 1); if (dl_chunk_size < map_size) { dl_chunk_size = map_size; } } throttling_delay = 1000000 / (throttling_bandwidth_dl | throttling_bandwidth_ul); throttling = 2; }#endif#ifdef QUOTAS if (result.quota_size_changed != 0) { user_quota_size = result.user_quota_size; } if (result.quota_files_changed != 0) { user_quota_files = result.user_quota_files; }#endif#ifdef RATIOS if (result.ratio_ul_changed != 0) { ratio_upload = result.ratio_upload; ratio_for_non_anon = 1; } if (result.ratio_dl_changed != 0) { ratio_download = result.ratio_download; }#endif#ifdef PER_USER_LIMITS per_user_max = result.per_user_max;#endif #ifdef NON_ROOT_FTP result.uid = geteuid(); result.gid = getegid();#endif return result; } auth_scan = auth_scan->next; } return result;}/* * Check if an user belongs to the trusted group, either in his * primary group, or his supplementary groups. Root is always trusted. */static int check_trustedgroup(const uid_t uid, const gid_t gid){ GETGROUPS_T *alloca_suppgroups; int n; int n2; int result = 0; if (uid == (uid_t) 0) { return 1; } if (userchroot == 2) { return 0; } if (gid == chroot_trustedgid) { return 1; }#ifdef HAVE_GETGROUPS if ((n = getgroups(0, NULL)) <= 0) { return 0; } if ((alloca_suppgroups = ALLOCA(n * (sizeof *alloca_suppgroups))) == NULL) { die_mem(); } n2 = getgroups(n, alloca_suppgroups); /* Jedi's paranoia */ if (n2 < n) { n = n2; } result = 0; while (n != 0) { n--; if (alloca_suppgroups[n] == (GETGROUPS_T) chroot_trustedgid) { result = 1; break; } }; ALLOCA_FREE(alloca_suppgroups);#endif return result;}/* * Create a home directory on demand. */static int create_home_and_chdir(const char * const home){ char *pathcomp; char *z; size_t len; const char delim = '/'; if (home == NULL || *home != '/') { return -1; } if (chdir(home) == 0) { return 0; } if (create_home == 0) { return -1; } len = strlen(home) + (size_t) 1U; if (len < (size_t) 2U || *home != delim) { return -1; } if ((pathcomp = ALLOCA(len)) == NULL) { return -1; } memcpy(pathcomp, home, len); /* safe, no possible overflow */ z = pathcomp; for (;;) { z++; if (*z == 0) { break; } if (*z == delim) { *z = 0; if (z[1] == 0) { break; } (void) mkdir(pathcomp, (mode_t) 0755); *z = delim; } } ALLOCA_FREE(pathcomp); (void) mkdir(home, (mode_t) 0700); if (chdir(home) != 0) { return -1; } if (chmod(home, (mode_t) 0755 & ~u_mask_d) < 0 || chown(home, authresult.uid, authresult.gid) < 0) { return -1; } return chdir(home);}void dopass(char *password){ static unsigned int tapping; gid_t *groups = NULL; char *hd; int ngroups;#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 int ngroups_max = NGROUPS_MAX; /* Use the compile time value */#else int ngroups_max = 1; /* use a sane default */#endif if (loggedin != 0) { if (guest != 0) { addreply_noformat(230, MSG_NO_PASSWORD_NEEDED);#ifdef LOG_ANON_EMAIL snprintf(account, sizeof account, "ftp: <%s> ", password);#endif } else { addreply_noformat(530, MSG_CANT_DO_TWICE); } return; } if (*account == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -