ftpd.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,298 行 · 第 1/2 页
C
1,298 行
* encapulation of the date subject * to Mode, Structure, and Type. * * NB: Form isn't handled. */send_data(instr, outstr) FILE *instr, *outstr;{ register int c; int netfd, filefd, cnt; char buf[BUFSIZ]; transflag++; if (setjmp(urgcatch)) { transflag = 0; return(-1); } switch (type) { case TYPE_A: while ((c = getc(instr)) != EOF) { if (c == '\n') { if (ferror (outstr)) { transflag = 0; return (1); } (void) putc('\r', outstr); } (void) putc(c, outstr); /* if (c == '\r') */ /* putc ('\0', outstr); */ } transflag = 0; if (ferror (instr) || ferror (outstr)) { return (1); } return (0); case TYPE_I: case TYPE_L: netfd = fileno(outstr); filefd = fileno(instr); while ((cnt = read(filefd, buf, sizeof (buf))) > 0) { if (write(netfd, buf, cnt) < 0) { transflag = 0; return (1); } } transflag = 0; return (cnt < 0); } reply(550, "Unimplemented TYPE %d in send_data", type); transflag = 0; return (-1);}/* * 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. */receive_data(instr, outstr) FILE *instr, *outstr;{ register int c; int cnt; 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) < 0) { transflag = 0; return (1); } } transflag = 0; return (cnt < 0); case TYPE_E: reply(553, "TYPE E not implemented."); transflag = 0; return (-1); case TYPE_A: while ((c = getc(instr)) != EOF) { while (c == '\r') { if (ferror (outstr)) { transflag = 0; return (1); } if ((c = getc(instr)) != '\n') (void) putc ('\r', outstr); /* if (c == '\0') */ /* continue; */ } (void) putc (c, outstr); } transflag = 0; if (ferror (instr) || ferror (outstr)) return (1); return (0); } transflag = 0; fatal("Unknown type in receive_data."); /*NOTREACHED*/}fatal(s) char *s;{ reply(451, "Error in server: %s\n", s); reply(221, "Closing connection due to server error."); dologout(0);}reply(va_alist)va_dcl{ va_list args; int n; char *s; va_start(args); n = va_arg(args, int); s = va_arg(args, char *); sprintf(aud_msg, "%d ", n); vsprintf(aud_msg+strlen(aud_msg), s, args); fputs(aud_msg, stdout); puts("\r"); (void) fflush(stdout); if (debug) { char buf[BUFSIZ]; syslog(LOG_DEBUG, "<--- %d ", n); vsprintf(buf, s, args); syslog(LOG_DEBUG, buf); }}lreply(va_alist)va_dcl{ va_list args; int n; char *s; va_start(args); n = va_arg(args, int); s = va_arg(args, char *); sprintf(aud_msg, "%d-", n); vsprintf(aud_msg+strlen(aud_msg), s, args); fputs(aud_msg, stdout); puts("\r"); (void) fflush(stdout); if (debug) { char buf[BUFSIZ]; syslog(LOG_DEBUG, "<--- %d- ", n); vsprintf(buf, s, args); syslog(LOG_DEBUG, buf); }}ack(s) char *s;{ reply(250, "%s command successful.", s);}nack(s) char *s;{ reply(502, "%s command not implemented.", s);}yyerror(s) char *s;{ char *cp; cp = index(cbuf,'\n'); *cp = '\0'; reply(500, "'%s': command not understood.",cbuf);}delete(name) char *name;{ struct stat st; if (stat(name, &st) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return; } if ((st.st_mode&S_IFMT) == S_IFDIR) { if (rmdir(name) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return; } goto done; } if (unlink(name) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return; }done: ack("DELE");}cwd(path) char *path;{ if (chdir(path) < 0) { reply(550, "%s: %s.", path, sys_errlist[errno]); return; } ack("CWD");}makedir(name) char *name;{ struct stat st; int dochown = stat(name, &st) < 0; if (mkdir(name, 0777) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return; } if (dochown) (void) chown(name, pw->pw_uid, -1); reply(257, "MKD command successful.");}removedir(name) char *name;{ if (rmdir(name) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return; } ack("RMD");}pwd(){ char path[MAXPATHLEN + 1]; if (getwd(path) == NULL) { reply(550, "%s.", path); return; } reply(257, "\"%s\" is current directory.", path);}char *renamefrom(name) char *name;{ struct stat st; if (stat(name, &st) < 0) { reply(550, "%s: %s.", name, sys_errlist[errno]); return ((char *)0); } reply(350, "File exists, ready for destination name"); return (name);}renamecmd(from, to) char *from, *to;{ if (rename(from, to) < 0) { reply(550, "rename: %s.", sys_errlist[errno]); return; } ack("RNTO");}dolog(sin) struct sockaddr_in *sin;{ struct hostent *hp = gethostbyaddr(&sin->sin_addr, sizeof (struct in_addr), AF_INET); time_t t; extern char *ctime(); char *ti; char st[80]; if (hp) { (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); endhostent(); } else (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), sizeof (remotehost)); if (!logging) return; t = time((time_t *) 0); ti = ctime(&t); strncpy(st,ti,strlen(ti)-1); /* get rid of CR */ syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, st);}#include <utmp.h>#define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))struct utmp utmp;/* * Record login in wtmp file. */dologin(p) struct passwd *p;{ char line[32]; if (wtmp >= 0) { /* hack, but must be unique and no tty line */ (void) sprintf(line, "ftp%d", getpid()); SCPYN(utmp.ut_line, line); SCPYN(utmp.ut_name, p->pw_name); SCPYN(utmp.ut_host, remotehost); utmp.ut_time = (long) time((time_t *) 0); (void) write(wtmp, (char *)&utmp, sizeof (utmp)); if (!guest) { /* anon must hang on */ (void) close(wtmp); wtmp = -1; } }}/* * Record logout in wtmp file * and exit with supplied status. */dologout(status) int status;{ if (logged_in) { (void) seteuid(0); if (wtmp < 0) wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); if (wtmp >= 0) { SCPYN(utmp.ut_name, ""); SCPYN(utmp.ut_host, ""); utmp.ut_time = (long) time((time_t *) 0); (void) write(wtmp, (char *)&utmp, sizeof (utmp)); (void) close(wtmp); } } /* beware of flushing buffers after a SIGPIPE */ _exit(status);}/* * Special version of popen which avoids * call to shell. This insures noone may * create a pipe to a hidden program as a side * effect of a list or dir command. */#define tst(a,b) (*mode == 'r'? (b) : (a))#define RDR 0#define WTR 1static int popen_pid[5];static char *nextarg(cpp) char *cpp;{ register char *cp = cpp; if (cp == 0) return (cp); while (*cp && *cp != ' ' && *cp != '\t') cp++; if (*cp == ' ' || *cp == '\t') { *cp++ = '\0'; while (*cp == ' ' || *cp == '\t') cp++; } if (cp == cpp) return ((char *)0); return (cp);}FILE *popen(cmd, mode) char *cmd, *mode;{ int p[2], ac, gac; register myside, hisside, pid; char *av[20], *gav[512]; register char *cp; if (pipe(p) < 0) return (NULL); cp = cmd, ac = 0; /* break up string into pieces */ do { av[ac++] = cp; cp = nextarg(cp); } while (cp && *cp && ac < 20); av[ac] = (char *)0; gav[0] = av[0]; /* glob each piece */ for (gac = ac = 1; av[ac] != NULL; ac++) { char **pop; extern char **glob(), **copyblk(); pop = glob(av[ac]); if (pop == (char **)NULL) { /* globbing failed */ char *vv[2]; vv[0] = av[ac]; vv[1] = 0; pop = copyblk(vv); } av[ac] = (char *)pop; /* save to free later */ while (*pop && gac < 512) gav[gac++] = *pop++; } gav[gac] = (char *)0; myside = tst(p[WTR], p[RDR]); hisside = tst(p[RDR], p[WTR]); if ((pid = fork()) == 0) { /* myside and hisside reverse roles in child */ (void) close(myside); (void) dup2(hisside, tst(0, 1)); (void) close(hisside); execv(gav[0], gav); _exit(1); } for (ac = 1; av[ac] != NULL; ac++) blkfree((char **)av[ac]); if (pid == -1) return (NULL); popen_pid[myside] = pid; (void) close(hisside); return (fdopen(myside, mode));}pclose(ptr) FILE *ptr;{ register f, r; register void (*hstat)(), (*istat)(), (*qstat)(); int status; f = fileno(ptr); (void) fclose(ptr); istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); hstat = signal(SIGHUP, SIG_IGN); while ((r = wait(&status)) != popen_pid[f] && r != -1) ; if (r == -1) status = -1; (void) signal(SIGINT, istat); (void) signal(SIGQUIT, qstat); (void) signal(SIGHUP, hstat); return (status);}/* * Check user requesting login priviledges. * Disallow anyone who does not have a standard * shell returned by getusershell() (/etc/shells). * Disallow anyone mentioned in the file FTPUSERS * to allow people such as uucp to be avoided. */checkuser(name) register char *name;{ register char *cp; FILE *fd; struct passwd *p; char *shell; int found = 0; char line[BUFSIZ], *index(), *getusershell(); if ((p = getpwnam(name)) == NULL) return (0); if ((shell = p->pw_shell) == NULL || *shell == 0) shell = "/bin/sh";#ifdef 43BSD while ((cp = getusershell()) != NULL) if (strcmp(cp, shell) == 0) break; endusershell();#else endpwent();#endif 43BSD if (cp == NULL) return (0); if ((fd = fopen(FTPUSERS, "r")) == NULL) return (1); while (fgets(line, sizeof (line), fd) != NULL) { if ((cp = index(line, '\n')) != NULL) *cp = '\0'; if (strcmp(line, name) == 0) { found++; break; } } (void) fclose(fd); return (!found);}voidmyoob(){ char *cp; /* only process if transfer occurring */ if (!transflag) { return; } cp = tmpline; if (getline(cp, 7, stdin) == NULL) { reply(221, "You could at least say goodby."); dologout(0); } upper(cp); if (strcmp(cp, "ABOR\r\n")) return; tmpline[0] = '\0'; reply(426,"Transfer aborted. Data connection closed."); reply(226,"Abort successful"); longjmp(urgcatch, 1);}/* * Note: The 530 reply codes could be 4xx codes, except nothing is * given in the state tables except 421 which implies an exit. (RFC959) */passive(){ int len; struct sockaddr_in tmp; register char *p, *a; pdata = socket(AF_INET, SOCK_STREAM, 0); if (pdata < 0) { reply(530, "Can't open passive connection"); return; } tmp = ctrl_addr; tmp.sin_port = 0; seteuid(0); if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) { seteuid(pw->pw_uid); (void) close(pdata); pdata = -1; reply(530, "Can't open passive connection"); return; } seteuid(pw->pw_uid); len = sizeof(tmp); if (getsockname(pdata, (char *) &tmp, &len) < 0) { (void) close(pdata); pdata = -1; reply(530, "Can't open passive connection"); return; } if (listen(pdata, 1) < 0) { (void) close(pdata); pdata = -1; reply(530, "Can't open passive connection"); return; } a = (char *) &tmp.sin_addr; p = (char *) &tmp.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]));}char *gunique(local) char *local;{ static char new[MAXPATHLEN]; char *cp = rindex(local, '/'); int d, count=0; char ext = '1'; if (cp) { *cp = '\0'; } d = access(cp ? local : ".", 2); if (cp) { *cp = '/'; } if (d < 0) { syslog(LOG_ERR, "%s: %m", local); return((char *) 0); } (void) strcpy(new, local); cp = new + strlen(new); *cp++ = '.'; while (!d) { if (++count == 100) { reply(452, "Unique file name not cannot be created."); return((char *) 0); } *cp++ = ext; *cp = '\0'; if (ext == '9') { ext = '0'; } else { ext++; } if ((d = access(new, 0)) < 0) { break; } if (ext != '0') { cp--; } else if (*(cp - 2) == '.') { *(cp - 1) = '1'; } else { *(cp - 2) = *(cp - 2) + 1; cp--; } } return(new);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?