1 #ifndef lint 2 static char sccsid[] = "@(#)ftpd.c 4.29 (Berkeley) 02/10/84"; 3 #endif 4 5 /* 6 * FTP server. 7 */ 8 #include <sys/param.h> 9 #include <sys/stat.h> 10 #include <sys/ioctl.h> 11 #include <sys/socket.h> 12 #include <sys/file.h> 13 #include <sys/wait.h> 14 15 #include <netinet/in.h> 16 17 #include <arpa/ftp.h> 18 #include <arpa/inet.h> 19 20 #include <stdio.h> 21 #include <signal.h> 22 #include <pwd.h> 23 #include <setjmp.h> 24 #include <netdb.h> 25 #include <errno.h> 26 27 /* 28 * File containing login names 29 * NOT to be used on this machine. 30 * Commonly used to disallow uucp. 31 */ 32 #define FTPUSERS "/etc/ftpusers" 33 34 extern int errno; 35 extern char *sys_errlist[]; 36 extern char *crypt(); 37 extern char version[]; 38 extern char *home; /* pointer to home directory for glob */ 39 extern FILE *popen(), *fopen(); 40 extern int pclose(), fclose(); 41 42 struct sockaddr_in ctrl_addr; 43 struct sockaddr_in data_source; 44 struct sockaddr_in data_dest; 45 struct sockaddr_in his_addr; 46 47 struct hostent *hp; 48 49 int data; 50 jmp_buf errcatch; 51 int logged_in; 52 struct passwd *pw; 53 int debug; 54 int timeout; 55 int logging; 56 int guest; 57 int wtmp; 58 int type; 59 int form; 60 int stru; /* avoid C keyword */ 61 int mode; 62 int usedefault = 1; /* for data transfers */ 63 char hostname[32]; 64 char remotehost[32]; 65 struct servent *sp; 66 67 /* 68 * Timeout intervals for retrying connections 69 * to hosts that don't accept PORT cmds. This 70 * is a kludge, but given the problems with TCP... 71 */ 72 #define SWAITMAX 90 /* wait at most 90 seconds */ 73 #define SWAITINT 5 /* interval between retries */ 74 75 int swaitmax = SWAITMAX; 76 int swaitint = SWAITINT; 77 78 int lostconn(); 79 int reapchild(); 80 FILE *getdatasock(), *dataconn(); 81 82 main(argc, argv) 83 int argc; 84 char *argv[]; 85 { 86 int ctrl, s, options = 0; 87 char *cp; 88 89 sp = getservbyname("ftp", "tcp"); 90 if (sp == 0) { 91 fprintf(stderr, "ftpd: ftp/tcp: unknown service\n"); 92 exit(1); 93 } 94 ctrl_addr.sin_port = sp->s_port; 95 data_source.sin_port = htons(ntohs(sp->s_port) - 1); 96 signal(SIGPIPE, lostconn); 97 debug = 0; 98 argc--, argv++; 99 while (argc > 0 && *argv[0] == '-') { 100 for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { 101 102 case 'v': 103 debug = 1; 104 break; 105 106 case 'd': 107 debug = 1; 108 options |= SO_DEBUG; 109 break; 110 111 case 'l': 112 logging = 1; 113 break; 114 115 case 't': 116 timeout = atoi(++cp); 117 goto nextopt; 118 break; 119 120 default: 121 fprintf(stderr, "Unknown flag -%c ignored.\n", *cp); 122 break; 123 } 124 nextopt: 125 argc--, argv++; 126 } 127 #ifndef DEBUG 128 if (fork()) 129 exit(0); 130 for (s = 0; s < 10; s++) 131 if (!logging || (s != 2)) 132 (void) close(s); 133 (void) open("/", O_RDONLY); 134 (void) dup2(0, 1); 135 if (!logging) 136 (void) dup2(0, 2); 137 { int tt = open("/dev/tty", O_RDWR); 138 if (tt > 0) { 139 ioctl(tt, TIOCNOTTY, 0); 140 close(tt); 141 } 142 } 143 #endif 144 while ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 145 perror("ftpd: socket"); 146 sleep(5); 147 } 148 if (options & SO_DEBUG) 149 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 150 perror("ftpd: setsockopt (SO_DEBUG)"); 151 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, 0, 0) < 0) 152 perror("ftpd: setsockopt (SO_KEEPALIVE)"); 153 while (bind(s, &ctrl_addr, sizeof (ctrl_addr), 0) < 0) { 154 perror("ftpd: bind"); 155 sleep(5); 156 } 157 signal(SIGCHLD, reapchild); 158 listen(s, 10); 159 for (;;) { 160 int hisaddrlen = sizeof (his_addr); 161 162 ctrl = accept(s, &his_addr, &hisaddrlen, 0); 163 if (ctrl < 0) { 164 if (errno == EINTR) 165 continue; 166 perror("ftpd: accept"); 167 continue; 168 } 169 if (fork() == 0) { 170 signal (SIGCHLD, SIG_IGN); 171 dolog(&his_addr); 172 close(s); 173 dup2(ctrl, 0), close(ctrl), dup2(0, 1); 174 /* do telnet option negotiation here */ 175 /* 176 * Set up default state 177 */ 178 logged_in = 0; 179 data = -1; 180 type = TYPE_A; 181 form = FORM_N; 182 stru = STRU_F; 183 mode = MODE_S; 184 (void) getsockname(0, &ctrl_addr, sizeof (ctrl_addr)); 185 gethostname(hostname, sizeof (hostname)); 186 reply(220, "%s FTP server (%s) ready.", 187 hostname, version); 188 for (;;) { 189 setjmp(errcatch); 190 yyparse(); 191 } 192 } 193 close(ctrl); 194 } 195 } 196 197 reapchild() 198 { 199 union wait status; 200 201 while (wait3(&status, WNOHANG, 0) > 0) 202 ; 203 } 204 205 lostconn() 206 { 207 208 if (debug) 209 fprintf(stderr, "Lost connection.\n"); 210 dologout(-1); 211 } 212 213 pass(passwd) 214 char *passwd; 215 { 216 char *xpasswd, *savestr(); 217 static struct passwd save; 218 219 if (logged_in || pw == NULL) { 220 reply(503, "Login with USER first."); 221 return; 222 } 223 if (!guest) { /* "ftp" is only account allowed no password */ 224 xpasswd = crypt(passwd, pw->pw_passwd); 225 if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) { 226 reply(530, "Login incorrect."); 227 pw = NULL; 228 return; 229 } 230 } 231 setegid(pw->pw_gid); 232 initgroups(pw->pw_name, pw->pw_gid); 233 if (chdir(pw->pw_dir)) { 234 reply(550, "User %s: can't change directory to $s.", 235 pw->pw_name, pw->pw_dir); 236 goto bad; 237 } 238 239 if (guest) /* grab wtmp before chroot */ 240 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 241 242 if (guest && chroot(pw->pw_dir) < 0) { 243 reply(550, "Can't set guest privileges."); 244 goto bad; 245 } 246 if (!guest) 247 reply(230, "User %s logged in.", pw->pw_name); 248 else 249 reply(230, "Guest login ok, access restrictions apply."); 250 logged_in = 1; 251 dologin(pw); 252 seteuid(pw->pw_uid); 253 /* 254 * Save everything so globbing doesn't 255 * clobber the fields. 256 */ 257 save = *pw; 258 save.pw_name = savestr(pw->pw_name); 259 save.pw_passwd = savestr(pw->pw_passwd); 260 save.pw_comment = savestr(pw->pw_comment); 261 save.pw_gecos = savestr(pw->pw_gecos, &save.pw_gecos); 262 save.pw_dir = savestr(pw->pw_dir); 263 save.pw_shell = savestr(pw->pw_shell); 264 pw = &save; 265 home = pw->pw_dir; /* home dir for globbing */ 266 return; 267 bad: 268 seteuid(0); 269 pw = NULL; 270 } 271 272 char * 273 savestr(s) 274 char *s; 275 { 276 char *malloc(); 277 char *new = malloc(strlen(s) + 1); 278 279 if (new != NULL) 280 strcpy(new, s); 281 return (new); 282 } 283 284 retrieve(cmd, name) 285 char *cmd, *name; 286 { 287 FILE *fin, *dout; 288 struct stat st; 289 int (*closefunc)(); 290 291 if (cmd == 0) { 292 #ifdef notdef 293 /* no remote command execution -- it's a security hole */ 294 if (*name == '|') 295 fin = popen(name + 1, "r"), closefunc = pclose; 296 else 297 #endif 298 fin = fopen(name, "r"), closefunc = fclose; 299 } else { 300 char line[BUFSIZ]; 301 302 sprintf(line, cmd, name), name = line; 303 fin = popen(line, "r"), closefunc = pclose; 304 } 305 if (fin == NULL) { 306 if (errno != 0) 307 reply(550, "%s: %s.", name, sys_errlist[errno]); 308 return; 309 } 310 st.st_size = 0; 311 if (cmd == 0 && 312 (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { 313 reply(550, "%s: not a plain file.", name); 314 goto done; 315 } 316 dout = dataconn(name, st.st_size, "w"); 317 if (dout == NULL) 318 goto done; 319 if (send_data(fin, dout) || ferror(dout)) 320 reply(550, "%s: %s.", name, sys_errlist[errno]); 321 else 322 reply(226, "Transfer complete."); 323 fclose(dout), data = -1; 324 done: 325 (*closefunc)(fin); 326 } 327 328 store(name, mode) 329 char *name, *mode; 330 { 331 FILE *fout, *din; 332 int (*closefunc)(), dochown = 0; 333 334 #ifdef notdef 335 /* no remote command execution -- it's a security hole */ 336 if (name[0] == '|') 337 fout = popen(&name[1], "w"), closefunc = pclose; 338 else 339 #endif 340 { 341 struct stat st; 342 343 if (stat(name, &st) < 0) 344 dochown++; 345 fout = fopen(name, mode), closefunc = fclose; 346 } 347 if (fout == NULL) { 348 reply(550, "%s: %s.", name, sys_errlist[errno]); 349 return; 350 } 351 din = dataconn(name, (off_t)-1, "r"); 352 if (din == NULL) 353 goto done; 354 if (receive_data(din, fout) || ferror(fout)) 355 reply(550, "%s: %s.", name, sys_errlist[errno]); 356 else 357 reply(226, "Transfer complete."); 358 fclose(din), data = -1; 359 done: 360 if (dochown) 361 (void) chown(name, pw->pw_uid, -1); 362 (*closefunc)(fout); 363 } 364 365 FILE * 366 getdatasock(mode) 367 char *mode; 368 { 369 int s; 370 371 if (data >= 0) 372 return (fdopen(data, mode)); 373 s = socket(AF_INET, SOCK_STREAM, 0); 374 if (s < 0) 375 return (NULL); 376 seteuid(0); 377 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) 378 goto bad; 379 /* anchor socket to avoid multi-homing problems */ 380 data_source.sin_family = AF_INET; 381 data_source.sin_addr = ctrl_addr.sin_addr; 382 if (bind(s, &data_source, sizeof (data_source), 0) < 0) 383 goto bad; 384 seteuid(pw->pw_uid); 385 return (fdopen(s, mode)); 386 bad: 387 seteuid(pw->pw_uid); 388 close(s); 389 return (NULL); 390 } 391 392 FILE * 393 dataconn(name, size, mode) 394 char *name; 395 off_t size; 396 char *mode; 397 { 398 char sizebuf[32]; 399 FILE *file; 400 int retry = 0; 401 402 if (size >= 0) 403 sprintf (sizebuf, " (%ld bytes)", size); 404 else 405 (void) strcpy(sizebuf, ""); 406 if (data >= 0) { 407 reply(125, "Using existing data connection for %s%s.", 408 name, sizebuf); 409 usedefault = 1; 410 return (fdopen(data, mode)); 411 } 412 if (usedefault) 413 data_dest = his_addr; 414 usedefault = 1; 415 file = getdatasock(mode); 416 if (file == NULL) { 417 reply(425, "Can't create data socket (%s,%d): %s.", 418 inet_ntoa(data_source.sin_addr), 419 ntohs(data_source.sin_port), 420 sys_errlist[errno]); 421 return (NULL); 422 } 423 reply(150, "Opening data connection for %s (%s,%d)%s.", 424 name, inet_ntoa(data_dest.sin_addr.s_addr), 425 ntohs(data_dest.sin_port), sizebuf); 426 data = fileno(file); 427 while (connect(data, &data_dest, sizeof (data_dest), 0) < 0) { 428 if (errno == EADDRINUSE && retry < swaitmax) { 429 sleep(swaitint); 430 retry += swaitint; 431 continue; 432 } 433 reply(425, "Can't build data connection: %s.", 434 sys_errlist[errno]); 435 (void) fclose(file); 436 data = -1; 437 return (NULL); 438 } 439 return (file); 440 } 441 442 /* 443 * Tranfer the contents of "instr" to 444 * "outstr" peer using the appropriate 445 * encapulation of the date subject 446 * to Mode, Structure, and Type. 447 * 448 * NB: Form isn't handled. 449 */ 450 send_data(instr, outstr) 451 FILE *instr, *outstr; 452 { 453 register int c; 454 int netfd, filefd, cnt; 455 char buf[BUFSIZ]; 456 457 switch (type) { 458 459 case TYPE_A: 460 while ((c = getc(instr)) != EOF) { 461 if (c == '\n') { 462 if (ferror (outstr)) 463 return (1); 464 putc('\r', outstr); 465 } 466 putc(c, outstr); 467 if (c == '\r') 468 putc ('\0', outstr); 469 } 470 if (ferror (instr) || ferror (outstr)) 471 return (1); 472 return (0); 473 474 case TYPE_I: 475 case TYPE_L: 476 netfd = fileno(outstr); 477 filefd = fileno(instr); 478 479 while ((cnt = read(filefd, buf, sizeof (buf))) > 0) 480 if (write(netfd, buf, cnt) < 0) 481 return (1); 482 return (cnt < 0); 483 } 484 reply(504,"Unimplemented TYPE %d in send_data", type); 485 return (1); 486 } 487 488 /* 489 * Transfer data from peer to 490 * "outstr" using the appropriate 491 * encapulation of the data subject 492 * to Mode, Structure, and Type. 493 * 494 * N.B.: Form isn't handled. 495 */ 496 receive_data(instr, outstr) 497 FILE *instr, *outstr; 498 { 499 register int c; 500 int cnt; 501 char buf[BUFSIZ]; 502 503 504 switch (type) { 505 506 case TYPE_I: 507 case TYPE_L: 508 while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) 509 if (write(fileno(outstr), buf, cnt) < 0) 510 return (1); 511 return (cnt < 0); 512 513 case TYPE_E: 514 reply(504, "TYPE E not implemented."); 515 return (1); 516 517 case TYPE_A: 518 while ((c = getc(instr)) != EOF) { 519 if (c == '\r') { 520 if (ferror (outstr)) 521 return (1); 522 if ((c = getc(instr)) != '\n') 523 putc ('\r', outstr); 524 if (c == '\0') 525 continue; 526 } 527 putc (c, outstr); 528 } 529 if (ferror (instr) || ferror (outstr)) 530 return (1); 531 return (0); 532 } 533 fatal("Unknown type in receive_data."); 534 /*NOTREACHED*/ 535 } 536 537 fatal(s) 538 char *s; 539 { 540 reply(451, "Error in server: %s\n", s); 541 reply(221, "Closing connection due to server error."); 542 dologout(0); 543 } 544 545 reply(n, s, args) 546 int n; 547 char *s; 548 { 549 550 printf("%d ", n); 551 _doprnt(s, &args, stdout); 552 printf("\r\n"); 553 fflush(stdout); 554 if (debug) { 555 fprintf(stderr, "<--- %d ", n); 556 _doprnt(s, &args, stderr); 557 fprintf(stderr, "\n"); 558 fflush(stderr); 559 } 560 } 561 562 lreply(n, s, args) 563 int n; 564 char *s; 565 { 566 printf("%d-", n); 567 _doprnt(s, &args, stdout); 568 printf("\r\n"); 569 fflush(stdout); 570 if (debug) { 571 fprintf(stderr, "<--- %d-", n); 572 _doprnt(s, &args, stderr); 573 fprintf(stderr, "\n"); 574 } 575 } 576 577 replystr(s) 578 char *s; 579 { 580 printf("%s\r\n", s); 581 fflush(stdout); 582 if (debug) 583 fprintf(stderr, "<--- %s\n", s); 584 } 585 586 ack(s) 587 char *s; 588 { 589 reply(200, "%s command okay.", s); 590 } 591 592 nack(s) 593 char *s; 594 { 595 reply(502, "%s command not implemented.", s); 596 } 597 598 yyerror() 599 { 600 reply(500, "Command not understood."); 601 } 602 603 delete(name) 604 char *name; 605 { 606 struct stat st; 607 608 if (stat(name, &st) < 0) { 609 reply(550, "%s: %s.", name, sys_errlist[errno]); 610 return; 611 } 612 if ((st.st_mode&S_IFMT) == S_IFDIR) { 613 if (rmdir(name) < 0) { 614 reply(550, "%s: %s.", name, sys_errlist[errno]); 615 return; 616 } 617 goto done; 618 } 619 if (unlink(name) < 0) { 620 reply(550, "%s: %s.", name, sys_errlist[errno]); 621 return; 622 } 623 done: 624 ack("DELE"); 625 } 626 627 cwd(path) 628 char *path; 629 { 630 631 if (chdir(path) < 0) { 632 reply(550, "%s: %s.", path, sys_errlist[errno]); 633 return; 634 } 635 ack("CWD"); 636 } 637 638 makedir(name) 639 char *name; 640 { 641 struct stat st; 642 int dochown = stat(name, &st) < 0; 643 644 if (mkdir(name, 0777) < 0) { 645 reply(550, "%s: %s.", name, sys_errlist[errno]); 646 return; 647 } 648 if (dochown) 649 (void) chown(name, pw->pw_uid, -1); 650 ack("MKDIR"); 651 } 652 653 removedir(name) 654 char *name; 655 { 656 657 if (rmdir(name) < 0) { 658 reply(550, "%s: %s.", name, sys_errlist[errno]); 659 return; 660 } 661 ack("RMDIR"); 662 } 663 664 pwd() 665 { 666 char path[MAXPATHLEN + 1]; 667 668 if (getwd(path) == NULL) { 669 reply(451, "%s.", path); 670 return; 671 } 672 reply(251, "\"%s\" is current directory.", path); 673 } 674 675 char * 676 renamefrom(name) 677 char *name; 678 { 679 struct stat st; 680 681 if (stat(name, &st) < 0) { 682 reply(550, "%s: %s.", name, sys_errlist[errno]); 683 return ((char *)0); 684 } 685 reply(350, "File exists, ready for destination name"); 686 return (name); 687 } 688 689 renamecmd(from, to) 690 char *from, *to; 691 { 692 693 if (rename(from, to) < 0) { 694 reply(550, "rename: %s.", sys_errlist[errno]); 695 return; 696 } 697 ack("RNTO"); 698 } 699 700 dolog(sin) 701 struct sockaddr_in *sin; 702 { 703 struct hostent *hp = gethostbyaddr(&sin->sin_addr, 704 sizeof (struct in_addr), AF_INET); 705 time_t t; 706 707 if (hp) { 708 strncpy(remotehost, hp->h_name, sizeof (remotehost)); 709 endhostent(); 710 } else 711 strncpy(remotehost, inet_ntoa(sin->sin_addr), 712 sizeof (remotehost)); 713 if (!logging) 714 return; 715 t = time(0); 716 fprintf(stderr,"FTPD: connection from %s at %s", remotehost, ctime(&t)); 717 fflush(stderr); 718 } 719 720 #include <utmp.h> 721 722 #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 723 struct utmp utmp; 724 725 /* 726 * Record login in wtmp file. 727 */ 728 dologin(pw) 729 struct passwd *pw; 730 { 731 char line[32]; 732 733 if (guest && (wtmp >= 0)) 734 lseek(wtmp, 0, L_XTND); 735 else 736 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 737 if (wtmp >= 0) { 738 /* hack, but must be unique and no tty line */ 739 sprintf(line, "ftp%d", getpid()); 740 SCPYN(utmp.ut_line, line); 741 SCPYN(utmp.ut_name, pw->pw_name); 742 SCPYN(utmp.ut_host, remotehost); 743 utmp.ut_time = time(0); 744 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 745 if (!guest) 746 (void) close(wtmp); 747 } 748 } 749 750 /* 751 * Record logout in wtmp file 752 * and exit with supplied status. 753 */ 754 dologout(status) 755 int status; 756 { 757 if (!logged_in) 758 _exit(status); 759 seteuid(0); 760 if (guest && (wtmp >= 0)) 761 lseek(wtmp, 0, L_XTND); 762 else 763 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 764 if (wtmp >= 0) { 765 SCPYN(utmp.ut_name, ""); 766 SCPYN(utmp.ut_host, ""); 767 utmp.ut_time = time(0); 768 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 769 (void) close(wtmp); 770 } 771 /* beware of flushing buffers after a SIGPIPE */ 772 _exit(status); 773 } 774 775 /* 776 * Special version of popen which avoids 777 * call to shell. This insures noone may 778 * create a pipe to a hidden program as a side 779 * effect of a list or dir command. 780 */ 781 #define tst(a,b) (*mode == 'r'? (b) : (a)) 782 #define RDR 0 783 #define WTR 1 784 static int popen_pid[5]; 785 786 static char * 787 nextarg(cpp) 788 char *cpp; 789 { 790 register char *cp = cpp; 791 792 if (cp == 0) 793 return (cp); 794 while (*cp && *cp != ' ' && *cp != '\t') 795 cp++; 796 if (*cp == ' ' || *cp == '\t') { 797 *cp++ = '\0'; 798 while (*cp == ' ' || *cp == '\t') 799 cp++; 800 } 801 if (cp == cpp) 802 return ((char *)0); 803 return (cp); 804 } 805 806 FILE * 807 popen(cmd, mode) 808 char *cmd, *mode; 809 { 810 int p[2], ac, gac; 811 register myside, hisside, pid; 812 char *av[20], *gav[512]; 813 register char *cp; 814 815 if (pipe(p) < 0) 816 return (NULL); 817 cp = cmd, ac = 0; 818 /* break up string into pieces */ 819 do { 820 av[ac++] = cp; 821 cp = nextarg(cp); 822 } while (cp && *cp && ac < 20); 823 av[ac] = (char *)0; 824 gav[0] = av[0]; 825 /* glob each piece */ 826 for (gac = ac = 1; av[ac] != NULL; ac++) { 827 char **pop; 828 extern char **glob(); 829 830 pop = glob(av[ac]); 831 if (pop) { 832 av[ac] = (char *)pop; /* save to free later */ 833 while (*pop && gac < 512) 834 gav[gac++] = *pop++; 835 } 836 } 837 gav[gac] = (char *)0; 838 myside = tst(p[WTR], p[RDR]); 839 hisside = tst(p[RDR], p[WTR]); 840 if ((pid = fork()) == 0) { 841 /* myside and hisside reverse roles in child */ 842 close(myside); 843 dup2(hisside, tst(0, 1)); 844 close(hisside); 845 execv(gav[0], gav); 846 _exit(1); 847 } 848 for (ac = 1; av[ac] != NULL; ac++) 849 blkfree((char **)av[ac]); 850 if (pid == -1) 851 return (NULL); 852 popen_pid[myside] = pid; 853 close(hisside); 854 return (fdopen(myside, mode)); 855 } 856 857 pclose(ptr) 858 FILE *ptr; 859 { 860 register f, r, (*hstat)(), (*istat)(), (*qstat)(); 861 int status; 862 863 f = fileno(ptr); 864 fclose(ptr); 865 istat = signal(SIGINT, SIG_IGN); 866 qstat = signal(SIGQUIT, SIG_IGN); 867 hstat = signal(SIGHUP, SIG_IGN); 868 while ((r = wait(&status)) != popen_pid[f] && r != -1) 869 ; 870 if (r == -1) 871 status = -1; 872 signal(SIGINT, istat); 873 signal(SIGQUIT, qstat); 874 signal(SIGHUP, hstat); 875 return (status); 876 } 877 878 /* 879 * Check user requesting login priviledges. 880 * Disallow anyone mentioned in the file FTPUSERS 881 * to allow people such as uucp to be avoided. 882 */ 883 checkuser(name) 884 register char *name; 885 { 886 char line[BUFSIZ], *index(); 887 FILE *fd; 888 int found = 0; 889 890 fd = fopen(FTPUSERS, "r"); 891 if (fd == NULL) 892 return (1); 893 while (fgets(line, sizeof (line), fd) != NULL) { 894 register char *cp = index(line, '\n'); 895 896 if (cp) 897 *cp = '\0'; 898 if (strcmp(line, name) == 0) { 899 found++; 900 break; 901 } 902 } 903 fclose(fd); 904 return (!found); 905 } 906