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
cwd defined in line 1060; used 3 times
dataconn defined in line 660; used 5 times
delete defined in line 1036; used 1 times
dolog defined in line 1121; used 1 times
dologout defined in line 1150; used 8 times
end_login defined in line 401; used 2 times
fatal defined in line 974; used 2 times
getdatasock defined in line 626; used 2 times
gunique defined in line 1239; used 2 times
lostconn defined in line 251; used 2 times
lreply defined in line 999; used 5 times
main defined in line 133; never used
makedir defined in line 1069; used 1 times
myoob defined in line 1161; used 2 times
nack defined in line 1019; used 2 times
pass defined in line 412; used 1 times
passive defined in line 1195; used 1 times
perror_reply defined in line 1271; used 33 times
pwd defined in line 1087; used 1 times
receive_data defined in line 815; used 1 times
removedir defined in line 1078; used 1 times
renamecmd defined in line 1112; used 1 times
renamefrom defined in line 1098; used 2 times
reply defined in line 984; used 93 times
retrieve defined in line 502; used 4 times
send_data defined in line 736; used 1 times
send_file_list defined in line 1283; used 2 times
setproctitle defined in line 1414; used 4 times
sgetpwnam defined in line 285; used 2 times
sgetsave defined in line 264; used 6 times
statcmd defined in line 922; used 1 times
statfilecmd defined in line 891; used 1 times
store defined in line 560; used 3 times
user defined in line 328; used 1 times
yyerror defined in line 1026; used 1 times

Defined variables

Argv defined in line 128; used 2 times
LastArgv defined in line 129; used 4 times
askpasswd defined in line 312; used 5 times
byte_count defined in line 102; used 9 times
copyright defined in line 19; never used
ctrl_addr defined in line 79; used 5 times
data defined in line 85; used 13 times
data_dest defined in line 81; used 4 times
data_source defined in line 80; used 7 times
debug defined in line 89; used 6 times
defumask defined in line 107; used 2 times
errcatch defined in line 86; used 4 times
file_size defined in line 101; used 3 times
form defined in line 95; used 2 times
guest defined in line 93; used 8 times
his_addr defined in line 82; used 5 times
hostname defined in line 109; used 4 times
logged_in defined in line 87; used 7 times
logging defined in line 92; used 6 times
login_attempts defined in line 311; used 4 times
maxtimeout defined in line 91; used 5 times
mode defined in line 97; used 15 times
onefile defined in line 1278; used 2 times
pasv_addr defined in line 83; used 9 times
pdata defined in line 99; used 19 times
proctitle defined in line 130; used 7 times
pw defined in line 88; used 30 times
remotehost defined in line 110; used 17 times
sccsid defined in line 23; never used
stru defined in line 96; used 2 times
swaitint defined in line 121; used 2 times
swaitmax defined in line 120; used 1 times
timeout defined in line 90; used 5 times
tmpline defined in line 108; used 3 times
transflag defined in line 100; used 23 times
ttyline defined in line 259; used 4 times
type defined in line 94; used 16 times
urgcatch defined in line 86; used 4 times
usedefault defined in line 98; used 4 times

Defined macros

CMASK defined in line 105; used 4 times
FTP_NAMES defined in line 39; never used
MAXHOSTNAMELEN defined in line 57; used 3 times
SWAITINT defined in line 118; used 1 times
SWAITMAX defined in line 117; used 1 times
UC defined in line 1221; used 13 times
Last modified: 1996-03-23
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 11292
Valid CSS Valid XHTML 1.0 Strict