|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.