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