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