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) 06/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 } 1101