📄 ftpcmd.y
字号:
if (strncasecmp(passtxt, s, 5) == 0) syslog(LOG_DEBUG, "command: %s", passtxt); else syslog(LOG_DEBUG, "command: %s", s); } tmpline[0] = '\0'; return (s); } if (c == 0) tmpline[0] = '\0'; } retry: while ((c = getc(iop)) != EOF) {#ifdef TRANSFER_COUNT byte_count_total++; byte_count_in++;#endif c &= 0377; if (c == IAC) { if ((c = getc(iop)) != EOF) {#ifdef TRANSFER_COUNT byte_count_total++; byte_count_in++;#endif c &= 0377; switch (c) { case WILL: case WONT: c = getc(iop);#ifdef TRANSFER_COUNT byte_count_total++; byte_count_in++;#endif printf("%c%c%c", IAC, DONT, 0377 & c); (void) fflush(stdout); continue; case DO: case DONT: c = getc(iop);#ifdef TRANSFER_COUNT byte_count_total++; byte_count_in++;#endif printf("%c%c%c", IAC, WONT, 0377 & c); (void) fflush(stdout); continue; case IAC: break; default: continue; /* ignore command */ } } } *cs++ = c; if (--n <= 0 || c == '\n') break; } if (c == EOF && cs == s) { if (ferror(iop) && (errno == EINTR)) goto retry; return (NULL); } *cs++ = '\0'; if (debug) { if (strncasecmp(passtxt, s, 5) == 0) syslog(LOG_DEBUG, "command: %s", passtxt); else syslog(LOG_DEBUG, "command: %s", s); } return (s);}static void toolong(int a) /* signal that caused this function to be called */{ time_t now; reply(421, "Timeout (%d seconds): closing control connection.", timeout_idle); (void) time(&now); if (logging) { syslog(LOG_INFO, "User %s timed out after %d seconds at %.24s", (pw ? pw->pw_name : "unknown"), timeout_idle, ctime(&now)); } dologout(1);}int yylex(void){ static int cpos, state; register char *cp, *cp2; register struct tab *p; int n; time_t now; char c = '\0'; extern time_t limit_time; extern time_t login_time; for (;;) { switch (state) { case CMD: yyerrorcalled = 0; setproctitle("%s: IDLE", proctitle); if (is_shutdown(!logged_in, 0) != 0) { reply(221, "Server shutting down. Goodbye."); dologout(0); } time(&now); if ((limit_time > 0) && (((now - login_time) / 60) > limit_time)) { reply(221, "Time limit reached. Goodbye."); dologout(0); }#ifdef IGNORE_NOOP if (!alarm_running) { (void) signal(SIGALRM, toolong); (void) alarm((unsigned) timeout_idle); alarm_running = 1; }#else (void) signal(SIGALRM, toolong); (void) alarm((unsigned) timeout_idle);#endif if (wu_getline(cbuf, sizeof(cbuf) - 1, stdin) == NULL) { (void) alarm(0); reply(221, "You could at least say goodbye."); dologout(0); }#ifndef IGNORE_NOOP (void) alarm(0);#endif if ((cp = strchr(cbuf, '\r'))) { *cp++ = '\n'; *cp = '\0'; } if ((cp = strpbrk(cbuf, " \n"))) cpos = cp - cbuf; if (cpos == 0) cpos = 4; c = cbuf[cpos]; cbuf[cpos] = '\0'; upper(cbuf);#ifdef IGNORE_NOOP if (strncasecmp(cbuf, "NOOP", 4) != 0) { (void) alarm(0); alarm_running = 0; }#endif p = lookup(cmdtab, cbuf); cbuf[cpos] = c; if (strncasecmp(cbuf, "PASS", 4) != 0 && strncasecmp(cbuf, "SITE GPASS", 10) != 0) { if ((cp = strchr(cbuf, '\n'))) *cp = '\0'; setproctitle("%s: %s", proctitle, cbuf); if (cp) *cp = '\n'; } if (p != 0) { if (p->implemented == 0) { nack(p->name); longjmp(errcatch, 0); /* NOTREACHED */ } state = p->state; yylval.String = p->name; return (p->token); } break; case SITECMD: if (cbuf[cpos] == ' ') { cpos++; return (SP); } cp = &cbuf[cpos]; if ((cp2 = strpbrk(cp, " \n"))) cpos = cp2 - cbuf; c = cbuf[cpos]; cbuf[cpos] = '\0'; upper(cp); p = lookup(sitetab, cp); cbuf[cpos] = c; if (p != 0) {#ifndef PARANOID /* what GOOD is SITE *, anyways?! _H */ if (p->implemented == 0) {#else if (1) { syslog(LOG_WARNING, "refused SITE %s %s from %s of %s", p->name, &cbuf[cpos], anonymous ? guestpw : authuser, remoteident);#endif /* PARANOID */ state = CMD; nack(p->name); longjmp(errcatch, 0); /* NOTREACHED */ } state = p->state; yylval.String = p->name; return (p->token); } state = CMD; break; case OSTR: if (cbuf[cpos] == '\n') { state = CMD; return (CRLF); } /* FALLTHROUGH */ case STR1: case ZSTR1: dostr1: if (cbuf[cpos] == ' ') { cpos++; if (state == OSTR) state = STR2; else ++state; return (SP); } break; case ZSTR2: if (cbuf[cpos] == '\n') { state = CMD; return (CRLF); } /* FALLTHROUGH */ case STR2: cp = &cbuf[cpos]; n = strlen(cp); cpos += n - 1; /* * Make sure the string is nonempty and \n terminated. */ if (n > 1 && cbuf[cpos] == '\n') { cbuf[cpos] = '\0'; yylval.String = copy(cp); cbuf[cpos] = '\n'; state = ARGS; return (STRING); } break; case NSTR: if (cbuf[cpos] == ' ') { cpos++; return (SP); } if (isdigit(cbuf[cpos])) { cp = &cbuf[cpos]; while (isdigit(cbuf[++cpos])); c = cbuf[cpos]; cbuf[cpos] = '\0'; yylval.Number = atoi(cp); cbuf[cpos] = c; state = STR1; return (NUMBER); } state = STR1; goto dostr1; case STR3: if (cbuf[cpos] == ' ') { cpos++; return (SP); } cp = &cbuf[cpos]; cp2 = strpbrk(cp, " \n"); if (cp2 != NULL) { c = *cp2; *cp2 = '\0'; } n = strlen(cp); cpos += n; /* * Make sure the string is nonempty and SP terminated. */ if ((cp2 - cp) > 1) { yylval.String = copy(cp); cbuf[cpos] = c; state = OSTR; return (STRING); } break; case ARGS: if (isdigit(cbuf[cpos])) { cp = &cbuf[cpos]; while (isdigit(cbuf[++cpos])); c = cbuf[cpos]; cbuf[cpos] = '\0'; yylval.Number = atoi(cp); cbuf[cpos] = c; return (NUMBER); } switch (cbuf[cpos++]) { case '\n': state = CMD; return (CRLF); case ' ': return (SP); case ',': return (COMMA); case 'A': case 'a': return (A); case 'B': case 'b': return (B); case 'C': case 'c': return (C); case 'E': case 'e': return (E); case 'F': case 'f': return (F); case 'I': case 'i': return (I); case 'L': case 'l': return (L); case 'N': case 'n': return (N); case 'P': case 'p': return (P); case 'R': case 'r': return (R); case 'S': case 's': return (S); case 'T': case 't': return (T); } break; default: fatal("Unknown state in scanner."); } if (yyerrorcalled == 0) { if ((cp = strchr(cbuf, '\n')) != NULL) *cp = '\0'; if (logged_in) reply(500, "'%s': command not understood.", cbuf); else reply(530, "Please login with USER and PASS."); } state = CMD; longjmp(errcatch, 0); }}void upper(char *s){ while (*s != '\0') { if (islower(*s)) *s = toupper(*s); s++; }}char *copy(char *s){ char *p; p = (char *) malloc((unsigned) strlen(s) + 1); if (p == NULL) fatal("Ran out of memory."); (void) strcpy(p, s); return (p);}void help(struct tab *ctab, char *s){ struct aclmember *entry = NULL; struct tab *c; size_t width, NCMDS; char *type; if (ctab == sitetab) type = "SITE "; else type = ""; width = 0, NCMDS = 0; for (c = ctab; c->name != NULL; c++) { size_t len = strlen(c->name); if (len > width) width = len; NCMDS++; } width = (width + 8) & ~7; if (s == 0) { register size_t i, j, w; size_t columns, lines; lreply(214, "The following %scommands are recognized %s.", type, "(* =>'s unimplemented)"); columns = 76 / width; if (columns == 0) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { char line[BUFSIZ], *ptr = line; strcpy(ptr, " "); ptr += 3; for (j = 0; j < columns; j++) { c = ctab + j * lines + i; (void) sprintf(ptr, "%s%c", c->name, c->implemented ? ' ' : '*'); w = strlen(c->name) + 1; ptr += w; if (c + lines >= &ctab[NCMDS]) break; while (w < width) { *(ptr++) = ' '; w++; } } *ptr = '\0'; lreply(0, "%s", line); } (void) fflush(stdout);#ifdef VIRTUAL if (virtual_mode && !virtual_ftpaccess && virtual_email[0] != '\0') reply(214, "Direct comments to %s.", virtual_email); else#endif if ((getaclentry("email", &entry)) && ARG0) reply(214, "Direct comments to %s.", ARG0); else reply(214, "Direct comments to ftp-bugs@%s.", hostname); return; } upper(s); c = lookup(ctab, s); if (c == (struct tab *) NULL) { reply(502, "Unknown command %s.", s); return; } if (c->implemented) reply(214, "Syntax: %s%s %s", type, c->name, c->help); else reply(214, "%s%-*s\t%s; unimplemented.", type, width, c->name, c->help);}void sizecmd(char *filename){ switch (type) { case TYPE_L: case TYPE_I:{ struct stat stbuf; if (stat(filename, &stbuf) < 0 || (stbuf.st_mode & S_IFMT) != S_IFREG) reply(550, "%s: not a plain file.", filename); else#if OFFSET_SIZE == 8 reply(213, "%qu", stbuf.st_size);#else#ifdef _AIX42 reply(213, "%llu", stbuf.st_size);#else reply(213, "%lu", stbuf.st_size);#endif#endif break; } case TYPE_A:{ FILE *fin; register int c; register long count; struct stat stbuf; fin = fopen(filename, "r"); if (fin == NULL) { perror_reply(550, filename); return; } if (fstat(fileno(fin), &stbuf) < 0 || (stbuf.st_mode & S_IFMT) != S_IFREG) { reply(550, "%s: not a plain file.", filename); (void) fclose(fin); return; } count = 0; while ((c = getc(fin)) != EOF) { if (c == '\n') /* will get expanded to \r\n */ count++; count++; } (void) fclose(fin); reply(213, "%ld", count); break; } default: reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); }}void site_exec(char *cmd){#ifdef PARANOID syslog(LOG_CRIT, "REFUSED SITE_EXEC (slipped through!!): %s", cmd);#else char buf[MAXPATHLEN]; char *sp = (char *) strchr(cmd, ' '), *slash, *t; FILE *cmdf; /* sanitize the command-string */ if (sp == 0) { while ((slash = strchr(cmd, '/')) != 0) cmd = slash + 1; } else { while (sp && (slash = (char *) strchr(cmd, '/')) && (slash < sp)) cmd = slash + 1; } for (t = cmd; *t && !isspace(*t); t++) { if (isupper(*t)) { *t = tolower(*t); } } /* build the command */ if (strlen(_PATH_EXECPATH) + strlen(cmd) + 2 > sizeof(buf)) return; sprintf(buf, "%s/%s", _PATH_EXECPATH, cmd); cmdf = ftpd_popen(buf, "r", 0); if (!cmdf) { perror_reply(550, cmd); if (log_commands) syslog(LOG_INFO, "SITE EXEC (FAIL: %m): %s", cmd); } else { int lines = 0; int maxlines = 0; struct aclmember *entry = NULL; char class[1024]; int maxfound = 0; int defmaxlines = 20; int which; (void) acl_getclass(class); while ((getaclentry("site-exec-max-lines", &entry)) && ARG0) { if (ARG1) for (which = 1; (which < MAXARGS) && ARG[which]; which++) { if (!strcasecmp(ARG[which], class)) { maxlines = atoi(ARG0); maxfound = 1; } if (!strcmp(ARG[which], "*")) defmaxlines = atoi(ARG0); } else defmaxlines = atoi(ARG0); } if (!maxfound) maxlines = defmaxlines; lreply(200, "%s", cmd); while (fgets(buf, sizeof buf, cmdf)) { size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') buf[--len] = '\0'; lreply(200, "%s", buf); if (maxlines <= 0) ++lines; else if (++lines >= maxlines) { lreply(200, "*** Truncated ***"); break; } } reply(200, " (end of '%s')", cmd); if (log_commands) syslog(LOG_INFO, "SITE EXEC (lines: %d): %s", lines, cmd); ftpd_pclose(cmdf); }#endif /* PARANOID */}void alias(char *s){ struct aclmember *entry = NULL; if (s != (char *) NULL) { while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) if (!strcmp(ARG0, s)) { reply(214, "%s is an alias for %s.", ARG0, ARG1); return; } reply(502, "Unknown alias %s.", s); return; } lreply(214, "The following aliases are available."); while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) lreply(0, " %-8s %s", ARG0, ARG1); (void) fflush(stdout); reply(214, "");}void cdpath(void){ struct aclmember *entry = NULL; lreply(214, "The cdpath is:"); while (getaclentry("cdpath", &entry) && ARG0 != NULL) lreply(0, " %s", ARG0); (void) fflush(stdout); reply(214, "");}void print_groups(void){ gid_t groups[NGROUPS_MAX]; int ngroups = 0; if ((ngroups = getgroups(NGROUPS_MAX, groups)) < 0) { return; } lreply(214, "Group membership is:"); ngroups--; for (; ngroups >= 0; ngroups--) lreply(214, " %d", groups[ngroups]); (void) fflush(stdout); reply(214, "");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -