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