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