📄 ftpd.c
字号:
} (void) fclose(din); data = -1; pdata = -1;done: LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); (*closefunc)(fout);}static FILE *getdatasock(mode) const char *mode;{ int on = 1, s, t, tries; sigset_t allsigs; if (data >= 0) return (fdopen(data, mode)); sigfillset(&allsigs); sigprocmask (SIG_BLOCK, &allsigs, NULL); (void) seteuid((uid_t)0); s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) goto bad; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0) goto bad; /* anchor socket to avoid multi-homing problems */#ifndef __linux__ data_source.sin_len = sizeof(struct sockaddr_in);#endif data_source.sin_family = AF_INET; data_source.sin_addr = ctrl_addr.sin_addr; for (tries = 1; ; tries++) { if (bind(s, (struct sockaddr *)&data_source, sizeof(data_source)) >= 0) break; if (errno != EADDRINUSE || tries > 10) goto bad; sleep(tries); } (void) seteuid((uid_t)pw->pw_uid); sigfillset(&allsigs); sigprocmask (SIG_UNBLOCK, &allsigs, NULL);#ifdef IP_TOS on = IPTOS_THROUGHPUT; if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");#endif#ifdef TCP_NOPUSH /* * Turn off push flag to keep sender TCP from sending short packets * at the boundaries of each write(). Should probably do a SO_SNDBUF * to set the send buffer size as well, but that may not be desirable * in heavy-load situations. */ on = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m");#endif#ifdef SO_SNDBUF on = 65536; if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m");#endif return (fdopen(s, mode));bad: /* Return the real value of errno (close may change it) */ t = errno; (void) seteuid((uid_t)pw->pw_uid); sigfillset (&allsigs); sigprocmask (SIG_UNBLOCK, &allsigs, NULL); (void) close(s); errno = t; return (NULL);}static FILE *dataconn(name, size, mode) const char *name; off_t size; const char *mode;{ char sizebuf[32]; FILE *file; int retry = 0, tos; file_size = size; byte_count = 0; if (size != (off_t) -1) { (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", (quad_t) size); } else sizebuf[0] = '\0'; if (pdata >= 0) { struct sockaddr_in from; int s, fromlen = sizeof(from); signal (SIGALRM, toolong); (void) alarm ((unsigned) timeout); s = accept(pdata, (struct sockaddr *)&from, &fromlen); (void) alarm (0); if (s < 0) { reply(425, "Can't open data connection."); (void) close(pdata); pdata = -1; return (NULL); } if (ntohs(from.sin_port) < IPPORT_RESERVED) { perror_reply(425, "Can't build data connection"); (void) close(pdata); (void) close(s); pdata = -1; return (NULL); } if (from.sin_addr.s_addr != his_addr.sin_addr.s_addr) { perror_reply(435, "Can't build data connection"); (void) close(pdata); (void) close(s); pdata = -1; return (NULL); } (void) close(pdata); pdata = s;#ifdef IP_TOS tos = IPTOS_THROUGHPUT; (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int));#endif reply(150, "Opening %s mode data connection for '%s'%s.", type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); return (fdopen(pdata, mode)); } if (data >= 0) { reply(125, "Using existing data connection for '%s'%s.", name, sizebuf); usedefault = 1; return (fdopen(data, mode)); } if (usedefault) data_dest = his_addr; usedefault = 1; file = getdatasock(mode); if (file == NULL) { reply(425, "Can't create data socket (%s,%d): %s.", inet_ntoa(data_source.sin_addr), ntohs(data_source.sin_port), strerror(errno)); return (NULL); } data = fileno(file); /* * attempt to connect to reserved port on client machine; * this looks like an attack */ if (ntohs(data_dest.sin_port) < IPPORT_RESERVED || ntohs(data_dest.sin_port) == 2049) { /* XXX */ perror_reply(425, "Can't build data connection"); (void) fclose(file); data = -1; return NULL; } if (data_dest.sin_addr.s_addr != his_addr.sin_addr.s_addr) { perror_reply(435, "Can't build data connection"); (void) fclose(file); data = -1; return NULL; } while (connect(data, (struct sockaddr *)&data_dest, sizeof(data_dest)) < 0) { if (errno == EADDRINUSE && retry < swaitmax) { sleep((unsigned) swaitint); retry += swaitint; continue; } perror_reply(425, "Can't build data connection"); (void) fclose(file); data = -1; return (NULL); } reply(150, "Opening %s mode data connection for '%s'%s.", type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); return (file);}/* * Tranfer the contents of "instr" to "outstr" peer using the appropriate * encapsulation of the data subject to Mode, Structure, and Type. * * NB: Form isn't handled. */static voidsend_data(instr, outstr, blksize, filesize, isreg) FILE *instr, *outstr; off_t blksize; off_t filesize; int isreg;{ int c, cnt, filefd, netfd; char *buf, *bp; size_t len; transflag++; if (setjmp(urgcatch)) { transflag = 0; return; } switch (type) { case TYPE_A: while ((c = getc(instr)) != EOF) { byte_count++; if (c == '\n') { if (ferror(outstr)) goto data_err; (void) putc('\r', outstr); } (void) putc(c, outstr); } fflush(outstr); transflag = 0; if (ferror(instr)) goto file_err; if (ferror(outstr)) goto data_err; reply(226, "Transfer complete."); return; case TYPE_I: case TYPE_L: /* * isreg is only set if we are not doing restart and we * are sending a regular file */ netfd = fileno(outstr); filefd = fileno(instr); if (isreg && filesize < (off_t)16 * 1024 * 1024) { buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, (off_t)0); if (buf==MAP_FAILED || buf==NULL) { syslog(LOG_WARNING, "mmap(%lu): %m", (unsigned long)filesize); goto oldway; } bp = buf; len = filesize; do { cnt = write(netfd, bp, len); len -= cnt; bp += cnt; if (cnt > 0) byte_count += cnt; } while(cnt > 0 && len > 0); transflag = 0; munmap(buf, (size_t)filesize); if (cnt < 0) goto data_err; reply(226, "Transfer complete."); return; }oldway: if ((buf = malloc((u_int)blksize)) == NULL) { transflag = 0; perror_reply(451, "Local resource failure: malloc"); return; } while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && write(netfd, buf, cnt) == cnt) byte_count += cnt; transflag = 0; (void)free(buf); if (cnt != 0) { if (cnt < 0) goto file_err; goto data_err; } reply(226, "Transfer complete."); return; default: transflag = 0; reply(550, "Unimplemented TYPE %d in send_data", type); return; }data_err: transflag = 0; perror_reply(426, "Data connection"); return;file_err: transflag = 0; perror_reply(551, "Error on input file");}/* * Transfer data from peer to "outstr" using the appropriate encapulation of * the data subject to Mode, Structure, and Type. * * N.B.: Form isn't handled. */static intreceive_data(instr, outstr) FILE *instr, *outstr;{ int c; int cnt; volatile int bare_lfs = 0; char buf[BUFSIZ]; transflag++; if (setjmp(urgcatch)) { transflag = 0; return (-1); } switch (type) { case TYPE_I: case TYPE_L: while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { if (write(fileno(outstr), buf, cnt) != cnt) goto file_err; byte_count += cnt; } if (cnt < 0) goto data_err; transflag = 0; return (0); case TYPE_E: reply(553, "TYPE E not implemented."); transflag = 0; return (-1); case TYPE_A: while ((c = getc(instr)) != EOF) { byte_count++; if (c == '\n') bare_lfs++; while (c == '\r') { if (ferror(outstr)) goto data_err; if ((c = getc(instr)) != '\n') { (void) putc ('\r', outstr); if (c == '\0' || c == EOF) goto contin2; } } (void) putc(c, outstr); contin2: ; } fflush(outstr); if (ferror(instr)) goto data_err; if (ferror(outstr)) goto file_err; transflag = 0; if (bare_lfs) { lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); (void)printf(" File may not have transferred correctly.\r\n"); } return (0); default: reply(550, "Unimplemented TYPE %d in receive_data", type); transflag = 0; return (-1); }data_err: transflag = 0; perror_reply(426, "Data Connection"); return (-1);file_err: transflag = 0; perror_reply(452, "Error writing file"); return (-1);}voidstatfilecmd(filename) char *filename;{ FILE *fin; int c; char line[LINE_MAX]; (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); fin = ftpd_popen(line, "r"); lreply(211, "status of %s:", filename); while ((c = getc(fin)) != EOF) { if (c == '\n') { if (ferror(stdout)){ perror_reply(421, "control connection"); (void) ftpd_pclose(fin); dologout(1); /* NOTREACHED */ } if (ferror(fin)) { perror_reply(551, filename); (void) ftpd_pclose(fin); return; } (void) putc('\r', stdout); } (void) putc(c, stdout); } (void) ftpd_pclose(fin); reply(211, "End of Status");}voidstatcmd(){ struct sockaddr_in *sn; u_char *a, *p; lreply(211, "%s FTP server status:", hostname, version); printf(" %s\r\n", version); printf(" Connected to %s", remotehost); if (!isdigit(remotehost[0])) printf(" (%s)", inet_ntoa(his_addr.sin_addr)); printf("\r\n"); if (logged_in) { if (guest) printf(" Logged in anonymously\r\n"); else printf(" Logged in as %s\r\n", pw->pw_name); } else if (askpasswd) printf(" Waiting for password\r\n"); else printf(" Waiting for user name\r\n"); printf(" TYPE: %s", typenames[type]); if (type == TYPE_A || type == TYPE_E) printf(", FORM: %s", formnames[form]); if (type == TYPE_L)#if CHAR_BIT == 8 printf(" %d", CHAR_BIT);#else printf(" %d", bytesize); /* need definition! */#endif printf("; STRUcture: %s; transfer MODE: %s\r\n", strunames[stru], modenames[mode]); if (data != -1) printf(" Data connection open\r\n"); else if (pdata != -1) { printf(" in Passive mode"); sn = &pasv_addr; goto printaddr; } else if (usedefault == 0) { printf(" PORT"); sn = &data_dest;printaddr: a = (u_char *) &sn->sin_addr; p = (u_char *) &sn->sin_port;#define UC(b) (((int) b) & 0xff) printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));#undef UC } else printf(" No data connection\r\n"); reply(211, "End of status");}voidfatal(s) const char *s;{ reply(451, "Error in server: %s\n", s); reply(221, "Closing connection due to server error."); dologout(0); /* NOTREACHED */}void#if __STDC__reply(int n, const char *fmt, ...)#elsereply(n, fmt, va_alist) int n; char *fmt; va_dcl#endif{ va_list ap;#if __STDC__ va_start(ap, fmt);#else va_start(ap);#endif (void)printf("%d ", n); (void)vprintf(fmt, ap); (void)printf("\r\n"); (void)fflush(stdout); if (debug) { syslog(LOG_DEBUG, "<--- %d ", n); vsyslog(LOG_DEBUG, fmt, ap); }}void#if __STDC__lreply(int n, const char *fmt, ...)#elselreply(n, fmt, va_alist) int n; char *fmt; va_dcl#endif{ va_list ap;#if __STDC__ va_start(ap, fmt);#else va_start(ap);#endif (void)printf("%d- ", n); (void)vprintf(fmt, ap); (void)printf("\r\n"); (void)fflush(stdout); if (debug) { syslog(LOG_DEBUG, "<--- %d- ", n); vsyslog(LOG_DEBUG, fmt, ap); }}static voidack(s) const char *s;{ reply(250, "%s command successful.", s);}voidnack(s) const char *s;{ reply(502, "%s command not implemented.", s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -