📄 ftpd.c
字号:
syslog(crit, "(%s@%s) %s%s", ((loggedin != 0 && *account != 0) ? account : "?"), (*host != 0 ? host : "?"), urgency, line);# ifdef SAVE_DESCRIPTORS closelog();# endif va_end(va);#endif}#ifndef NO_STANDALONE/* this is taken from the code examples for Stevens' "Advanced * Programming in the Unix Environment. The code is publicly available * at ftp://ftp.uu.net/published/books/stevens.advprog.tar.Z */static unsigned int open_max(void){ long z; if ((z = (long) sysconf(_SC_OPEN_MAX)) < 0L) { perror("_SC_OPEN_MAX"); _EXIT(EXIT_FAILURE); } return (unsigned int) z;}#endifstatic void addreply_newline(const char * const str, const size_t size){ struct reply *newline; if ((newline = (struct reply *) malloc(offsetof(struct reply, line) + size)) == NULL) { die_mem(); } if (firstreply == NULL) { firstreply = newline; } else { lastreply->next = newline; } newline->next = NULL; lastreply = newline; memcpy(newline->line, str, size); }void addreply_noformat(const int code, const char * const line){ if (code != 0) { replycode = code; } addreply_newline(line, strlen(line) + (size_t) 1U);}void addreply(const int code, const char * const line, ...){ register char *a; register char *b; va_list ap; int last; char buf[MAX_SERVER_REPLY_LEN]; if (code != 0) { replycode = code; } va_start(ap, line); vsnprintf(buf, sizeof buf, line, ap); va_end(ap); last = 0; a = buf; for (;;) { b = strchr(a, '\n'); if (b != NULL) { *b = 0; } else { b = a; while (*b != 0) { b++; } last++; } addreply_newline(a, (size_t) (b - a) + (size_t) 1U); if (last != 0) { break; } a = b + 1; }}void doreply(void){ register struct reply *scannedentry; register struct reply *nextentry; if ((scannedentry = firstreply) == NULL) { return; } CORK_ON(1); do { nextentry = scannedentry->next;#ifdef WITH_TLS if (tls_cnx != NULL) { char buf[MAX_SERVER_REPLY_LEN]; snprintf(buf, sizeof buf, "%3d%c%s\r\n", replycode, nextentry == NULL ? ' ' : '-', scannedentry->line); SSL_write(tls_cnx, buf, strlen(buf)); } else#endif { printf("%3d%c%s\r\n", replycode, nextentry == NULL ? ' ' : '-', scannedentry->line); } if (logging > 1) { logfile(LOG_DEBUG, "%3d%c%s", replycode, nextentry == NULL ? ' ' : '-', scannedentry->line); } } while ((scannedentry = nextentry) != NULL); fflush(stdout); CORK_OFF(1); /* We don't free() after printf() because of Solaris stream bugs, * Thanks to Kenneth Stailey */ scannedentry = firstreply; do { nextentry = scannedentry->next; free(scannedentry); } while ((scannedentry = nextentry) != NULL); firstreply = lastreply = NULL;}/* Check whether a file name is valid. Files names starting * with a dot are only allowed to root and to users * chroot()ed in their home directories -Jedi. */static int checknamesanity(const char *name, int dot_ok){ register const char *namepnt;#ifdef PARANOID_FILE_NAMES const char *validchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefgihjklmnopqrstuvwxyz" "0123456789./-_";#endif if (name == NULL || *name == 0) { return -1; } /* optimize . and .. */ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) { return 0; } namepnt = name;#ifdef PARANOID_FILE_NAMES /* we want to make sure we don't get any non-alphanumeric file name */ if (strlen(namepnt) != strspn(namepnt, validchars)) { return -1; }#endif#ifdef QUOTAS if (hasquota() == 0 && strstr(namepnt, QUOTA_FILE) != NULL) { return -1; /* .ftpquota => *NO* */ }#endif if (strstr(namepnt, PUREFTPD_TMPFILE_PREFIX) != NULL) { return -1; } while (*namepnt != 0) { if (ISCTRLCODE(*namepnt) || *namepnt == '\\') { return -1; } if (dot_ok == 0) { if (*namepnt == '/') { namepnt++; } else if (namepnt != name) { namepnt++; continue; } if (namepnt[0] == 0) { /* /$ */ return 0; } if (namepnt[0] == '.') { /* /. */ if (namepnt[1] == 0) { /* /.$ => ok */ return 0; } if (namepnt[1] == '.') { /* /.. */ if (namepnt[2] == 0) { /* /..$ => ok */ return 0; } if (namepnt[2] != '/') { /* /..[^/] => *NO* */ return -1; } } else if (namepnt[1] != '/') { /* /.[^/]/ => *NO* */ return -1; } } if (namepnt != name) { continue; } } namepnt++; } return 0;}static void do_ipv6_port(char *p, char delim){ char *deb; struct sockaddr_storage a; deb = p; while (*p && strchr("0123456789abcdefABCDEF:", *p) != NULL) { p++; } if (*p != delim || atoi(p + 1) == 0) { nope: (void) close(datafd); datafd = -1; addreply_noformat(501, MSG_SYNTAX_ERROR_IP); return; } *p++ = 0; if (generic_aton(deb, &a) != 0) { goto nope; } doport2(a, (unsigned int) atoi(p));}#ifndef MINIMALvoid doesta(void){ struct sockaddr_storage dataconn; socklen_t socksize; char hbuf[NI_MAXHOST]; char pbuf[NI_MAXSERV]; if (passive != 0 || datafd == -1) { addreply_noformat(520, MSG_ACTIVE_DISABLED); return; } if (xferfd == -1) { opendata(); if (xferfd == -1) { addreply_noformat(425, MSG_CANT_CREATE_DATA_SOCKET); return; } } socksize = (socklen_t) sizeof dataconn; if (getsockname(xferfd, (struct sockaddr *) &dataconn, &socksize) < 0 || getnameinfo((struct sockaddr *) &dataconn, STORAGE_LEN(dataconn), hbuf, sizeof hbuf, pbuf, sizeof pbuf, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { addreply_noformat(425, MSG_GETSOCKNAME_DATA); closedata(); return; } addreply(225, "Connected from (|%c|%s|%s|)", STORAGE_FAMILY(dataconn) == AF_INET6 ? '2' : '1', hbuf, pbuf);}void doestp(void){ struct sockaddr_storage dataconn; socklen_t socksize; char hbuf[NI_MAXHOST]; char pbuf[NI_MAXSERV]; if (passive == 0 || datafd == -1) { addreply_noformat(520, MSG_CANT_PASSIVE); return; } if (xferfd == -1) { opendata(); if (xferfd == -1) { addreply_noformat(425, MSG_CANT_CREATE_DATA_SOCKET); return; } } socksize = (socklen_t) sizeof dataconn; if (getpeername(xferfd, (struct sockaddr *) &dataconn, &socksize) < 0 || getnameinfo((struct sockaddr *) &dataconn, STORAGE_LEN(dataconn), hbuf, sizeof hbuf, pbuf, sizeof pbuf, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { addreply_noformat(425, MSG_GETSOCKNAME_DATA); closedata(); return; } addreply(225, "Connected to (|%c|%s|%s|)", STORAGE_FAMILY(dataconn) == AF_INET6 ? '2' : '1', hbuf, pbuf);}#endifvoid doeprt(char *p){ char delim; int family; delim = *p++; family = atoi(p); while (isdigit((unsigned char) *p)) { p++; } if (*p == delim) { p++; } else { addreply_noformat(501, MSG_SYNTAX_ERROR_IP); return; } if (family == 2 && v6ready) { do_ipv6_port(p, delim); return; } if (family != 1) { if (v6ready) { addreply_noformat(522, MSG_ONLY_IPV4V6); } else { addreply_noformat(522, MSG_ONLY_IPV4); } return; } { unsigned int a1, a2, a3, a4, port = 0U; /* there should be dot-decimal ip as rfc2428 states, * but troll used for some reason "comma-decimal" notation * so I decided to leave it */ if ((sscanf(p, "%u,%u,%u,%u", &a1, &a2, &a3, &a4) != 4 && sscanf(p, "%u.%u.%u.%u", &a1, &a2, &a3, &a4) != 4) || a1 > 255U || a2 > 255U || a3 > 255U || a4 > 255U || (a1 | a2 | a3 | a4) == 0U) { addreply_noformat(501, MSG_SYNTAX_ERROR_IP); return; } while (*p && strchr("0123456789.,", *p)) { p++; } if (*p == delim) { port = (unsigned int) atoi(++p); while (*p && isdigit((unsigned char) *p)) { p++; } } if (*p != delim || port > 65535U || port <= 0U) { addreply_noformat(501, MSG_SYNTAX_ERROR_IP); return; } else { struct sockaddr_storage a; memset(&a, 0, sizeof a); STORAGE_FAMILY(a) = AF_INET; STORAGE_SIN_ADDR(a) = htonl((a1 << 24) | (a2 << 16) | (a3 << 8) | a4); SET_STORAGE_LEN(a, sizeof(struct sockaddr_in)); doport2(a, port); } }}void stripctrl(char * const buf, size_t len){ if (len <= (size_t) 0U) { return; } do { len--; if (ISCTRLCODE(buf[len]) && buf[len] != 0 && buf[len] != '\n') { buf[len] = '_'; } } while (len != (size_t) 0U);}#ifndef MINIMAL/* * small help routine to display a banner * type = 0 reads .banner/welcome.msg * type = 1 reads .message (after cd'ing into a directory) */void dobanner(const int type){ char buffer[512]; FILE *msg; size_t buflen; unsigned int nblines = BANNER_MAXLINES; switch (type) { case 0: if ((msg = fopen(".banner", "r")) == NULL# ifdef WITH_WELCOME_MSG && (msg = fopen("welcome.msg", "r")) == NULL# endif ) { return; } break; case 1: if ((msg = fopen(".message", "r")) == NULL) { return; } break; default: return; } while (fgets(buffer, sizeof buffer, msg) != NULL && nblines > 0U) { nblines--; if ((buflen = strlen(buffer)) > (size_t) 0U) { buflen--; while (buffer[buflen] == '\n' || buffer[buflen] == '\r') { buffer[buflen] = 0; if (buflen == (size_t) 0U) { break; } buflen--; } stripctrl(buffer, buflen); } addreply_noformat(0, buffer); } (void) fclose(msg);}#endif#ifndef MINIMALint modernformat(const char *file, char *target, size_t target_size){ const char *ft; struct tm *t; struct stat st; int ret = 0; if (stat(file, &st) != 0 || !(t = gmtime((time_t *) &st.st_mtime))) { return -1; } if (S_ISREG(st.st_mode)) { ft = "file"; } else if (S_ISDIR(st.st_mode)) { ret = 1; ft = "dir"; if (*file == '.') { if (file[1] == '.' && file[2] == 0) { ft = "pdir"; } else if (file[1] == 0) { ft = "cdir"; } } else if (*file == '/' && file[1] == 0) { ft = "pdir"; } } else { ft = "unknown"; } if (guest != 0) { if (SNCHECK(snprintf(target, target_size, "type=%s;siz%c=%llu;modify=%04d%02d%02d%02d%02d%02d;UNIX.mode=0%o;unique=%xg%llx; %s", ft, ret ? 'd' : 'e', (unsigned long long) st.st_size, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (unsigned int) st.st_mode & 07777, (unsigned int) st.st_dev, (unsigned long long) st.st_ino, file), target_size)) { _EXIT(EXIT_FAILURE); } } else { if (SNCHECK(snprintf(target, target_size, "type=%s;siz%c=%llu;modify=%04d%02d%02d%02d%02d%02d;UNIX.mode=0%o;UNIX.uid=%lld;UNIX.gid=%lld;unique=%xg%llx; %s", ft, ret ? 'd' : 'e', (unsigned long long) st.st_size, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, (unsigned int) st.st_mode & 07777, (unsigned long long) st.st_uid, (unsigned long long) st.st_gid, (unsigned int) st.st_dev, (unsigned long long) st.st_ino, file), target_size)) { _EXIT(EXIT_FAILURE); } } return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -