|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1985, 1988, 1990 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)ftpd.c 5.37 (Berkeley) 6/27/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: * FTP server. ! 32: */ ! 33: #include <sys/param.h> ! 34: #include <sys/stat.h> ! 35: #include <sys/ioctl.h> ! 36: #include <sys/socket.h> ! 37: #include <sys/file.h> ! 38: #include <sys/wait.h> ! 39: #include <sys/dir.h> ! 40: ! 41: #include <netinet/in.h> ! 42: #include <netinet/in_systm.h> ! 43: #include <netinet/ip.h> ! 44: ! 45: #define FTP_NAMES ! 46: #include <arpa/ftp.h> ! 47: #include <arpa/inet.h> ! 48: #include <arpa/telnet.h> ! 49: ! 50: #include <ctype.h> ! 51: #include <stdio.h> ! 52: #include <signal.h> ! 53: #include <pwd.h> ! 54: #include <setjmp.h> ! 55: #include <netdb.h> ! 56: #include <errno.h> ! 57: #include <string.h> ! 58: #include <syslog.h> ! 59: #include <varargs.h> ! 60: #include "pathnames.h" ! 61: ! 62: /* ! 63: * File containing login names ! 64: * NOT to be used on this machine. ! 65: * Commonly used to disallow uucp. ! 66: */ ! 67: extern int errno; ! 68: extern char *crypt(); ! 69: extern char version[]; ! 70: extern char *home; /* pointer to home directory for glob */ ! 71: extern FILE *ftpd_popen(), *fopen(), *freopen(); ! 72: extern int ftpd_pclose(), fclose(); ! 73: extern char *getline(); ! 74: extern char cbuf[]; ! 75: extern off_t restart_point; ! 76: ! 77: struct sockaddr_in ctrl_addr; ! 78: struct sockaddr_in data_source; ! 79: struct sockaddr_in data_dest; ! 80: struct sockaddr_in his_addr; ! 81: struct sockaddr_in pasv_addr; ! 82: ! 83: int data; ! 84: jmp_buf errcatch, urgcatch; ! 85: int logged_in; ! 86: struct passwd *pw; ! 87: int debug; ! 88: int timeout = 900; /* timeout after 15 minutes of inactivity */ ! 89: int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ ! 90: int logging; ! 91: int guest; ! 92: int type; ! 93: int form; ! 94: int stru; /* avoid C keyword */ ! 95: int mode; ! 96: int usedefault = 1; /* for data transfers */ ! 97: int pdata = -1; /* for passive mode */ ! 98: int transflag; ! 99: off_t file_size; ! 100: off_t byte_count; ! 101: #if !defined(CMASK) || CMASK == 0 ! 102: #undef CMASK ! 103: #define CMASK 027 ! 104: #endif ! 105: int defumask = CMASK; /* default umask value */ ! 106: char tmpline[7]; ! 107: char hostname[MAXHOSTNAMELEN]; ! 108: char remotehost[MAXHOSTNAMELEN]; ! 109: ! 110: /* ! 111: * Timeout intervals for retrying connections ! 112: * to hosts that don't accept PORT cmds. This ! 113: * is a kludge, but given the problems with TCP... ! 114: */ ! 115: #define SWAITMAX 90 /* wait at most 90 seconds */ ! 116: #define SWAITINT 5 /* interval between retries */ ! 117: ! 118: int swaitmax = SWAITMAX; ! 119: int swaitint = SWAITINT; ! 120: ! 121: int lostconn(); ! 122: int myoob(); ! 123: FILE *getdatasock(), *dataconn(); ! 124: ! 125: #ifdef SETPROCTITLE ! 126: char **Argv = NULL; /* pointer to argument vector */ ! 127: char *LastArgv = NULL; /* end of argv */ ! 128: char proctitle[BUFSIZ]; /* initial part of title */ ! 129: #endif /* SETPROCTITLE */ ! 130: ! 131: main(argc, argv, envp) ! 132: int argc; ! 133: char *argv[]; ! 134: char **envp; ! 135: { ! 136: int addrlen, on = 1, tos; ! 137: char *cp; ! 138: ! 139: addrlen = sizeof (his_addr); ! 140: if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { ! 141: syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); ! 142: exit(1); ! 143: } ! 144: addrlen = sizeof (ctrl_addr); ! 145: if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { ! 146: syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); ! 147: exit(1); ! 148: } ! 149: #ifdef IP_TOS ! 150: tos = IPTOS_LOWDELAY; ! 151: if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) ! 152: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); ! 153: #endif ! 154: data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); ! 155: debug = 0; ! 156: openlog("ftpd", LOG_PID, LOG_DAEMON); ! 157: #ifdef SETPROCTITLE ! 158: /* ! 159: * Save start and extent of argv for setproctitle. ! 160: */ ! 161: Argv = argv; ! 162: while (*envp) ! 163: envp++; ! 164: LastArgv = envp[-1] + strlen(envp[-1]); ! 165: #endif /* SETPROCTITLE */ ! 166: ! 167: argc--, argv++; ! 168: while (argc > 0 && *argv[0] == '-') { ! 169: for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { ! 170: ! 171: case 'v': ! 172: debug = 1; ! 173: break; ! 174: ! 175: case 'd': ! 176: debug = 1; ! 177: break; ! 178: ! 179: case 'l': ! 180: logging = 1; ! 181: break; ! 182: ! 183: case 't': ! 184: timeout = atoi(++cp); ! 185: if (maxtimeout < timeout) ! 186: maxtimeout = timeout; ! 187: goto nextopt; ! 188: ! 189: case 'T': ! 190: maxtimeout = atoi(++cp); ! 191: if (timeout > maxtimeout) ! 192: timeout = maxtimeout; ! 193: goto nextopt; ! 194: ! 195: case 'u': ! 196: { ! 197: int val = 0; ! 198: ! 199: while (*++cp && *cp >= '0' && *cp <= '9') ! 200: val = val*8 + *cp - '0'; ! 201: if (*cp) ! 202: fprintf(stderr, "ftpd: Bad value for -u\n"); ! 203: else ! 204: defumask = val; ! 205: goto nextopt; ! 206: } ! 207: ! 208: default: ! 209: fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", ! 210: *cp); ! 211: break; ! 212: } ! 213: nextopt: ! 214: argc--, argv++; ! 215: } ! 216: (void) freopen(_PATH_DEVNULL, "w", stderr); ! 217: (void) signal(SIGPIPE, lostconn); ! 218: (void) signal(SIGCHLD, SIG_IGN); ! 219: if ((int)signal(SIGURG, myoob) < 0) ! 220: syslog(LOG_ERR, "signal: %m"); ! 221: ! 222: /* Try to handle urgent data inline */ ! 223: #ifdef SO_OOBINLINE ! 224: if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) ! 225: syslog(LOG_ERR, "setsockopt: %m"); ! 226: #endif ! 227: ! 228: #ifdef F_SETOWN ! 229: if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) ! 230: syslog(LOG_ERR, "fcntl F_SETOWN: %m"); ! 231: #endif ! 232: dolog(&his_addr); ! 233: /* ! 234: * Set up default state ! 235: */ ! 236: data = -1; ! 237: type = TYPE_A; ! 238: form = FORM_N; ! 239: stru = STRU_F; ! 240: mode = MODE_S; ! 241: tmpline[0] = '\0'; ! 242: (void) gethostname(hostname, sizeof (hostname)); ! 243: reply(220, "%s FTP server (%s) ready.", hostname, version); ! 244: (void) setjmp(errcatch); ! 245: for (;;) ! 246: (void) yyparse(); ! 247: /* NOTREACHED */ ! 248: } ! 249: ! 250: lostconn() ! 251: { ! 252: ! 253: if (debug) ! 254: syslog(LOG_DEBUG, "lost connection"); ! 255: dologout(-1); ! 256: } ! 257: ! 258: static char ttyline[20]; ! 259: ! 260: /* ! 261: * Helper function for sgetpwnam(). ! 262: */ ! 263: char * ! 264: sgetsave(s) ! 265: char *s; ! 266: { ! 267: char *malloc(); ! 268: char *new = malloc((unsigned) strlen(s) + 1); ! 269: ! 270: if (new == NULL) { ! 271: perror_reply(421, "Local resource failure: malloc"); ! 272: dologout(1); ! 273: /* NOTREACHED */ ! 274: } ! 275: (void) strcpy(new, s); ! 276: return (new); ! 277: } ! 278: ! 279: /* ! 280: * Save the result of a getpwnam. Used for USER command, since ! 281: * the data returned must not be clobbered by any other command ! 282: * (e.g., globbing). ! 283: */ ! 284: struct passwd * ! 285: sgetpwnam(name) ! 286: char *name; ! 287: { ! 288: static struct passwd save; ! 289: register struct passwd *p; ! 290: char *sgetsave(); ! 291: ! 292: if ((p = getpwnam(name)) == NULL) ! 293: return (p); ! 294: if (save.pw_name) { ! 295: free(save.pw_name); ! 296: free(save.pw_passwd); ! 297: free(save.pw_gecos); ! 298: free(save.pw_dir); ! 299: free(save.pw_shell); ! 300: } ! 301: save = *p; ! 302: save.pw_name = sgetsave(p->pw_name); ! 303: save.pw_passwd = sgetsave(p->pw_passwd); ! 304: save.pw_gecos = sgetsave(p->pw_gecos); ! 305: save.pw_dir = sgetsave(p->pw_dir); ! 306: save.pw_shell = sgetsave(p->pw_shell); ! 307: return (&save); ! 308: } ! 309: ! 310: int login_attempts; /* number of failed login attempts */ ! 311: int askpasswd; /* had user command, ask for passwd */ ! 312: ! 313: /* ! 314: * USER command. ! 315: * Sets global passwd pointer pw if named account exists and is acceptable; ! 316: * sets askpasswd if a PASS command is expected. If logged in previously, ! 317: * need to reset state. If name is "ftp" or "anonymous", the name is not in ! 318: * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. ! 319: * If account doesn't exist, ask for passwd anyway. Otherwise, check user ! 320: * requesting login privileges. Disallow anyone who does not have a standard ! 321: * shell as returned by getusershell(). Disallow anyone mentioned in the file ! 322: * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. ! 323: */ ! 324: user(name) ! 325: char *name; ! 326: { ! 327: register char *cp; ! 328: char *shell; ! 329: char *getusershell(); ! 330: ! 331: if (logged_in) { ! 332: if (guest) { ! 333: reply(530, "Can't change user from guest login."); ! 334: return; ! 335: } ! 336: end_login(); ! 337: } ! 338: ! 339: guest = 0; ! 340: if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { ! 341: if (checkuser("ftp") || checkuser("anonymous")) ! 342: reply(530, "User %s access denied.", name); ! 343: else if ((pw = sgetpwnam("ftp")) != NULL) { ! 344: guest = 1; ! 345: askpasswd = 1; ! 346: reply(331, "Guest login ok, send ident as password."); ! 347: } else ! 348: reply(530, "User %s unknown.", name); ! 349: return; ! 350: } ! 351: if (pw = sgetpwnam(name)) { ! 352: if ((shell = pw->pw_shell) == NULL || *shell == 0) ! 353: shell = _PATH_BSHELL; ! 354: while ((cp = getusershell()) != NULL) ! 355: if (strcmp(cp, shell) == 0) ! 356: break; ! 357: endusershell(); ! 358: if (cp == NULL || checkuser(name)) { ! 359: reply(530, "User %s access denied.", name); ! 360: if (logging) ! 361: syslog(LOG_NOTICE, ! 362: "FTP LOGIN REFUSED FROM %s, %s", ! 363: remotehost, name); ! 364: pw = (struct passwd *) NULL; ! 365: return; ! 366: } ! 367: } ! 368: reply(331, "Password required for %s.", name); ! 369: askpasswd = 1; ! 370: /* ! 371: * Delay before reading passwd after first failed ! 372: * attempt to slow down passwd-guessing programs. ! 373: */ ! 374: if (login_attempts) ! 375: sleep((unsigned) login_attempts); ! 376: } ! 377: ! 378: /* ! 379: * Check if a user is in the file _PATH_FTPUSERS ! 380: */ ! 381: checkuser(name) ! 382: char *name; ! 383: { ! 384: register FILE *fd; ! 385: register char *p; ! 386: char line[BUFSIZ]; ! 387: ! 388: if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) { ! 389: while (fgets(line, sizeof(line), fd) != NULL) ! 390: if ((p = index(line, '\n')) != NULL) { ! 391: *p = '\0'; ! 392: if (line[0] == '#') ! 393: continue; ! 394: if (strcmp(line, name) == 0) ! 395: return (1); ! 396: } ! 397: (void) fclose(fd); ! 398: } ! 399: return (0); ! 400: } ! 401: ! 402: /* ! 403: * Terminate login as previous user, if any, resetting state; ! 404: * used when USER command is given or login fails. ! 405: */ ! 406: end_login() ! 407: { ! 408: ! 409: (void) seteuid((uid_t)0); ! 410: if (logged_in) ! 411: logwtmp(ttyline, "", ""); ! 412: pw = NULL; ! 413: logged_in = 0; ! 414: guest = 0; ! 415: } ! 416: ! 417: pass(passwd) ! 418: char *passwd; ! 419: { ! 420: char *xpasswd, *salt; ! 421: ! 422: if (logged_in || askpasswd == 0) { ! 423: reply(503, "Login with USER first."); ! 424: return; ! 425: } ! 426: askpasswd = 0; ! 427: if (!guest) { /* "ftp" is only account allowed no password */ ! 428: if (pw == NULL) ! 429: salt = "xx"; ! 430: else ! 431: salt = pw->pw_passwd; ! 432: xpasswd = crypt(passwd, salt); ! 433: /* The strcmp does not catch null passwords! */ ! 434: if (pw == NULL || *pw->pw_passwd == '\0' || ! 435: strcmp(xpasswd, pw->pw_passwd)) { ! 436: reply(530, "Login incorrect."); ! 437: pw = NULL; ! 438: if (login_attempts++ >= 5) { ! 439: syslog(LOG_NOTICE, ! 440: "repeated login failures from %s", ! 441: remotehost); ! 442: exit(0); ! 443: } ! 444: return; ! 445: } ! 446: } ! 447: login_attempts = 0; /* this time successful */ ! 448: (void) setegid((gid_t)pw->pw_gid); ! 449: (void) initgroups(pw->pw_name, pw->pw_gid); ! 450: ! 451: /* open wtmp before chroot */ ! 452: (void)sprintf(ttyline, "ftp%d", getpid()); ! 453: logwtmp(ttyline, pw->pw_name, remotehost); ! 454: logged_in = 1; ! 455: ! 456: if (guest) { ! 457: /* ! 458: * We MUST do a chdir() after the chroot. Otherwise ! 459: * the old current directory will be accessible as "." ! 460: * outside the new root! ! 461: */ ! 462: if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { ! 463: reply(550, "Can't set guest privileges."); ! 464: goto bad; ! 465: } ! 466: } else if (chdir(pw->pw_dir) < 0) { ! 467: if (chdir("/") < 0) { ! 468: reply(530, "User %s: can't change directory to %s.", ! 469: pw->pw_name, pw->pw_dir); ! 470: goto bad; ! 471: } else ! 472: lreply(230, "No directory! Logging in with home=/"); ! 473: } ! 474: if (seteuid((uid_t)pw->pw_uid) < 0) { ! 475: reply(550, "Can't set uid."); ! 476: goto bad; ! 477: } ! 478: if (guest) { ! 479: reply(230, "Guest login ok, access restrictions apply."); ! 480: #ifdef SETPROCTITLE ! 481: sprintf(proctitle, "%s: anonymous/%.*s", remotehost, ! 482: sizeof(proctitle) - sizeof(remotehost) - ! 483: sizeof(": anonymous/"), passwd); ! 484: setproctitle(proctitle); ! 485: #endif /* SETPROCTITLE */ ! 486: if (logging) ! 487: syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", ! 488: remotehost, passwd); ! 489: } else { ! 490: reply(230, "User %s logged in.", pw->pw_name); ! 491: #ifdef SETPROCTITLE ! 492: sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); ! 493: setproctitle(proctitle); ! 494: #endif /* SETPROCTITLE */ ! 495: if (logging) ! 496: syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", ! 497: remotehost, pw->pw_name); ! 498: } ! 499: home = pw->pw_dir; /* home dir for globbing */ ! 500: (void) umask(defumask); ! 501: return; ! 502: bad: ! 503: /* Forget all about it... */ ! 504: end_login(); ! 505: } ! 506: ! 507: retrieve(cmd, name) ! 508: char *cmd, *name; ! 509: { ! 510: FILE *fin, *dout; ! 511: struct stat st; ! 512: int (*closefunc)(); ! 513: ! 514: if (cmd == 0) { ! 515: fin = fopen(name, "r"), closefunc = fclose; ! 516: st.st_size = 0; ! 517: } else { ! 518: char line[BUFSIZ]; ! 519: ! 520: (void) sprintf(line, cmd, name), name = line; ! 521: fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; ! 522: st.st_size = -1; ! 523: st.st_blksize = BUFSIZ; ! 524: } ! 525: if (fin == NULL) { ! 526: if (errno != 0) ! 527: perror_reply(550, name); ! 528: return; ! 529: } ! 530: if (cmd == 0 && ! 531: (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { ! 532: reply(550, "%s: not a plain file.", name); ! 533: goto done; ! 534: } ! 535: if (restart_point) { ! 536: if (type == TYPE_A) { ! 537: register int i, n, c; ! 538: ! 539: n = restart_point; ! 540: i = 0; ! 541: while (i++ < n) { ! 542: if ((c=getc(fin)) == EOF) { ! 543: perror_reply(550, name); ! 544: goto done; ! 545: } ! 546: if (c == '\n') ! 547: i++; ! 548: } ! 549: } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { ! 550: perror_reply(550, name); ! 551: goto done; ! 552: } ! 553: } ! 554: dout = dataconn(name, st.st_size, "w"); ! 555: if (dout == NULL) ! 556: goto done; ! 557: send_data(fin, dout, st.st_blksize); ! 558: (void) fclose(dout); ! 559: data = -1; ! 560: pdata = -1; ! 561: done: ! 562: (*closefunc)(fin); ! 563: } ! 564: ! 565: store(name, mode, unique) ! 566: char *name, *mode; ! 567: int unique; ! 568: { ! 569: FILE *fout, *din; ! 570: struct stat st; ! 571: int (*closefunc)(); ! 572: char *gunique(); ! 573: ! 574: if (unique && stat(name, &st) == 0 && ! 575: (name = gunique(name)) == NULL) ! 576: return; ! 577: ! 578: if (restart_point) ! 579: mode = "r+w"; ! 580: fout = fopen(name, mode); ! 581: closefunc = fclose; ! 582: if (fout == NULL) { ! 583: perror_reply(553, name); ! 584: return; ! 585: } ! 586: if (restart_point) { ! 587: if (type == TYPE_A) { ! 588: register int i, n, c; ! 589: ! 590: n = restart_point; ! 591: i = 0; ! 592: while (i++ < n) { ! 593: if ((c=getc(fout)) == EOF) { ! 594: perror_reply(550, name); ! 595: goto done; ! 596: } ! 597: if (c == '\n') ! 598: i++; ! 599: } ! 600: /* ! 601: * We must do this seek to "current" position ! 602: * because we are changing from reading to ! 603: * writing. ! 604: */ ! 605: if (fseek(fout, 0L, L_INCR) < 0) { ! 606: perror_reply(550, name); ! 607: goto done; ! 608: } ! 609: } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { ! 610: perror_reply(550, name); ! 611: goto done; ! 612: } ! 613: } ! 614: din = dataconn(name, (off_t)-1, "r"); ! 615: if (din == NULL) ! 616: goto done; ! 617: if (receive_data(din, fout) == 0) { ! 618: if (unique) ! 619: reply(226, "Transfer complete (unique file name:%s).", ! 620: name); ! 621: else ! 622: reply(226, "Transfer complete."); ! 623: } ! 624: (void) fclose(din); ! 625: data = -1; ! 626: pdata = -1; ! 627: done: ! 628: (*closefunc)(fout); ! 629: } ! 630: ! 631: FILE * ! 632: getdatasock(mode) ! 633: char *mode; ! 634: { ! 635: int s, on = 1, tries; ! 636: ! 637: if (data >= 0) ! 638: return (fdopen(data, mode)); ! 639: s = socket(AF_INET, SOCK_STREAM, 0); ! 640: if (s < 0) ! 641: return (NULL); ! 642: (void) seteuid((uid_t)0); ! 643: if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, ! 644: (char *) &on, sizeof (on)) < 0) ! 645: goto bad; ! 646: /* anchor socket to avoid multi-homing problems */ ! 647: data_source.sin_family = AF_INET; ! 648: data_source.sin_addr = ctrl_addr.sin_addr; ! 649: for (tries = 1; ; tries++) { ! 650: if (bind(s, (struct sockaddr *)&data_source, ! 651: sizeof (data_source)) >= 0) ! 652: break; ! 653: if (errno != EADDRINUSE || tries > 10) ! 654: goto bad; ! 655: sleep(tries); ! 656: } ! 657: (void) seteuid((uid_t)pw->pw_uid); ! 658: #ifdef IP_TOS ! 659: on = IPTOS_THROUGHPUT; ! 660: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) ! 661: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); ! 662: #endif ! 663: return (fdopen(s, mode)); ! 664: bad: ! 665: (void) seteuid((uid_t)pw->pw_uid); ! 666: (void) close(s); ! 667: return (NULL); ! 668: } ! 669: ! 670: FILE * ! 671: dataconn(name, size, mode) ! 672: char *name; ! 673: off_t size; ! 674: char *mode; ! 675: { ! 676: char sizebuf[32]; ! 677: FILE *file; ! 678: int retry = 0, tos; ! 679: ! 680: file_size = size; ! 681: byte_count = 0; ! 682: if (size != (off_t) -1) ! 683: (void) sprintf (sizebuf, " (%ld bytes)", size); ! 684: else ! 685: (void) strcpy(sizebuf, ""); ! 686: if (pdata >= 0) { ! 687: struct sockaddr_in from; ! 688: int s, fromlen = sizeof(from); ! 689: ! 690: s = accept(pdata, (struct sockaddr *)&from, &fromlen); ! 691: if (s < 0) { ! 692: reply(425, "Can't open data connection."); ! 693: (void) close(pdata); ! 694: pdata = -1; ! 695: return(NULL); ! 696: } ! 697: (void) close(pdata); ! 698: pdata = s; ! 699: #ifdef IP_TOS ! 700: tos = IPTOS_LOWDELAY; ! 701: (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, ! 702: sizeof(int)); ! 703: #endif ! 704: reply(150, "Opening %s mode data connection for %s%s.", ! 705: type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); ! 706: return(fdopen(pdata, mode)); ! 707: } ! 708: if (data >= 0) { ! 709: reply(125, "Using existing data connection for %s%s.", ! 710: name, sizebuf); ! 711: usedefault = 1; ! 712: return (fdopen(data, mode)); ! 713: } ! 714: if (usedefault) ! 715: data_dest = his_addr; ! 716: usedefault = 1; ! 717: file = getdatasock(mode); ! 718: if (file == NULL) { ! 719: reply(425, "Can't create data socket (%s,%d): %s.", ! 720: inet_ntoa(data_source.sin_addr), ! 721: ntohs(data_source.sin_port), strerror(errno)); ! 722: return (NULL); ! 723: } ! 724: data = fileno(file); ! 725: while (connect(data, (struct sockaddr *)&data_dest, ! 726: sizeof (data_dest)) < 0) { ! 727: if (errno == EADDRINUSE && retry < swaitmax) { ! 728: sleep((unsigned) swaitint); ! 729: retry += swaitint; ! 730: continue; ! 731: } ! 732: perror_reply(425, "Can't build data connection"); ! 733: (void) fclose(file); ! 734: data = -1; ! 735: return (NULL); ! 736: } ! 737: reply(150, "Opening %s mode data connection for %s%s.", ! 738: type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); ! 739: return (file); ! 740: } ! 741: ! 742: /* ! 743: * Tranfer the contents of "instr" to ! 744: * "outstr" peer using the appropriate ! 745: * encapsulation of the data subject ! 746: * to Mode, Structure, and Type. ! 747: * ! 748: * NB: Form isn't handled. ! 749: */ ! 750: send_data(instr, outstr, blksize) ! 751: FILE *instr, *outstr; ! 752: off_t blksize; ! 753: { ! 754: register int c, cnt; ! 755: register char *buf; ! 756: int netfd, filefd; ! 757: ! 758: transflag++; ! 759: if (setjmp(urgcatch)) { ! 760: transflag = 0; ! 761: return; ! 762: } ! 763: switch (type) { ! 764: ! 765: case TYPE_A: ! 766: while ((c = getc(instr)) != EOF) { ! 767: byte_count++; ! 768: if (c == '\n') { ! 769: if (ferror(outstr)) ! 770: goto data_err; ! 771: (void) putc('\r', outstr); ! 772: } ! 773: (void) putc(c, outstr); ! 774: } ! 775: fflush(outstr); ! 776: transflag = 0; ! 777: if (ferror(instr)) ! 778: goto file_err; ! 779: if (ferror(outstr)) ! 780: goto data_err; ! 781: reply(226, "Transfer complete."); ! 782: return; ! 783: ! 784: case TYPE_I: ! 785: case TYPE_L: ! 786: if ((buf = malloc((u_int)blksize)) == NULL) { ! 787: transflag = 0; ! 788: perror_reply(451, "Local resource failure: malloc"); ! 789: return; ! 790: } ! 791: netfd = fileno(outstr); ! 792: filefd = fileno(instr); ! 793: while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && ! 794: write(netfd, buf, cnt) == cnt) ! 795: byte_count += cnt; ! 796: transflag = 0; ! 797: (void)free(buf); ! 798: if (cnt != 0) { ! 799: if (cnt < 0) ! 800: goto file_err; ! 801: goto data_err; ! 802: } ! 803: reply(226, "Transfer complete."); ! 804: return; ! 805: default: ! 806: transflag = 0; ! 807: reply(550, "Unimplemented TYPE %d in send_data", type); ! 808: return; ! 809: } ! 810: ! 811: data_err: ! 812: transflag = 0; ! 813: perror_reply(426, "Data connection"); ! 814: return; ! 815: ! 816: file_err: ! 817: transflag = 0; ! 818: perror_reply(551, "Error on input file"); ! 819: } ! 820: ! 821: /* ! 822: * Transfer data from peer to ! 823: * "outstr" using the appropriate ! 824: * encapulation of the data subject ! 825: * to Mode, Structure, and Type. ! 826: * ! 827: * N.B.: Form isn't handled. ! 828: */ ! 829: receive_data(instr, outstr) ! 830: FILE *instr, *outstr; ! 831: { ! 832: register int c; ! 833: int cnt, bare_lfs = 0; ! 834: char buf[BUFSIZ]; ! 835: ! 836: transflag++; ! 837: if (setjmp(urgcatch)) { ! 838: transflag = 0; ! 839: return (-1); ! 840: } ! 841: switch (type) { ! 842: ! 843: case TYPE_I: ! 844: case TYPE_L: ! 845: while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) { ! 846: if (write(fileno(outstr), buf, cnt) != cnt) ! 847: goto file_err; ! 848: byte_count += cnt; ! 849: } ! 850: if (cnt < 0) ! 851: goto data_err; ! 852: transflag = 0; ! 853: return (0); ! 854: ! 855: case TYPE_E: ! 856: reply(553, "TYPE E not implemented."); ! 857: transflag = 0; ! 858: return (-1); ! 859: ! 860: case TYPE_A: ! 861: while ((c = getc(instr)) != EOF) { ! 862: byte_count++; ! 863: if (c == '\n') ! 864: bare_lfs++; ! 865: while (c == '\r') { ! 866: if (ferror(outstr)) ! 867: goto data_err; ! 868: if ((c = getc(instr)) != '\n') { ! 869: (void) putc ('\r', outstr); ! 870: if (c == '\0' || c == EOF) ! 871: goto contin2; ! 872: } ! 873: } ! 874: (void) putc(c, outstr); ! 875: contin2: ; ! 876: } ! 877: fflush(outstr); ! 878: if (ferror(instr)) ! 879: goto data_err; ! 880: if (ferror(outstr)) ! 881: goto file_err; ! 882: transflag = 0; ! 883: if (bare_lfs) { ! 884: lreply(230, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); ! 885: printf(" File may not have transferred correctly.\r\n"); ! 886: } ! 887: return (0); ! 888: default: ! 889: reply(550, "Unimplemented TYPE %d in receive_data", type); ! 890: transflag = 0; ! 891: return (-1); ! 892: } ! 893: ! 894: data_err: ! 895: transflag = 0; ! 896: perror_reply(426, "Data Connection"); ! 897: return (-1); ! 898: ! 899: file_err: ! 900: transflag = 0; ! 901: perror_reply(452, "Error writing file"); ! 902: return (-1); ! 903: } ! 904: ! 905: statfilecmd(filename) ! 906: char *filename; ! 907: { ! 908: char line[BUFSIZ]; ! 909: FILE *fin; ! 910: int c; ! 911: ! 912: (void) sprintf(line, "/bin/ls -lgA %s", filename); ! 913: fin = ftpd_popen(line, "r"); ! 914: lreply(211, "status of %s:", filename); ! 915: while ((c = getc(fin)) != EOF) { ! 916: if (c == '\n') { ! 917: if (ferror(stdout)){ ! 918: perror_reply(421, "control connection"); ! 919: (void) ftpd_pclose(fin); ! 920: dologout(1); ! 921: /* NOTREACHED */ ! 922: } ! 923: if (ferror(fin)) { ! 924: perror_reply(551, filename); ! 925: (void) ftpd_pclose(fin); ! 926: return; ! 927: } ! 928: (void) putc('\r', stdout); ! 929: } ! 930: (void) putc(c, stdout); ! 931: } ! 932: (void) ftpd_pclose(fin); ! 933: reply(211, "End of Status"); ! 934: } ! 935: ! 936: statcmd() ! 937: { ! 938: struct sockaddr_in *sin; ! 939: u_char *a, *p; ! 940: ! 941: lreply(211, "%s FTP server status:", hostname, version); ! 942: printf(" %s\r\n", version); ! 943: printf(" Connected to %s", remotehost); ! 944: if (!isdigit(remotehost[0])) ! 945: printf(" (%s)", inet_ntoa(his_addr.sin_addr)); ! 946: printf("\r\n"); ! 947: if (logged_in) { ! 948: if (guest) ! 949: printf(" Logged in anonymously\r\n"); ! 950: else ! 951: printf(" Logged in as %s\r\n", pw->pw_name); ! 952: } else if (askpasswd) ! 953: printf(" Waiting for password\r\n"); ! 954: else ! 955: printf(" Waiting for user name\r\n"); ! 956: printf(" TYPE: %s", typenames[type]); ! 957: if (type == TYPE_A || type == TYPE_E) ! 958: printf(", FORM: %s", formnames[form]); ! 959: if (type == TYPE_L) ! 960: #if NBBY == 8 ! 961: printf(" %d", NBBY); ! 962: #else ! 963: printf(" %d", bytesize); /* need definition! */ ! 964: #endif ! 965: printf("; STRUcture: %s; transfer MODE: %s\r\n", ! 966: strunames[stru], modenames[mode]); ! 967: if (data != -1) ! 968: printf(" Data connection open\r\n"); ! 969: else if (pdata != -1) { ! 970: printf(" in Passive mode"); ! 971: sin = &pasv_addr; ! 972: goto printaddr; ! 973: } else if (usedefault == 0) { ! 974: printf(" PORT"); ! 975: sin = &data_dest; ! 976: printaddr: ! 977: a = (u_char *) &sin->sin_addr; ! 978: p = (u_char *) &sin->sin_port; ! 979: #define UC(b) (((int) b) & 0xff) ! 980: printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]), ! 981: UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); ! 982: #undef UC ! 983: } else ! 984: printf(" No data connection\r\n"); ! 985: reply(211, "End of status"); ! 986: } ! 987: ! 988: fatal(s) ! 989: char *s; ! 990: { ! 991: reply(451, "Error in server: %s\n", s); ! 992: reply(221, "Closing connection due to server error."); ! 993: dologout(0); ! 994: /* NOTREACHED */ ! 995: } ! 996: ! 997: /* VARARGS2 */ ! 998: reply(n, fmt, p0, p1, p2, p3, p4, p5) ! 999: int n; ! 1000: char *fmt; ! 1001: { ! 1002: printf("%d ", n); ! 1003: printf(fmt, p0, p1, p2, p3, p4, p5); ! 1004: printf("\r\n"); ! 1005: (void)fflush(stdout); ! 1006: if (debug) { ! 1007: syslog(LOG_DEBUG, "<--- %d ", n); ! 1008: syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); ! 1009: } ! 1010: } ! 1011: ! 1012: /* VARARGS2 */ ! 1013: lreply(n, fmt, p0, p1, p2, p3, p4, p5) ! 1014: int n; ! 1015: char *fmt; ! 1016: { ! 1017: printf("%d- ", n); ! 1018: printf(fmt, p0, p1, p2, p3, p4, p5); ! 1019: printf("\r\n"); ! 1020: (void)fflush(stdout); ! 1021: if (debug) { ! 1022: syslog(LOG_DEBUG, "<--- %d- ", n); ! 1023: syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5); ! 1024: } ! 1025: } ! 1026: ! 1027: ack(s) ! 1028: char *s; ! 1029: { ! 1030: reply(250, "%s command successful.", s); ! 1031: } ! 1032: ! 1033: nack(s) ! 1034: char *s; ! 1035: { ! 1036: reply(502, "%s command not implemented.", s); ! 1037: } ! 1038: ! 1039: /* ARGSUSED */ ! 1040: yyerror(s) ! 1041: char *s; ! 1042: { ! 1043: char *cp; ! 1044: ! 1045: if (cp = index(cbuf,'\n')) ! 1046: *cp = '\0'; ! 1047: reply(500, "'%s': command not understood.", cbuf); ! 1048: } ! 1049: ! 1050: delete(name) ! 1051: char *name; ! 1052: { ! 1053: struct stat st; ! 1054: ! 1055: if (stat(name, &st) < 0) { ! 1056: perror_reply(550, name); ! 1057: return; ! 1058: } ! 1059: if ((st.st_mode&S_IFMT) == S_IFDIR) { ! 1060: if (rmdir(name) < 0) { ! 1061: perror_reply(550, name); ! 1062: return; ! 1063: } ! 1064: goto done; ! 1065: } ! 1066: if (unlink(name) < 0) { ! 1067: perror_reply(550, name); ! 1068: return; ! 1069: } ! 1070: done: ! 1071: ack("DELE"); ! 1072: } ! 1073: ! 1074: cwd(path) ! 1075: char *path; ! 1076: { ! 1077: if (chdir(path) < 0) ! 1078: perror_reply(550, path); ! 1079: else ! 1080: ack("CWD"); ! 1081: } ! 1082: ! 1083: makedir(name) ! 1084: char *name; ! 1085: { ! 1086: if (mkdir(name, 0777) < 0) ! 1087: perror_reply(550, name); ! 1088: else ! 1089: reply(257, "MKD command successful."); ! 1090: } ! 1091: ! 1092: removedir(name) ! 1093: char *name; ! 1094: { ! 1095: if (rmdir(name) < 0) ! 1096: perror_reply(550, name); ! 1097: else ! 1098: ack("RMD"); ! 1099: } ! 1100: ! 1101: pwd() ! 1102: { ! 1103: char path[MAXPATHLEN + 1]; ! 1104: extern char *getwd(); ! 1105: ! 1106: if (getwd(path) == (char *)NULL) ! 1107: reply(550, "%s.", path); ! 1108: else ! 1109: reply(257, "\"%s\" is current directory.", path); ! 1110: } ! 1111: ! 1112: char * ! 1113: renamefrom(name) ! 1114: char *name; ! 1115: { ! 1116: struct stat st; ! 1117: ! 1118: if (stat(name, &st) < 0) { ! 1119: perror_reply(550, name); ! 1120: return ((char *)0); ! 1121: } ! 1122: reply(350, "File exists, ready for destination name"); ! 1123: return (name); ! 1124: } ! 1125: ! 1126: renamecmd(from, to) ! 1127: char *from, *to; ! 1128: { ! 1129: if (rename(from, to) < 0) ! 1130: perror_reply(550, "rename"); ! 1131: else ! 1132: ack("RNTO"); ! 1133: } ! 1134: ! 1135: dolog(sin) ! 1136: struct sockaddr_in *sin; ! 1137: { ! 1138: struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, ! 1139: sizeof (struct in_addr), AF_INET); ! 1140: time_t t, time(); ! 1141: extern char *ctime(); ! 1142: ! 1143: if (hp) ! 1144: (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); ! 1145: else ! 1146: (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), ! 1147: sizeof (remotehost)); ! 1148: #ifdef SETPROCTITLE ! 1149: sprintf(proctitle, "%s: connected", remotehost); ! 1150: setproctitle(proctitle); ! 1151: #endif /* SETPROCTITLE */ ! 1152: ! 1153: if (logging) { ! 1154: t = time((time_t *) 0); ! 1155: syslog(LOG_INFO, "connection from %s at %s", ! 1156: remotehost, ctime(&t)); ! 1157: } ! 1158: } ! 1159: ! 1160: /* ! 1161: * Record logout in wtmp file ! 1162: * and exit with supplied status. ! 1163: */ ! 1164: dologout(status) ! 1165: int status; ! 1166: { ! 1167: if (logged_in) { ! 1168: (void) seteuid((uid_t)0); ! 1169: logwtmp(ttyline, "", ""); ! 1170: } ! 1171: /* beware of flushing buffers after a SIGPIPE */ ! 1172: _exit(status); ! 1173: } ! 1174: ! 1175: myoob() ! 1176: { ! 1177: char *cp; ! 1178: ! 1179: /* only process if transfer occurring */ ! 1180: if (!transflag) ! 1181: return; ! 1182: cp = tmpline; ! 1183: if (getline(cp, 7, stdin) == NULL) { ! 1184: reply(221, "You could at least say goodbye."); ! 1185: dologout(0); ! 1186: } ! 1187: upper(cp); ! 1188: if (strcmp(cp, "ABOR\r\n") == 0) { ! 1189: tmpline[0] = '\0'; ! 1190: reply(426, "Transfer aborted. Data connection closed."); ! 1191: reply(226, "Abort successful"); ! 1192: longjmp(urgcatch, 1); ! 1193: } ! 1194: if (strcmp(cp, "STAT\r\n") == 0) { ! 1195: if (file_size != (off_t) -1) ! 1196: reply(213, "Status: %lu of %lu bytes transferred", ! 1197: byte_count, file_size); ! 1198: else ! 1199: reply(213, "Status: %lu bytes transferred", byte_count); ! 1200: } ! 1201: } ! 1202: ! 1203: /* ! 1204: * Note: a response of 425 is not mentioned as a possible response to ! 1205: * the PASV command in RFC959. However, it has been blessed as ! 1206: * a legitimate response by Jon Postel in a telephone conversation ! 1207: * with Rick Adams on 25 Jan 89. ! 1208: */ ! 1209: passive() ! 1210: { ! 1211: int len; ! 1212: register char *p, *a; ! 1213: ! 1214: pdata = socket(AF_INET, SOCK_STREAM, 0); ! 1215: if (pdata < 0) { ! 1216: perror_reply(425, "Can't open passive connection"); ! 1217: return; ! 1218: } ! 1219: pasv_addr = ctrl_addr; ! 1220: pasv_addr.sin_port = 0; ! 1221: (void) seteuid((uid_t)0); ! 1222: if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) { ! 1223: (void) seteuid((uid_t)pw->pw_uid); ! 1224: goto pasv_error; ! 1225: } ! 1226: (void) seteuid((uid_t)pw->pw_uid); ! 1227: len = sizeof(pasv_addr); ! 1228: if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) ! 1229: goto pasv_error; ! 1230: if (listen(pdata, 1) < 0) ! 1231: goto pasv_error; ! 1232: a = (char *) &pasv_addr.sin_addr; ! 1233: p = (char *) &pasv_addr.sin_port; ! 1234: ! 1235: #define UC(b) (((int) b) & 0xff) ! 1236: ! 1237: reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), ! 1238: UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); ! 1239: return; ! 1240: ! 1241: pasv_error: ! 1242: (void) close(pdata); ! 1243: pdata = -1; ! 1244: perror_reply(425, "Can't open passive connection"); ! 1245: return; ! 1246: } ! 1247: ! 1248: /* ! 1249: * Generate unique name for file with basename "local". ! 1250: * The file named "local" is already known to exist. ! 1251: * Generates failure reply on error. ! 1252: */ ! 1253: char * ! 1254: gunique(local) ! 1255: char *local; ! 1256: { ! 1257: static char new[MAXPATHLEN]; ! 1258: struct stat st; ! 1259: char *cp = rindex(local, '/'); ! 1260: int count = 0; ! 1261: ! 1262: if (cp) ! 1263: *cp = '\0'; ! 1264: if (stat(cp ? local : ".", &st) < 0) { ! 1265: perror_reply(553, cp ? local : "."); ! 1266: return((char *) 0); ! 1267: } ! 1268: if (cp) ! 1269: *cp = '/'; ! 1270: (void) strcpy(new, local); ! 1271: cp = new + strlen(new); ! 1272: *cp++ = '.'; ! 1273: for (count = 1; count < 100; count++) { ! 1274: (void) sprintf(cp, "%d", count); ! 1275: if (stat(new, &st) < 0) ! 1276: return(new); ! 1277: } ! 1278: reply(452, "Unique file name cannot be created."); ! 1279: return((char *) 0); ! 1280: } ! 1281: ! 1282: /* ! 1283: * Format and send reply containing system error number. ! 1284: */ ! 1285: perror_reply(code, string) ! 1286: int code; ! 1287: char *string; ! 1288: { ! 1289: reply(code, "%s: %s.", string, strerror(errno)); ! 1290: } ! 1291: ! 1292: static char *onefile[] = { ! 1293: "", ! 1294: 0 ! 1295: }; ! 1296: ! 1297: send_file_list(whichfiles) ! 1298: char *whichfiles; ! 1299: { ! 1300: struct stat st; ! 1301: DIR *dirp = NULL; ! 1302: struct direct *dir; ! 1303: FILE *dout = NULL; ! 1304: register char **dirlist, *dirname; ! 1305: int simple = 0; ! 1306: char *strpbrk(); ! 1307: ! 1308: if (strpbrk(whichfiles, "~{[*?") != NULL) { ! 1309: extern char **glob(), *globerr; ! 1310: ! 1311: globerr = NULL; ! 1312: dirlist = glob(whichfiles); ! 1313: if (globerr != NULL) { ! 1314: reply(550, globerr); ! 1315: return; ! 1316: } else if (dirlist == NULL) { ! 1317: errno = ENOENT; ! 1318: perror_reply(550, whichfiles); ! 1319: return; ! 1320: } ! 1321: } else { ! 1322: onefile[0] = whichfiles; ! 1323: dirlist = onefile; ! 1324: simple = 1; ! 1325: } ! 1326: ! 1327: if (setjmp(urgcatch)) { ! 1328: transflag = 0; ! 1329: return; ! 1330: } ! 1331: while (dirname = *dirlist++) { ! 1332: if (stat(dirname, &st) < 0) { ! 1333: /* ! 1334: * If user typed "ls -l", etc, and the client ! 1335: * used NLST, do what the user meant. ! 1336: */ ! 1337: if (dirname[0] == '-' && *dirlist == NULL && ! 1338: transflag == 0) { ! 1339: retrieve("/bin/ls %s", dirname); ! 1340: return; ! 1341: } ! 1342: perror_reply(550, whichfiles); ! 1343: if (dout != NULL) { ! 1344: (void) fclose(dout); ! 1345: transflag = 0; ! 1346: data = -1; ! 1347: pdata = -1; ! 1348: } ! 1349: return; ! 1350: } ! 1351: ! 1352: if ((st.st_mode&S_IFMT) == S_IFREG) { ! 1353: if (dout == NULL) { ! 1354: dout = dataconn("file list", (off_t)-1, "w"); ! 1355: if (dout == NULL) ! 1356: return; ! 1357: transflag++; ! 1358: } ! 1359: fprintf(dout, "%s%s\n", dirname, ! 1360: type == TYPE_A ? "\r" : ""); ! 1361: byte_count += strlen(dirname) + 1; ! 1362: continue; ! 1363: } else if ((st.st_mode&S_IFMT) != S_IFDIR) ! 1364: continue; ! 1365: ! 1366: if ((dirp = opendir(dirname)) == NULL) ! 1367: continue; ! 1368: ! 1369: while ((dir = readdir(dirp)) != NULL) { ! 1370: char nbuf[MAXPATHLEN]; ! 1371: ! 1372: if (dir->d_name[0] == '.' && dir->d_namlen == 1) ! 1373: continue; ! 1374: if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && ! 1375: dir->d_namlen == 2) ! 1376: continue; ! 1377: ! 1378: sprintf(nbuf, "%s/%s", dirname, dir->d_name); ! 1379: ! 1380: /* ! 1381: * We have to do a stat to insure it's ! 1382: * not a directory or special file. ! 1383: */ ! 1384: if (simple || (stat(nbuf, &st) == 0 && ! 1385: (st.st_mode&S_IFMT) == S_IFREG)) { ! 1386: if (dout == NULL) { ! 1387: dout = dataconn("file list", (off_t)-1, ! 1388: "w"); ! 1389: if (dout == NULL) ! 1390: return; ! 1391: transflag++; ! 1392: } ! 1393: if (nbuf[0] == '.' && nbuf[1] == '/') ! 1394: fprintf(dout, "%s%s\n", &nbuf[2], ! 1395: type == TYPE_A ? "\r" : ""); ! 1396: else ! 1397: fprintf(dout, "%s%s\n", nbuf, ! 1398: type == TYPE_A ? "\r" : ""); ! 1399: byte_count += strlen(nbuf) + 1; ! 1400: } ! 1401: } ! 1402: (void) closedir(dirp); ! 1403: } ! 1404: ! 1405: if (dout == NULL) ! 1406: reply(550, "No files found."); ! 1407: else if (ferror(dout) != 0) ! 1408: perror_reply(550, "Data connection"); ! 1409: else ! 1410: reply(226, "Transfer complete."); ! 1411: ! 1412: transflag = 0; ! 1413: if (dout != NULL) ! 1414: (void) fclose(dout); ! 1415: data = -1; ! 1416: pdata = -1; ! 1417: } ! 1418: ! 1419: #ifdef SETPROCTITLE ! 1420: /* ! 1421: * clobber argv so ps will show what we're doing. ! 1422: * (stolen from sendmail) ! 1423: * warning, since this is usually started from inetd.conf, it ! 1424: * often doesn't have much of an environment or arglist to overwrite. ! 1425: */ ! 1426: ! 1427: /*VARARGS1*/ ! 1428: setproctitle(fmt, a, b, c) ! 1429: char *fmt; ! 1430: { ! 1431: register char *p, *bp, ch; ! 1432: register int i; ! 1433: char buf[BUFSIZ]; ! 1434: ! 1435: (void) sprintf(buf, fmt, a, b, c); ! 1436: ! 1437: /* make ps print our process name */ ! 1438: p = Argv[0]; ! 1439: *p++ = '-'; ! 1440: ! 1441: i = strlen(buf); ! 1442: if (i > LastArgv - p - 2) { ! 1443: i = LastArgv - p - 2; ! 1444: buf[i] = '\0'; ! 1445: } ! 1446: bp = buf; ! 1447: while (ch = *bp++) ! 1448: if (ch != '\n' && ch != '\r') ! 1449: *p++ = ch; ! 1450: while (p < LastArgv) ! 1451: *p++ = ' '; ! 1452: } ! 1453: #endif /* SETPROCTITLE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.