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: }