# 2.11BSD#431 - /usr/src/libexec/ftpd/ftpd.c

##### Functions

    ack               X
    cwd               X
    dataconn          X
    delete            X
    dolog             X
    dologout          X
    end_login         X
    fatal             X
    getdatasock       X
    gunique           X
    lostconn          X
    lreply            X
    main              X
    makedir           X
    myoob             X
    nack              X
    pass              X
    passive           X
    perror_reply      X
    pwd               X
    receive_data      X
    removedir         X
    renamecmd         X
    renamefrom        X
    reply             X
    retrieve          X
    send_data         X
    send_file_list    X
    setproctitle      X
    sgetpwnam         X
    sgetsave          X
    statcmd           X
    statfilecmd       X
    store             X
    user              X
    yyerror           X

##### Variables

    Argv              X
    LastArgv          X
    askpasswd         X
    byte_count        X
    copyright         X
    ctrl_addr         X
    data              X
    data_dest         X
    data_source       X
    debug             X
    defumask          X
    errcatch          X
    file_size         X
    form              X
    guest             X
    his_addr          X
    hostname          X
    logged_in         X
    logging           X
    login_attempts    X
    maxtimeout        X
    mode              X
    pasv_addr         X
    pdata             X
    proctitle         X
    pw                X
    remotehost        X
    stru              X
    swaitint          X
    swaitmax          X
    timeout           X
    tmpline           X
    transflag         X
    type              X
    urgcatch          X
    usedefault        X

##### Macros

    CMASK             X
    FTP_NAMES         X
    MAXHOSTNAMELEN    X
    SWAITINT          X
    SWAITMAX          X
    UC                X

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

#### Defined functions

ack defined in line 1013; used 4 times

- in line 1057, 1066, 1084, 1118

cwd defined in line 1060; used 3 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 279-284(2), 333

dataconn defined in line 660; used 5 times

- in line 125, 549, 609, 1340, 1373

delete defined in line 1036; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 257

dolog defined in line 1121; used 1 times

- in line 233

dologout defined in line 1150; used 8 times

- in line 256, 273, 906, 979, 1171
- in /usr/src/libexec/ftpd/ftpcmd.y line 472, 842, 862

end_login defined in line 401; used 2 times

- in line 341, 499

fatal defined in line 974; used 2 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 1055, 1082

getdatasock defined in line 626; used 2 times

- in line 125, 702

gunique defined in line 1239; used 2 times

- in line 567-570(2)

lostconn defined in line 251; used 2 times

- in line 123, 218

lreply defined in line 999; used 5 times

- in line 467, 870, 900, 927
- in /usr/src/libexec/ftpd/ftpcmd.y line 1112

main defined in line 133; never used
makedir defined in line 1069; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 314

myoob defined in line 1161; used 2 times

- in line 124, 220

nack defined in line 1019; used 2 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 884, 910

pass defined in line 412; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 115

passive defined in line 1195; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 129

perror_reply defined in line 1271; used 33 times

- in line 272, 522, 538, 545, 578, 589, 601-605(2), 718, 774, 799-804(2), 882-887(2), 904, 910, 1042-1047(2), 1053, 1064, 1073, 1082, 1105, 1116, 1202, 1230, 1251, 1304, 1328, 1394
- in /usr/src/libexec/ftpd/ftpcmd.y line 375, 452, 1171

pwd defined in line 1087; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 328

receive_data defined in line 815; used 1 times

- in line 612

removedir defined in line 1078; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 321

renamecmd defined in line 1112; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 264

renamefrom defined in line 1098; used 2 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 481-485(2)

reply defined in line 984; used 93 times

- in line 244, 338, 349-351(2), 362, 375, 387, 418, 431, 458-463(2), 470-474(2), 485, 527, 614-617(2), 682, 689-694(2), 704, 723, 767, 789-793(2), 842, 875, 919, 971, 977-978(2), 1016, 1022, 1033, 1075, 1093-1095(2), 1108, 1170, 1176-1185(4), 1223, 1264, 1275, 1300, 1392-1396(2)
- in /usr/src/libexec/ftpd/ftpcmd.y line 125, 137-149(4), 156-160(2), 171-175(2), 183-196(4), 268, 274, 309, 350, 359-362(2), 372-377(2), 384, 391, 397, 413-419(3), 454, 460, 471, 497, 622, 664, 834, 861, 1135, 1141-1147(3), 1160-1162(2), 1176, 1189-1192(2)

retrieve defined in line 502; used 4 times

- in line 1325
- in /usr/src/libexec/ftpd/ftpcmd.y line 201, 234-239(2)

send_data defined in line 736; used 1 times

- in line 552

send_file_list defined in line 1283; used 2 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 222-227(2)

setproctitle defined in line 1414; used 4 times

- in line 479, 488, 1136
- in /usr/src/libexec/ftpd/ftpcmd.y line 867

