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