📄 ftpd.c
字号:
}/* ARGSUSED */voidyyerror(char *s){ char *cp; (void)s; /* ignore argument */ if ((cp = strchr(cbuf,'\n'))!=NULL) *cp = '\0'; reply(500, "'%s': command not understood.", cbuf);}voiddelete(name) char *name;{ struct stat st; LOGCMD("delete", name); if (stat(name, &st) < 0) { perror_reply(550, name); return; } if ((st.st_mode&S_IFMT) == S_IFDIR) { if (rmdir(name) < 0) { perror_reply(550, name); return; } goto done; } if (unlink(name) < 0) { perror_reply(550, name); return; }done: ack("DELE");}voidcwd(path) const char *path;{ FILE *message; if (chdir(path) < 0) perror_reply(550, path); else { if ((message = fopen(_PATH_CWDMESG, "r")) != NULL) { char *cp, line[LINE_MAX]; while (fgets(line, sizeof(line), message) != NULL) { if ((cp = strchr(line, '\n')) != NULL) *cp = '\0'; lreply(250, "%s", line); } (void) fflush(stdout); (void) fclose(message); } ack("CWD"); }}voidmakedir(name) char *name;{ LOGCMD("mkdir", name); if (mkdir(name, 0777) < 0) perror_reply(550, name); else reply(257, "MKD command successful.");}voidremovedir(name) char *name;{ LOGCMD("rmdir", name); if (rmdir(name) < 0) perror_reply(550, name); else ack("RMD");}voidpwd(){ char path[MAXPATHLEN + 1]; if (getwd(path) == (char *)NULL) reply(550, "%s.", path); else reply(257, "\"%s\" is current directory.", path);}char *renamefrom(name) char *name;{ struct stat st; if (stat(name, &st) < 0) { perror_reply(550, name); return ((char *)0); } reply(350, "File exists, ready for destination name"); return (name);}voidrenamecmd(from, to) char *from, *to;{ LOGCMD2("rename", from, to); if (rename(from, to) < 0) perror_reply(550, "rename"); else ack("RNTO");}static voiddolog(sn) struct sockaddr_in *sn;{ struct hostent *hp = gethostbyaddr((char *)&sn->sin_addr, sizeof(struct in_addr), AF_INET); if (hp) (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)-1); else (void) strncpy(remotehost, inet_ntoa(sn->sin_addr), sizeof(remotehost)-1); remotehost[sizeof(remotehost)-1] = '\0';#ifdef HASSETPROCTITLE snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost); setproctitle(proctitle);#endif /* HASSETPROCTITLE */ if (logging) syslog(LOG_INFO, "connection from %s", remotehost);}/* * Record logout in wtmp file * and exit with supplied status. */voiddologout(status) int status;{ sigset_t allsigs; transflag = 0; if (logged_in) { sigfillset(&allsigs); sigprocmask(SIG_BLOCK, &allsigs, NULL); (void) seteuid((uid_t)0); logwtmp(ttyline, "", ""); if (doutmp) logout(utmp.ut_line);#if defined(KERBEROS) if (!notickets && krbtkfile_env) unlink(krbtkfile_env);#endif } /* beware of flushing buffers after a SIGPIPE */ _exit(status);}static voidmyoob(int signo){ char *cp; (void)signo; /* only process if transfer occurring */ if (!transflag) return; cp = tmpline; if (getline(cp, 7, stdin) == NULL) { reply(221, "You could at least say goodbye."); dologout(0); } upper(cp); if (strcmp(cp, "ABOR\r\n") == 0) { tmpline[0] = '\0'; reply(426, "Transfer aborted. Data connection closed."); reply(226, "Abort successful"); longjmp(urgcatch, 1); } if (strcmp(cp, "STAT\r\n") == 0) { if (file_size != (off_t) -1) reply(213, "Status: %qd of %qd bytes transferred", (quad_t) byte_count, (quad_t) file_size); else reply(213, "Status: %qd bytes transferred", (quad_t)byte_count); }}/* * Note: a response of 425 is not mentioned as a possible response to * the PASV command in RFC959. However, it has been blessed as * a legitimate response by Jon Postel in a telephone conversation * with Rick Adams on 25 Jan 89. */voidpassive(){ int len;#ifdef IP_PORTRANGE int on;#else u_short port;#endif char *p, *a; if (pw == NULL) { reply(530, "Please login with USER and PASS"); return; } if (pdata >= 0) close(pdata); pdata = socket(AF_INET, SOCK_STREAM, 0); if (pdata < 0) { perror_reply(425, "Can't open passive connection"); return; }#ifdef IP_PORTRANGE on = high_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT; if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, (char *)&on, sizeof(on)) < 0) goto pasv_error;#else#define FTP_DATA_BOTTOM 40000#define FTP_DATA_TOP 44999 if (high_data_ports) { for (port = FTP_DATA_BOTTOM; port <= FTP_DATA_TOP; port++) { pasv_addr = ctrl_addr; pasv_addr.sin_port = htons(port); if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) == 0) break; if (errno != EADDRINUSE) goto pasv_error; } if (port > FTP_DATA_TOP) goto pasv_error; } else#endif { pasv_addr = ctrl_addr; pasv_addr.sin_port = 0; if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) goto pasv_error; } len = sizeof(pasv_addr); if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) goto pasv_error; if (listen(pdata, 1) < 0) goto pasv_error; a = (char *) &pasv_addr.sin_addr; p = (char *) &pasv_addr.sin_port;#define UC(b) (((int) b) & 0xff) reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); return;pasv_error: (void) close(pdata); pdata = -1; perror_reply(425, "Can't open passive connection"); return;}/* * Generate unique name for file with basename "local". * The file named "local" is already known to exist. * Generates failure reply on error. */static intguniquefd(local, nam) const char *local; char **nam;{ static char new[MAXPATHLEN]; struct stat st; int count, len, fd; char *cp; cp = strrchr(local, '/'); if (cp) *cp = '\0'; if (stat(cp ? local : ".", &st) < 0) { perror_reply(553, cp ? local : "."); return (-1); } if (cp) *cp = '/'; (void) strncpy(new, local, sizeof(new)-1); new[sizeof(new)-1] = '\0'; len = strlen(new); if (len+2+1 >= (int)sizeof(new)-1) return (-1); cp = new + len; *cp++ = '.'; for (count = 1; count < 100; count++) { (void)snprintf(cp, sizeof(new) - (cp - new), "%d", count); fd = open(new, O_RDWR|O_CREAT|O_EXCL, 0666); if (fd == -1) continue; if (nam) *nam = new; return (fd); } reply(452, "Unique file name cannot be created."); return (-1);}/* * Format and send reply containing system error number. */voidperror_reply(code, string) int code; const char *string;{ reply(code, "%s: %s.", string, strerror(errno));}static const char *onefile[] = { "", 0};voidsend_file_list(whichf) const char *whichf;{ struct stat st; DIR *dirp = NULL; struct dirent *dir; FILE *volatile dout = NULL; char const *const *volatile dirlist; const char *dirname; volatile int simple = 0; volatile int freeglob = 0; glob_t gl; /* XXX: should the { go away if __linux__? */ if (strpbrk(whichf, "~{[*?") != NULL) {#ifdef __linux__ /* see popen.c */ int flags = GLOB_NOCHECK;#else int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;#endif memset(&gl, 0, sizeof(gl)); freeglob = 1; if (glob(whichf, flags, 0, &gl)) { reply(550, "not found"); goto out; } else if (gl.gl_pathc == 0) { errno = ENOENT; perror_reply(550, whichf); goto out; } /* The cast is necessary because of bugs in C's type system */ dirlist = (char const *const *) gl.gl_pathv; } else { onefile[0] = whichf; dirlist = onefile; simple = 1; } if (setjmp(urgcatch)) { transflag = 0; goto out; } while ((dirname = *dirlist++)!=NULL) { if (stat(dirname, &st) < 0) { /* * If user typed "ls -l", etc, and the client * used NLST, do what the user meant. */ if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) { retrieve("/bin/ls %s", dirname); goto out; } perror_reply(550, whichf); if (dout != NULL) { (void) fclose(dout); transflag = 0; data = -1; pdata = -1; } goto out; } if (S_ISREG(st.st_mode)) { if (dout == NULL) { dout = dataconn("file list", (off_t)-1, "w"); if (dout == NULL) goto out; transflag++; } fprintf(dout, "%s%s\n", dirname, type == TYPE_A ? "\r" : ""); byte_count += strlen(dirname) + 1; continue; } else if (!S_ISDIR(st.st_mode)) continue; if ((dirp = opendir(dirname)) == NULL) continue; while ((dir = readdir(dirp)) != NULL) { char nbuf[MAXPATHLEN];#ifdef __linux__ if (!strcmp(dir->d_name, ".")) continue; if (!strcmp(dir->d_name, "..")) continue;#else if (dir->d_name[0] == '.' && dir->d_namlen == 1) continue; if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && dir->d_namlen == 2) continue;#endif snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name); /* * We have to do a stat to insure it's * not a directory or special file. */ if (simple || (stat(nbuf, &st) == 0 && S_ISREG(st.st_mode))) { if (dout == NULL) { dout = dataconn("file list", (off_t)-1, "w"); if (dout == NULL) goto out; transflag++; } if (nbuf[0] == '.' && nbuf[1] == '/') fprintf(dout, "%s%s\n", &nbuf[2], type == TYPE_A ? "\r" : ""); else fprintf(dout, "%s%s\n", nbuf, type == TYPE_A ? "\r" : ""); byte_count += strlen(nbuf) + 1; } } (void) closedir(dirp); } if (dout == NULL) reply(550, "No files found."); else if (ferror(dout) != 0) perror_reply(550, "Data connection"); else reply(226, "Transfer complete."); transflag = 0; if (dout != NULL) (void) fclose(dout); data = -1; pdata = -1;out: if (freeglob) { freeglob = 0; globfree(&gl); }}static voidreapchild(int signo){ (void)signo; while (wait3(NULL, WNOHANG, NULL) > 0);}voidlogxfer(name, size, start) const char *name; off_t size; time_t start;{ char buf[2048]; char path[MAXPATHLEN]; char vremotehost[MAXHOSTNAMELEN*4], vpath[MAXPATHLEN*4]; char *vname, *vpw; time_t now; if ((statfd >= 0) && (getcwd(path, sizeof(path)) != NULL)) { time(&now); vname = (char *)malloc(strlen(name)*4+1); if (vname == NULL) return; vpw = (char *)malloc(strlen((guest) ? guestpw : pw->pw_name)*4+1); if (vpw == NULL) { free(vname); return; } strvis(vremotehost, remotehost, VIS_SAFE|VIS_NOSLASH); strvis(vpath, path, VIS_SAFE|VIS_NOSLASH); strvis(vname, name, VIS_SAFE|VIS_NOSLASH); strvis(vpw, (guest) ? guestpw : pw->pw_name, VIS_SAFE|VIS_NOSLASH); snprintf(buf, sizeof(buf), "%.24s %d %s %qd %s/%s %c %s %c %c %s ftp %d %s %s\n", ctime(&now), now - start + (now == start), vremotehost, (quad_t)size, vpath, vname, ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */, 'o', ((guest) ? 'a' : 'r'), vpw, 0 /* none yet */, ((guest) ? "*" : pw->pw_name), dhostname); write(statfd, buf, strlen(buf)); free(vname); free(vpw); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -