1: /*
   2:  * Copyright (c) 1985 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1985 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)ftpd.c	5.7 (Berkeley) 5/28/86";
  15: #endif not lint
  16: 
  17: /*
  18:  * FTP server.
  19:  */
  20: #include <sys/param.h>
  21: #include <sys/stat.h>
  22: #include <sys/ioctl.h>
  23: #include <sys/socket.h>
  24: #include <sys/file.h>
  25: #include <sys/wait.h>
  26: 
  27: #include <netinet/in.h>
  28: 
  29: #include <arpa/ftp.h>
  30: #include <arpa/inet.h>
  31: #include <arpa/telnet.h>
  32: 
  33: #include <stdio.h>
  34: #include <signal.h>
  35: #include <pwd.h>
  36: #include <setjmp.h>
  37: #include <netdb.h>
  38: #include <errno.h>
  39: #include <strings.h>
  40: #include <syslog.h>
  41: 
  42: /*
  43:  * File containing login names
  44:  * NOT to be used on this machine.
  45:  * Commonly used to disallow uucp.
  46:  */
  47: #define FTPUSERS    "/etc/ftpusers"
  48: 
  49: extern  int errno;
  50: extern  char *sys_errlist[];
  51: extern  char *crypt();
  52: extern  char version[];
  53: extern  char *home;     /* pointer to home directory for glob */
  54: extern  FILE *popen(), *fopen(), *freopen();
  55: extern  int  pclose(), fclose();
  56: extern  char *getline();
  57: extern  char cbuf[];
  58: 
  59: struct  sockaddr_in ctrl_addr;
  60: struct  sockaddr_in data_source;
  61: struct  sockaddr_in data_dest;
  62: struct  sockaddr_in his_addr;
  63: 
  64: int data;
  65: jmp_buf errcatch, urgcatch;
  66: int logged_in;
  67: struct  passwd *pw;
  68: int debug;
  69: int timeout = 900;    /* timeout after 15 minutes of inactivity */
  70: int logging;
  71: int guest;
  72: int wtmp;
  73: int type;
  74: int form;
  75: int stru;           /* avoid C keyword */
  76: int mode;
  77: int usedefault = 1;     /* for data transfers */
  78: int pdata;          /* for passive mode */
  79: int unique;
  80: int transflag;
  81: char    tmpline[7];
  82: char    hostname[32];
  83: char    remotehost[32];
  84: 
  85: /*
  86:  * Timeout intervals for retrying connections
  87:  * to hosts that don't accept PORT cmds.  This
  88:  * is a kludge, but given the problems with TCP...
  89:  */
  90: #define SWAITMAX    90  /* wait at most 90 seconds */
  91: #define SWAITINT    5   /* interval between retries */
  92: 
  93: int swaitmax = SWAITMAX;
  94: int swaitint = SWAITINT;
  95: 
  96: int lostconn();
  97: int myoob();
  98: FILE    *getdatasock(), *dataconn();
  99: 
 100: main(argc, argv)
 101:     int argc;
 102:     char *argv[];
 103: {
 104:     int addrlen, on = 1;
 105:     long pgid;
 106:     char *cp;
 107: 
 108:     addrlen = sizeof (his_addr);
 109:     if (getpeername(0, &his_addr, &addrlen) < 0) {
 110:         syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
 111:         exit(1);
 112:     }
 113:     addrlen = sizeof (ctrl_addr);
 114:     if (getsockname(0, (char *) &ctrl_addr, &addrlen) < 0) {
 115:         syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
 116:         exit(1);
 117:     }
 118:     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
 119:     debug = 0;
 120:     openlog("ftpd", LOG_PID, LOG_DAEMON);
 121:     argc--, argv++;
 122:     while (argc > 0 && *argv[0] == '-') {
 123:         for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
 124: 
 125:         case 'v':
 126:             debug = 1;
 127:             break;
 128: 
 129:         case 'd':
 130:             debug = 1;
 131:             break;
 132: 
 133:         case 'l':
 134:             logging = 1;
 135:             break;
 136: 
 137:         case 't':
 138:             timeout = atoi(++cp);
 139:             goto nextopt;
 140:             break;
 141: 
 142:         default:
 143:             fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
 144:                  *cp);
 145:             break;
 146:         }
 147: nextopt:
 148:         argc--, argv++;
 149:     }
 150:     (void) signal(SIGPIPE, lostconn);
 151:     (void) signal(SIGCHLD, SIG_IGN);
 152:     if (signal(SIGURG, myoob) < 0) {
 153:         syslog(LOG_ERR, "signal: %m");
 154:     }
 155:     /* handle urgent data inline */
 156: #ifdef SO_OOBINLINE
 157:     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) {
 158:         syslog(LOG_ERR, "setsockopt: %m");
 159:     }
 160: #endif SO_OOBINLINE
 161:     pgid = getpid();
 162:     if (ioctl(fileno(stdin), SIOCSPGRP, (char *) &pgid) < 0) {
 163:         syslog(LOG_ERR, "ioctl: %m");
 164:     }
 165:     dolog(&his_addr);
 166:     /* do telnet option negotiation here */
 167:     /*
 168: 	 * Set up default state
 169: 	 */
 170:     logged_in = 0;
 171:     data = -1;
 172:     type = TYPE_A;
 173:     form = FORM_N;
 174:     stru = STRU_F;
 175:     mode = MODE_S;
 176:     tmpline[0] = '\0';
 177:     (void) gethostname(hostname, sizeof (hostname));
 178:     reply(220, "%s FTP server (%s) ready.",
 179:         hostname, version);
 180:     for (;;) {
 181:         (void) setjmp(errcatch);
 182:         (void) yyparse();
 183:     }
 184: }
 185: 
 186: lostconn()
 187: {
 188: 
 189:     if (debug)
 190:         syslog(LOG_DEBUG, "lost connection");
 191:     dologout(-1);
 192: }
 193: 
 194: pass(passwd)
 195:     char *passwd;
 196: {
 197:     char *xpasswd, *savestr();
 198:     static struct passwd save;
 199: 
 200:     if (logged_in || pw == NULL) {
 201:         reply(503, "Login with USER first.");
 202:         return;
 203:     }
 204:     if (!guest) {       /* "ftp" is only account allowed no password */
 205:         xpasswd = crypt(passwd, pw->pw_passwd);
 206:         /* The strcmp does not catch null passwords! */
 207:         if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
 208:             reply(530, "Login incorrect.");
 209:             pw = NULL;
 210:             return;
 211:         }
 212:     }
 213:     setegid(pw->pw_gid);
 214:     initgroups(pw->pw_name, pw->pw_gid);
 215:     if (chdir(pw->pw_dir)) {
 216:         reply(530, "User %s: can't change directory to %s.",
 217:             pw->pw_name, pw->pw_dir);
 218:         goto bad;
 219:     }
 220: 
 221:     /* grab wtmp before chroot */
 222:     wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
 223:     if (guest && chroot(pw->pw_dir) < 0) {
 224:         reply(550, "Can't set guest privileges.");
 225:         if (wtmp >= 0) {
 226:             (void) close(wtmp);
 227:             wtmp = -1;
 228:         }
 229:         goto bad;
 230:     }
 231:     if (!guest)
 232:         reply(230, "User %s logged in.", pw->pw_name);
 233:     else
 234:         reply(230, "Guest login ok, access restrictions apply.");
 235:     logged_in = 1;
 236:     dologin(pw);
 237:     seteuid(pw->pw_uid);
 238:     /*
 239: 	 * Save everything so globbing doesn't
 240: 	 * clobber the fields.
 241: 	 */
 242:     save = *pw;
 243:     save.pw_name = savestr(pw->pw_name);
 244:     save.pw_passwd = savestr(pw->pw_passwd);
 245:     save.pw_comment = savestr(pw->pw_comment);
 246:     save.pw_gecos = savestr(pw->pw_gecos);
 247:     save.pw_dir = savestr(pw->pw_dir);
 248:     save.pw_shell = savestr(pw->pw_shell);
 249:     pw = &save;
 250:     home = pw->pw_dir;      /* home dir for globbing */
 251:     return;
 252: bad:
 253:     seteuid(0);
 254:     pw = NULL;
 255: }
 256: 
 257: char *
 258: savestr(s)
 259:     char *s;
 260: {
 261:     char *malloc();
 262:     char *new = malloc((unsigned) strlen(s) + 1);
 263: 
 264:     if (new != NULL)
 265:         (void) strcpy(new, s);
 266:     return (new);
 267: }
 268: 
 269: retrieve(cmd, name)
 270:     char *cmd, *name;
 271: {
 272:     FILE *fin, *dout;
 273:     struct stat st;
 274:     int (*closefunc)(), tmp;
 275: 
 276:     if (cmd == 0) {
 277: #ifdef notdef
 278:         /* no remote command execution -- it's a security hole */
 279:         if (*name == '|')
 280:             fin = popen(name + 1, "r"), closefunc = pclose;
 281:         else
 282: #endif
 283:             fin = fopen(name, "r"), closefunc = fclose;
 284:     } else {
 285:         char line[BUFSIZ];
 286: 
 287:         (void) sprintf(line, cmd, name), name = line;
 288:         fin = popen(line, "r"), closefunc = pclose;
 289:     }
 290:     if (fin == NULL) {
 291:         if (errno != 0)
 292:             reply(550, "%s: %s.", name, sys_errlist[errno]);
 293:         return;
 294:     }
 295:     st.st_size = 0;
 296:     if (cmd == 0 &&
 297:         (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
 298:         reply(550, "%s: not a plain file.", name);
 299:         goto done;
 300:     }
 301:     dout = dataconn(name, st.st_size, "w");
 302:     if (dout == NULL)
 303:         goto done;
 304:     if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) {
 305:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 306:     }
 307:     else if (tmp == 0) {
 308:         reply(226, "Transfer complete.");
 309:     }
 310:     (void) fclose(dout);
 311:     data = -1;
 312:     pdata = -1;
 313: done:
 314:     (*closefunc)(fin);
 315: }
 316: 
 317: store(name, mode)
 318:     char *name, *mode;
 319: {
 320:     FILE *fout, *din;
 321:     int (*closefunc)(), dochown = 0, tmp;
 322:     char *gunique(), *local;
 323: 
 324: #ifdef notdef
 325:     /* no remote command execution -- it's a security hole */
 326:     if (name[0] == '|')
 327:         fout = popen(&name[1], "w"), closefunc = pclose;
 328:     else
 329: #endif
 330:     {
 331:         struct stat st;
 332: 
 333:         local = name;
 334:         if (stat(name, &st) < 0) {
 335:             dochown++;
 336:         }
 337:         else if (unique) {
 338:             if ((local = gunique(name)) == NULL) {
 339:                 return;
 340:             }
 341:             dochown++;
 342:         }
 343:         fout = fopen(local, mode), closefunc = fclose;
 344:     }
 345:     if (fout == NULL) {
 346:         reply(553, "%s: %s.", local, sys_errlist[errno]);
 347:         return;
 348:     }
 349:     din = dataconn(local, (off_t)-1, "r");
 350:     if (din == NULL)
 351:         goto done;
 352:     if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) {
 353:         reply(552, "%s: %s.", local, sys_errlist[errno]);
 354:     }
 355:     else if (tmp == 0 && !unique) {
 356:         reply(226, "Transfer complete.");
 357:     }
 358:     else if (tmp == 0 && unique) {
 359:         reply(226, "Transfer complete (unique file name:%s).", local);
 360:     }
 361:     (void) fclose(din);
 362:     data = -1;
 363:     pdata = -1;
 364: done:
 365:     if (dochown)
 366:         (void) chown(local, pw->pw_uid, -1);
 367:     (*closefunc)(fout);
 368: }
 369: 
 370: FILE *
 371: getdatasock(mode)
 372:     char *mode;
 373: {
 374:     int s, on = 1;
 375: 
 376:     if (data >= 0)
 377:         return (fdopen(data, mode));
 378:     s = socket(AF_INET, SOCK_STREAM, 0);
 379:     if (s < 0)
 380:         return (NULL);
 381:     seteuid(0);
 382:     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0)
 383:         goto bad;
 384:     /* anchor socket to avoid multi-homing problems */
 385:     data_source.sin_family = AF_INET;
 386:     data_source.sin_addr = ctrl_addr.sin_addr;
 387:     if (bind(s, &data_source, sizeof (data_source)) < 0)
 388:         goto bad;
 389:     seteuid(pw->pw_uid);
 390:     return (fdopen(s, mode));
 391: bad:
 392:     seteuid(pw->pw_uid);
 393:     (void) close(s);
 394:     return (NULL);
 395: }
 396: 
 397: FILE *
 398: dataconn(name, size, mode)
 399:     char *name;
 400:     off_t size;
 401:     char *mode;
 402: {
 403:     char sizebuf[32];
 404:     FILE *file;
 405:     int retry = 0;
 406: 
 407:     if (size >= 0)
 408:         (void) sprintf (sizebuf, " (%ld bytes)", size);
 409:     else
 410:         (void) strcpy(sizebuf, "");
 411:     if (pdata > 0) {
 412:         struct sockaddr_in from;
 413:         int s, fromlen = sizeof(from);
 414: 
 415:         s = accept(pdata, &from, &fromlen);
 416:         if (s < 0) {
 417:             reply(425, "Can't open data connection.");
 418:             (void) close(pdata);
 419:             pdata = -1;
 420:             return(NULL);
 421:         }
 422:         (void) close(pdata);
 423:         pdata = s;
 424:         reply(150, "Openning data connection for %s (%s,%d)%s.",
 425:              name, inet_ntoa(from.sin_addr),
 426:              ntohs(from.sin_port), sizebuf);
 427:         return(fdopen(pdata, mode));
 428:     }
 429:     if (data >= 0) {
 430:         reply(125, "Using existing data connection for %s%s.",
 431:             name, sizebuf);
 432:         usedefault = 1;
 433:         return (fdopen(data, mode));
 434:     }
 435:     if (usedefault)
 436:         data_dest = his_addr;
 437:     usedefault = 1;
 438:     file = getdatasock(mode);
 439:     if (file == NULL) {
 440:         reply(425, "Can't create data socket (%s,%d): %s.",
 441:             inet_ntoa(data_source.sin_addr),
 442:             ntohs(data_source.sin_port),
 443:             sys_errlist[errno]);
 444:         return (NULL);
 445:     }
 446:     data = fileno(file);
 447:     while (connect(data, &data_dest, sizeof (data_dest)) < 0) {
 448:         if (errno == EADDRINUSE && retry < swaitmax) {
 449:             sleep((unsigned) swaitint);
 450:             retry += swaitint;
 451:             continue;
 452:         }
 453:         reply(425, "Can't build data connection: %s.",
 454:             sys_errlist[errno]);
 455:         (void) fclose(file);
 456:         data = -1;
 457:         return (NULL);
 458:     }
 459:     reply(150, "Opening data connection for %s (%s,%d)%s.",
 460:         name, inet_ntoa(data_dest.sin_addr),
 461:         ntohs(data_dest.sin_port), sizebuf);
 462:     return (file);
 463: }
 464: 
 465: /*
 466:  * Tranfer the contents of "instr" to
 467:  * "outstr" peer using the appropriate
 468:  * encapulation of the date subject
 469:  * to Mode, Structure, and Type.
 470:  *
 471:  * NB: Form isn't handled.
 472:  */
 473: send_data(instr, outstr)
 474:     FILE *instr, *outstr;
 475: {
 476:     register int c;
 477:     int netfd, filefd, cnt;
 478:     char buf[BUFSIZ];
 479: 
 480:     transflag++;
 481:     if (setjmp(urgcatch)) {
 482:         transflag = 0;
 483:         return(-1);
 484:     }
 485:     switch (type) {
 486: 
 487:     case TYPE_A:
 488:         while ((c = getc(instr)) != EOF) {
 489:             if (c == '\n') {
 490:                 if (ferror (outstr)) {
 491:                     transflag = 0;
 492:                     return (1);
 493:                 }
 494:                 (void) putc('\r', outstr);
 495:             }
 496:             (void) putc(c, outstr);
 497:         /*	if (c == '\r')			*/
 498:         /*		putc ('\0', outstr);	*/
 499:         }
 500:         transflag = 0;
 501:         if (ferror (instr) || ferror (outstr)) {
 502:             return (1);
 503:         }
 504:         return (0);
 505: 
 506:     case TYPE_I:
 507:     case TYPE_L:
 508:         netfd = fileno(outstr);
 509:         filefd = fileno(instr);
 510: 
 511:         while ((cnt = read(filefd, buf, sizeof (buf))) > 0) {
 512:             if (write(netfd, buf, cnt) < 0) {
 513:                 transflag = 0;
 514:                 return (1);
 515:             }
 516:         }
 517:         transflag = 0;
 518:         return (cnt < 0);
 519:     }
 520:     reply(550, "Unimplemented TYPE %d in send_data", type);
 521:     transflag = 0;
 522:     return (-1);
 523: }
 524: 
 525: /*
 526:  * Transfer data from peer to
 527:  * "outstr" using the appropriate
 528:  * encapulation of the data subject
 529:  * to Mode, Structure, and Type.
 530:  *
 531:  * N.B.: Form isn't handled.
 532:  */
 533: receive_data(instr, outstr)
 534:     FILE *instr, *outstr;
 535: {
 536:     register int c;
 537:     int cnt;
 538:     char buf[BUFSIZ];
 539: 
 540: 
 541:     transflag++;
 542:     if (setjmp(urgcatch)) {
 543:         transflag = 0;
 544:         return(-1);
 545:     }
 546:     switch (type) {
 547: 
 548:     case TYPE_I:
 549:     case TYPE_L:
 550:         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
 551:             if (write(fileno(outstr), buf, cnt) < 0) {
 552:                 transflag = 0;
 553:                 return (1);
 554:             }
 555:         }
 556:         transflag = 0;
 557:         return (cnt < 0);
 558: 
 559:     case TYPE_E:
 560:         reply(553, "TYPE E not implemented.");
 561:         transflag = 0;
 562:         return (-1);
 563: 
 564:     case TYPE_A:
 565:         while ((c = getc(instr)) != EOF) {
 566:             while (c == '\r') {
 567:                 if (ferror (outstr)) {
 568:                     transflag = 0;
 569:                     return (1);
 570:                 }
 571:                 if ((c = getc(instr)) != '\n')
 572:                     (void) putc ('\r', outstr);
 573:             /*	if (c == '\0')			*/
 574:             /*		continue;		*/
 575:             }
 576:             (void) putc (c, outstr);
 577:         }
 578:         transflag = 0;
 579:         if (ferror (instr) || ferror (outstr))
 580:             return (1);
 581:         return (0);
 582:     }
 583:     transflag = 0;
 584:     fatal("Unknown type in receive_data.");
 585:     /*NOTREACHED*/
 586: }
 587: 
 588: fatal(s)
 589:     char *s;
 590: {
 591:     reply(451, "Error in server: %s\n", s);
 592:     reply(221, "Closing connection due to server error.");
 593:     dologout(0);
 594: }
 595: 
 596: /*VARARGS2*/
 597: reply(n, s, args)
 598:     int n;
 599:     char *s;
 600: {
 601: 
 602:     printf("%d ", n);
 603:     _doprnt(s, &args, stdout);
 604:     printf("\r\n");
 605:     (void) fflush(stdout);
 606:     if (debug) {
 607:         syslog(LOG_DEBUG, "<--- %d ", n);
 608:         syslog(LOG_DEBUG, s, &args);
 609:     }
 610: }
 611: 
 612: /*VARARGS2*/
 613: lreply(n, s, args)
 614:     int n;
 615:     char *s;
 616: {
 617:     printf("%d-", n);
 618:     _doprnt(s, &args, stdout);
 619:     printf("\r\n");
 620:     (void) fflush(stdout);
 621:     if (debug) {
 622:         syslog(LOG_DEBUG, "<--- %d- ", n);
 623:         syslog(LOG_DEBUG, s, &args);
 624:     }
 625: }
 626: 
 627: ack(s)
 628:     char *s;
 629: {
 630:     reply(250, "%s command successful.", s);
 631: }
 632: 
 633: nack(s)
 634:     char *s;
 635: {
 636:     reply(502, "%s command not implemented.", s);
 637: }
 638: 
 639: yyerror(s)
 640:     char *s;
 641: {
 642:     char *cp;
 643: 
 644:     cp = index(cbuf,'\n');
 645:     *cp = '\0';
 646:     reply(500, "'%s': command not understood.",cbuf);
 647: }
 648: 
 649: delete(name)
 650:     char *name;
 651: {
 652:     struct stat st;
 653: 
 654:     if (stat(name, &st) < 0) {
 655:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 656:         return;
 657:     }
 658:     if ((st.st_mode&S_IFMT) == S_IFDIR) {
 659:         if (rmdir(name) < 0) {
 660:             reply(550, "%s: %s.", name, sys_errlist[errno]);
 661:             return;
 662:         }
 663:         goto done;
 664:     }
 665:     if (unlink(name) < 0) {
 666:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 667:         return;
 668:     }
 669: done:
 670:     ack("DELE");
 671: }
 672: 
 673: cwd(path)
 674:     char *path;
 675: {
 676: 
 677:     if (chdir(path) < 0) {
 678:         reply(550, "%s: %s.", path, sys_errlist[errno]);
 679:         return;
 680:     }
 681:     ack("CWD");
 682: }
 683: 
 684: makedir(name)
 685:     char *name;
 686: {
 687:     struct stat st;
 688:     int dochown = stat(name, &st) < 0;
 689: 
 690:     if (mkdir(name, 0777) < 0) {
 691:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 692:         return;
 693:     }
 694:     if (dochown)
 695:         (void) chown(name, pw->pw_uid, -1);
 696:     reply(257, "MKD command successful.");
 697: }
 698: 
 699: removedir(name)
 700:     char *name;
 701: {
 702: 
 703:     if (rmdir(name) < 0) {
 704:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 705:         return;
 706:     }
 707:     ack("RMD");
 708: }
 709: 
 710: pwd()
 711: {
 712:     char path[MAXPATHLEN + 1];
 713: 
 714:     if (getwd(path) == NULL) {
 715:         reply(550, "%s.", path);
 716:         return;
 717:     }
 718:     reply(257, "\"%s\" is current directory.", path);
 719: }
 720: 
 721: char *
 722: renamefrom(name)
 723:     char *name;
 724: {
 725:     struct stat st;
 726: 
 727:     if (stat(name, &st) < 0) {
 728:         reply(550, "%s: %s.", name, sys_errlist[errno]);
 729:         return ((char *)0);
 730:     }
 731:     reply(350, "File exists, ready for destination name");
 732:     return (name);
 733: }
 734: 
 735: renamecmd(from, to)
 736:     char *from, *to;
 737: {
 738: 
 739:     if (rename(from, to) < 0) {
 740:         reply(550, "rename: %s.", sys_errlist[errno]);
 741:         return;
 742:     }
 743:     ack("RNTO");
 744: }
 745: 
 746: dolog(sin)
 747:     struct sockaddr_in *sin;
 748: {
 749:     struct hostent *hp = gethostbyaddr(&sin->sin_addr,
 750:         sizeof (struct in_addr), AF_INET);
 751:     time_t t;
 752:     extern char *ctime();
 753: 
 754:     if (hp) {
 755:         (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
 756:         endhostent();
 757:     } else
 758:         (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
 759:             sizeof (remotehost));
 760:     if (!logging)
 761:         return;
 762:     t = time((time_t *) 0);
 763:     syslog(LOG_INFO,"FTPD: connection from %s at %s", remotehost, ctime(&t));
 764: }
 765: 
 766: #include <utmp.h>
 767: 
 768: #define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
 769: struct  utmp utmp;
 770: 
 771: /*
 772:  * Record login in wtmp file.
 773:  */
 774: dologin(pw)
 775:     struct passwd *pw;
 776: {
 777:     char line[32];
 778: 
 779:     if (wtmp >= 0) {
 780:         /* hack, but must be unique and no tty line */
 781:         (void) sprintf(line, "ftp%d", getpid());
 782:         SCPYN(utmp.ut_line, line);
 783:         SCPYN(utmp.ut_name, pw->pw_name);
 784:         SCPYN(utmp.ut_host, remotehost);
 785:         utmp.ut_time = (long) time((time_t *) 0);
 786:         (void) write(wtmp, (char *)&utmp, sizeof (utmp));
 787:         if (!guest) {       /* anon must hang on */
 788:             (void) close(wtmp);
 789:             wtmp = -1;
 790:         }
 791:     }
 792: }
 793: 
 794: /*
 795:  * Record logout in wtmp file
 796:  * and exit with supplied status.
 797:  */
 798: dologout(status)
 799:     int status;
 800: {
 801: 
 802:     if (logged_in) {
 803:         (void) seteuid(0);
 804:         if (wtmp < 0)
 805:             wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
 806:         if (wtmp >= 0) {
 807:             SCPYN(utmp.ut_name, "");
 808:             SCPYN(utmp.ut_host, "");
 809:             utmp.ut_time = (long) time((time_t *) 0);
 810:             (void) write(wtmp, (char *)&utmp, sizeof (utmp));
 811:             (void) close(wtmp);
 812:         }
 813:     }
 814:     /* beware of flushing buffers after a SIGPIPE */
 815:     _exit(status);
 816: }
 817: 
 818: /*
 819:  * Special version of popen which avoids
 820:  * call to shell.  This insures noone may
 821:  * create a pipe to a hidden program as a side
 822:  * effect of a list or dir command.
 823:  */
 824: #define tst(a,b)    (*mode == 'r'? (b) : (a))
 825: #define RDR 0
 826: #define WTR 1
 827: static  int popen_pid[5];
 828: 
 829: static char *
 830: nextarg(cpp)
 831:     char *cpp;
 832: {
 833:     register char *cp = cpp;
 834: 
 835:     if (cp == 0)
 836:         return (cp);
 837:     while (*cp && *cp != ' ' && *cp != '\t')
 838:         cp++;
 839:     if (*cp == ' ' || *cp == '\t') {
 840:         *cp++ = '\0';
 841:         while (*cp == ' ' || *cp == '\t')
 842:             cp++;
 843:     }
 844:     if (cp == cpp)
 845:         return ((char *)0);
 846:     return (cp);
 847: }
 848: 
 849: FILE *
 850: popen(cmd, mode)
 851:     char *cmd, *mode;
 852: {
 853:     int p[2], ac, gac;
 854:     register myside, hisside, pid;
 855:     char *av[20], *gav[512];
 856:     register char *cp;
 857: 
 858:     if (pipe(p) < 0)
 859:         return (NULL);
 860:     cp = cmd, ac = 0;
 861:     /* break up string into pieces */
 862:     do {
 863:         av[ac++] = cp;
 864:         cp = nextarg(cp);
 865:     } while (cp && *cp && ac < 20);
 866:     av[ac] = (char *)0;
 867:     gav[0] = av[0];
 868:     /* glob each piece */
 869:     for (gac = ac = 1; av[ac] != NULL; ac++) {
 870:         char **pop;
 871:         extern char **glob(), **copyblk();
 872: 
 873:         pop = glob(av[ac]);
 874:         if (pop == (char **)NULL) { /* globbing failed */
 875:             char *vv[2];
 876: 
 877:             vv[0] = av[ac];
 878:             vv[1] = 0;
 879:             pop = copyblk(vv);
 880:         }
 881:         av[ac] = (char *)pop;       /* save to free later */
 882:         while (*pop && gac < 512)
 883:             gav[gac++] = *pop++;
 884:     }
 885:     gav[gac] = (char *)0;
 886:     myside = tst(p[WTR], p[RDR]);
 887:     hisside = tst(p[RDR], p[WTR]);
 888:     if ((pid = fork()) == 0) {
 889:         /* myside and hisside reverse roles in child */
 890:         (void) close(myside);
 891:         (void) dup2(hisside, tst(0, 1));
 892:         (void) close(hisside);
 893:         execv(gav[0], gav);
 894:         _exit(1);
 895:     }
 896:     for (ac = 1; av[ac] != NULL; ac++)
 897:         blkfree((char **)av[ac]);
 898:     if (pid == -1)
 899:         return (NULL);
 900:     popen_pid[myside] = pid;
 901:     (void) close(hisside);
 902:     return (fdopen(myside, mode));
 903: }
 904: 
 905: pclose(ptr)
 906:     FILE *ptr;
 907: {
 908:     register f, r, (*hstat)(), (*istat)(), (*qstat)();
 909:     int status;
 910: 
 911:     f = fileno(ptr);
 912:     (void) fclose(ptr);
 913:     istat = signal(SIGINT, SIG_IGN);
 914:     qstat = signal(SIGQUIT, SIG_IGN);
 915:     hstat = signal(SIGHUP, SIG_IGN);
 916:     while ((r = wait(&status)) != popen_pid[f] && r != -1)
 917:         ;
 918:     if (r == -1)
 919:         status = -1;
 920:     (void) signal(SIGINT, istat);
 921:     (void) signal(SIGQUIT, qstat);
 922:     (void) signal(SIGHUP, hstat);
 923:     return (status);
 924: }
 925: 
 926: /*
 927:  * Check user requesting login priviledges.
 928:  * Disallow anyone who does not have a standard
 929:  * shell returned by getusershell() (/etc/shells).
 930:  * Disallow anyone mentioned in the file FTPUSERS
 931:  * to allow people such as uucp to be avoided.
 932:  */
 933: checkuser(name)
 934:     register char *name;
 935: {
 936:     register char *cp;
 937:     char line[BUFSIZ], *index(), *getusershell();
 938:     FILE *fd;
 939:     struct passwd *pw;
 940:     int found = 0;
 941: 
 942:     pw = getpwnam(name);
 943:     if (pw == NULL)
 944:         return (0);
 945:     while ((cp = getusershell()) != NULL)
 946:         if (strcmp(cp, pw->pw_shell) == 0)
 947:             break;
 948:     endpwent();
 949:     endusershell();
 950:     if (cp == NULL)
 951:         return (0);
 952:     fd = fopen(FTPUSERS, "r");
 953:     if (fd == NULL)
 954:         return (1);
 955:     while (fgets(line, sizeof (line), fd) != NULL) {
 956:         cp = index(line, '\n');
 957:         if (cp)
 958:             *cp = '\0';
 959:         if (strcmp(line, name) == 0) {
 960:             found++;
 961:             break;
 962:         }
 963:     }
 964:     (void) fclose(fd);
 965:     return (!found);
 966: }
 967: 
 968: myoob()
 969: {
 970:     char *cp;
 971: 
 972:     /* only process if transfer occurring */
 973:     if (!transflag) {
 974:         return;
 975:     }
 976:     cp = tmpline;
 977:     if (getline(cp, 7, stdin) == NULL) {
 978:         reply(221, "You could at least say goodby.");
 979:         dologout(0);
 980:     }
 981:     upper(cp);
 982:     if (strcmp(cp, "ABOR\r\n"))
 983:         return;
 984:     tmpline[0] = '\0';
 985:     reply(426,"Transfer aborted. Data connection closed.");
 986:     reply(226,"Abort successful");
 987:     longjmp(urgcatch, 1);
 988: }
 989: 
 990: /*
 991:  * Note: The 530 reply codes could be 4xx codes, except nothing is
 992:  * given in the state tables except 421 which implies an exit.  (RFC959)
 993:  */
 994: passive()
 995: {
 996:     int len;
 997:     struct sockaddr_in tmp;
 998:     register char *p, *a;
 999: 
1000:     pdata = socket(AF_INET, SOCK_STREAM, 0);
1001:     if (pdata < 0) {
1002:         reply(530, "Can't open passive connection");
1003:         return;
1004:     }
1005:     tmp = ctrl_addr;
1006:     tmp.sin_port = 0;
1007:     seteuid(0);
1008:     if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) {
1009:         seteuid(pw->pw_uid);
1010:         (void) close(pdata);
1011:         pdata = -1;
1012:         reply(530, "Can't open passive connection");
1013:         return;
1014:     }
1015:     seteuid(pw->pw_uid);
1016:     len = sizeof(tmp);
1017:     if (getsockname(pdata, (char *) &tmp, &len) < 0) {
1018:         (void) close(pdata);
1019:         pdata = -1;
1020:         reply(530, "Can't open passive connection");
1021:         return;
1022:     }
1023:     if (listen(pdata, 1) < 0) {
1024:         (void) close(pdata);
1025:         pdata = -1;
1026:         reply(530, "Can't open passive connection");
1027:         return;
1028:     }
1029:     a = (char *) &tmp.sin_addr;
1030:     p = (char *) &tmp.sin_port;
1031: 
1032: #define UC(b) (((int) b) & 0xff)
1033: 
1034:     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1035:         UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1036: }
1037: 
1038: char *
1039: gunique(local)
1040:     char *local;
1041: {
1042:     static char new[MAXPATHLEN];
1043:     char *cp = rindex(local, '/');
1044:     int d, count=0;
1045:     char ext = '1';
1046: 
1047:     if (cp) {
1048:         *cp = '\0';
1049:     }
1050:     d = access(cp ? local : ".", 2);
1051:     if (cp) {
1052:         *cp = '/';
1053:     }
1054:     if (d < 0) {
1055:         syslog(LOG_ERR, "%s: %m", local);
1056:         return((char *) 0);
1057:     }
1058:     (void) strcpy(new, local);
1059:     cp = new + strlen(new);
1060:     *cp++ = '.';
1061:     while (!d) {
1062:         if (++count == 100) {
1063:             reply(452, "Unique file name not cannot be created.");
1064:             return((char *) 0);
1065:         }
1066:         *cp++ = ext;
1067:         *cp = '\0';
1068:         if (ext == '9') {
1069:             ext = '0';
1070:         }
1071:         else {
1072:             ext++;
1073:         }
1074:         if ((d = access(new, 0)) < 0) {
1075:             break;
1076:         }
1077:         if (ext != '0') {
1078:             cp--;
1079:         }
1080:         else if (*(cp - 2) == '.') {
1081:             *(cp - 1) = '1';
1082:         }
1083:         else {
1084:             *(cp - 2) = *(cp - 2) + 1;
1085:             cp--;
1086:         }
1087:     }
1088:     return(new);
1089: }

Defined functions

ack defined in line 627; used 4 times
checkuser defined in line 933; used 1 times
cwd defined in line 673; used 3 times
dataconn defined in line 397; used 3 times
delete defined in line 649; used 1 times
dolog defined in line 746; used 1 times
dologin defined in line 774; used 1 times
dologout defined in line 798; used 6 times
fatal defined in line 588; used 3 times
getdatasock defined in line 370; used 2 times
gunique defined in line 1038; used 2 times
lostconn defined in line 186; used 2 times
lreply defined in line 613; used 1 times
main defined in line 100; never used
makedir defined in line 684; used 1 times
myoob defined in line 968; used 2 times
nack defined in line 633; used 1 times
nextarg defined in line 829; used 1 times
pass defined in line 194; used 1 times
passive defined in line 994; used 1 times
pclose defined in line 905; used 4 times
popen defined in line 849; used 4 times
pwd defined in line 710; used 1 times
receive_data defined in line 533; used 1 times
removedir defined in line 699; used 1 times
renamecmd defined in line 735; used 1 times
renamefrom defined in line 721; used 2 times
reply defined in line 597; used 78 times
retrieve defined in line 269; used 5 times
savestr defined in line 257; used 7 times
send_data defined in line 473; used 1 times
store defined in line 317; used 3 times
yyerror defined in line 639; used 1 times

Defined variables

copyright defined in line 8; never used
ctrl_addr defined in line 59; used 5 times
data defined in line 64; used 10 times
data_dest defined in line 61; used 5 times
data_source defined in line 60; used 7 times
debug defined in line 68; used 6 times
errcatch defined in line 65; used 3 times
form defined in line 74; used 1 times
guest defined in line 71; used 4 times
his_addr defined in line 62; used 4 times
hostname defined in line 82; used 3 times
logged_in defined in line 66; used 4 times
logging defined in line 70; used 2 times
mode defined in line 76; used 17 times
pdata defined in line 78; used 20 times
popen_pid defined in line 827; used 2 times
pw defined in line 67; used 38 times
remotehost defined in line 83; used 6 times
sccsid defined in line 14; never used
stru defined in line 75; used 1 times
swaitint defined in line 94; used 2 times
swaitmax defined in line 93; used 1 times
timeout defined in line 69; used 1 times
tmpline defined in line 81; used 3 times
transflag defined in line 80; used 16 times
type defined in line 73; used 4 times
unique defined in line 79; used 3 times
urgcatch defined in line 65; used 3 times
usedefault defined in line 77; used 3 times
utmp defined in line 769; used 11 times
wtmp defined in line 72; used 13 times

Defined macros

FTPUSERS defined in line 47; used 1 times
RDR defined in line 825; used 2 times
SCPYN defined in line 768; used 5 times
SWAITINT defined in line 91; used 1 times
  • in line 94
SWAITMAX defined in line 90; used 1 times
  • in line 93
UC defined in line 1032; used 6 times
WTR defined in line 826; used 2 times
tst defined in line 824; used 3 times
Last modified: 1986-05-29
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3270
Valid CSS Valid XHTML 1.0 Strict