sgetpwnam defined in line 285; used 2 times

- in line 346, 354

sgetsave defined in line 264; used 6 times

- in line 291, 303-307(5)

statcmd defined in line 922; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 252

statfilecmd defined in line 891; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 246

store defined in line 560; used 3 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 208, 215, 405

user defined in line 328; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 110

yyerror defined in line 1026; used 1 times

- in /usr/src/libexec/ftpd/ftpcmd.y line 1057

#### Defined variables

Argv defined in line 128; used 2 times

- in line 162, 1424

LastArgv defined in line 129; used 4 times

- in line 165, 1428-1429(2), 1436

askpasswd defined in line 312; used 5 times

- in line 348, 388, 417-421(2), 938

byte_count defined in line 102; used 9 times

- in line 671, 753, 781, 834, 848, 1183-1185(2), 1347, 1385

copyright defined in line 19; never used
ctrl_addr defined in line 79; used 5 times

- in line 151-156(3), 643, 1205

data defined in line 85; used 13 times

- in line 237, 554, 620, 632-633(2), 693-697(2), 710-711(2), 720, 953, 1332, 1401

data_dest defined in line 81; used 4 times

- in line 700, 711-712(2), 961

data_source defined in line 80; used 7 times

- in line 156, 642-646(4), 705-706(2)

debug defined in line 89; used 6 times

- in line 157, 173-177(2), 254, 992, 1007

defumask defined in line 107; used 2 times

- in line 205, 495

errcatch defined in line 86; used 4 times

- in line 245
- in /usr/src/libexec/ftpd/ftpcmd.y line 885, 911, 1059

file_size defined in line 101; used 3 times

- in line 670, 1181-1183(2)

form defined in line 95; used 2 times

- in line 239, 944

guest defined in line 93; used 8 times

- in line 337, 344-347(2), 409, 422, 451, 473, 934

his_addr defined in line 82; used 5 times

- in line 146-147(2), 233, 700, 931

hostname defined in line 109; used 4 times

- in line 243-244(3), 927

logged_in defined in line 87; used 7 times

- in line 336, 405-408(2), 417, 449, 933, 1153

logging defined in line 92; used 6 times

- in line 181, 363, 376, 481, 490, 1139

login_attempts defined in line 311; used 4 times

- in line 393-394(2), 433, 442

maxtimeout defined in line 91; used 5 times

- in line 186-193(5)

mode defined in line 97; used 15 times

- in line 241, 560-561(2), 574-575(2), 627-633(3), 653, 661-664(2), 691, 697-702(2), 952

onefile defined in line 1278; used 2 times

- in line 1308-1309(2)

pasv_addr defined in line 83; used 9 times

- in line 957, 1205-1219(8)

pdata defined in line 99; used 19 times

- in line 555, 621, 676-691(7), 955, 1200-1201(2), 1208, 1214-1216(2), 1228-1229(2), 1333, 1402

proctitle defined in line 130; used 7 times

- in line 476-479(3), 487-488(2), 1135-1136(2)

pw defined in line 88; used 30 times

- in line 346, 354-355(2), 367, 380, 407, 423-432(6), 443-448(4), 457-469(5), 485-494(4), 652-655(2), 937, 1209-1212(2)

remotehost defined in line 110; used 17 times

- in line 366, 379, 436, 448, 476-477(2), 483-492(3), 929-930(2), 1130-1135(5), 1142

sccsid defined in line 23; never used
stru defined in line 96; used 2 times

- in line 240, 952

swaitint defined in line 121; used 2 times

- in line 714-715(2)

swaitmax defined in line 120; used 1 times

- in line 713

timeout defined in line 90; used 5 times

- in line 185-193(5)

tmpline defined in line 108; used 3 times

- in line 242, 1168, 1175

transflag defined in line 100; used 23 times

- in line 744-746(2), 762, 773, 782, 792, 798-803(2), 822-824(2), 838-843(2), 868, 876-886(3), 1166, 1314, 1324, 1331, 1343, 1377, 1398

ttyline defined in line 259; used 4 times

- in line 406, 447-448(2), 1155

type defined in line 94; used 16 times

- in line 238, 531, 582, 690, 724, 749, 793, 827, 875, 942-945(4), 1346, 1381-1384(2)

urgcatch defined in line 86; used 4 times

- in line 745, 823, 1178, 1313

usedefault defined in line 98; used 4 times

- in line 696-701(3), 959

#### Defined macros

CMASK defined in line 105; used 4 times

- in line 103-107(4)

FTP_NAMES defined in line 39; never used
MAXHOSTNAMELEN defined in line 57; used 3 times

- in line 56, 109-110(2)

SWAITINT defined in line 118; used 1 times

- in line 121

SWAITMAX defined in line 117; used 1 times

- in line 120

UC defined in line 1221; used 13 times

- in line 966-968(7), 1223-1224(6)

Last modified: 1996-03-23 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 6372 |