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