1 /* 2 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /**************************************************************************** 6 7 Copyright (c) 1999,2000,2001 WU-FTPD Development Group. 8 All rights reserved. 9 10 Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994 11 The Regents of the University of California. 12 Portions Copyright (c) 1993, 1994 Washington University in Saint Louis. 13 Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc. 14 Portions Copyright (c) 1989 Massachusetts Institute of Technology. 15 Portions Copyright (c) 1998 Sendmail, Inc. 16 Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman. 17 Portions Copyright (c) 1997 by Stan Barber. 18 Portions Copyright (c) 1997 by Kent Landfield. 19 Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 20 Free Software Foundation, Inc. 21 22 Use and distribution of this software and its source code are governed 23 by the terms and conditions of the WU-FTPD Software License ("LICENSE"). 24 25 If you did not receive a copy of the license, it may be obtained online 26 at http://www.wu-ftpd.org/license.html. 27 28 $Id: ftpd.c,v 1.111 2000/07/01 18:17:39 wuftpd Exp $ 29 30 ****************************************************************************/ 31 /* FTP server. */ 32 #include "config.h" 33 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/stat.h> 37 #include <sys/ioctl.h> 38 #include <sys/socket.h> 39 #include <sys/file.h> 40 #include <sys/wait.h> 41 42 #ifdef AIX 43 #include <sys/id.h> 44 #include <sys/priv.h> 45 #include <netinet/if_ether.h> 46 #include <net/if_dl.h> 47 #endif 48 49 #ifdef AUX 50 #include <compat.h> 51 #endif 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 57 #define FTP_NAMES 58 #include <arpa/ftp.h> 59 #include <arpa/inet.h> 60 61 #include <ctype.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <signal.h> 65 #include <pwd.h> 66 #include <grp.h> 67 #include <setjmp.h> 68 #include <errno.h> 69 #include <string.h> 70 #ifdef INTERNAL_LS 71 #ifdef HAVE_GLOB_H 72 #include <glob.h> 73 #else 74 #include <wuftpd_glob.h> 75 #endif 76 #endif 77 #ifdef HAVE_GRP_H 78 #include <grp.h> 79 #endif 80 #include <sys/stat.h> 81 82 #define VA_LOCAL_DECL va_list ap; 83 #define VA_START(f) va_start(ap, f) 84 #define VA_END va_end(ap) 85 86 #include "proto.h" 87 88 #ifdef HAVE_UFS_QUOTA_H 89 #include <ufs/quota.h> 90 #endif 91 #ifdef HAVE_SYS_FS_UFS_QUOTA_H 92 #include <sys/fs/ufs_quota.h> 93 #endif 94 95 #ifdef HAVE_SYS_SYSLOG_H 96 #include <sys/syslog.h> 97 #endif 98 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H)) 99 #include <syslog.h> 100 #endif 101 #ifdef TIME_WITH_SYS_TIME 102 #include <time.h> 103 #include <sys/time.h> 104 #else 105 #ifdef HAVE_SYS_TIME_H 106 #include <sys/time.h> 107 #else 108 #include <time.h> 109 #endif 110 #endif 111 112 #ifdef HAVE_SYS_SENDFILE_H 113 #include <sys/sendfile.h> 114 #endif 115 116 #include "conversions.h" 117 #include "extensions.h" 118 119 #ifdef SHADOW_PASSWORD 120 #include <shadow.h> 121 #endif 122 123 #include "pathnames.h" 124 125 #ifdef M_UNIX 126 #include <arpa/nameser.h> 127 #include <resolv.h> 128 #endif 129 130 #if defined(HAVE_FCNTL_H) 131 #include <fcntl.h> 132 #endif 133 134 #ifdef HAVE_SYSINFO 135 #include <sys/systeminfo.h> 136 #endif 137 138 #ifdef KERBEROS 139 #include <sys/types.h> 140 #include <auth.h> 141 #include <krb.h> 142 #endif 143 144 #ifdef ULTRIX_AUTH 145 #include <auth.h> 146 #include <sys/svcinfo.h> 147 #endif 148 149 #ifndef HAVE_LSTAT 150 #define lstat stat 151 #endif 152 153 #ifdef AFS_AUTH 154 #include <afs/stds.h> 155 #include <afs/kautils.h> 156 #endif 157 158 #ifdef DCE_AUTH 159 #include <dce/rpc.h> 160 #include <dce/sec_login.h> 161 #include <dce/dce_error.h> 162 #endif 163 164 165 #ifdef HAVE_DIRENT_H 166 #include <dirent.h> 167 #else 168 #include <sys/dir.h> 169 #endif 170 171 #if defined(USE_LONGJMP) 172 #define wu_longjmp(x, y) longjmp((x), (y)) 173 #define wu_setjmp(x) setjmp(x) 174 #ifndef JMP_BUF 175 #define JMP_BUF jmp_buf 176 #endif 177 #else 178 #define wu_longjmp(x, y) siglongjmp((x), (y)) 179 #define wu_setjmp(x) sigsetjmp((x), 1) 180 #ifndef JMP_BUF 181 #define JMP_BUF sigjmp_buf 182 #endif 183 #endif 184 185 #ifndef MAXHOSTNAMELEN 186 #define MAXHOSTNAMELEN 64 /* may be too big */ 187 #endif 188 189 #ifndef TRUE 190 #define TRUE 1 191 #endif 192 193 #ifndef FALSE 194 #define FALSE !TRUE 195 #endif 196 197 #ifdef MAIL_ADMIN 198 #define MAILSERVERS 10 199 #define INCMAILS 10 200 int mailservers = 0; 201 char *mailserver[MAILSERVERS]; 202 int incmails = 0; 203 char *incmail[INCMAILS]; 204 char *mailfrom; 205 char *email(char *full_address); 206 FILE *SockOpen(char *host, int clientPort); 207 char *SockGets(FILE *sockfp, char *buf, int len); 208 int SockWrite(char *buf, int size, int nels, FILE *sockfp); 209 int SockPrintf(FILE *sockfp, char *format,...); 210 int SockPuts(FILE *sockfp, char *buf); 211 int Reply(FILE *sockfp); 212 int Send(FILE *sockfp, char *format,...); 213 #endif /* MAIL_ADMIN */ 214 215 #if defined(_SCO_DS) && !defined(SIGURG) 216 #define SIGURG SIGUSR1 217 #endif 218 219 /* File containing login names NOT to be used on this machine. Commonly used 220 * to disallow uucp. */ 221 extern int errno; 222 223 extern char *ctime(const time_t *); 224 #ifndef NO_CRYPT_PROTO 225 extern char *crypt(const char *, const char *); 226 #endif 227 228 extern char version[]; 229 extern char *home; /* pointer to home directory for glob */ 230 extern char cbuf[]; 231 extern off_t restart_point; 232 extern int yyerrorcalled; 233 234 struct SOCKSTORAGE ctrl_addr; 235 struct SOCKSTORAGE data_source; 236 struct SOCKSTORAGE data_dest; 237 struct SOCKSTORAGE his_addr; 238 struct SOCKSTORAGE pasv_addr; 239 struct SOCKSTORAGE vect_addr; 240 int route_vectored = 0; 241 int passive_port_min = 1024; 242 int passive_port_max = 65535; 243 int restricted_user = 0; 244 unsigned short data_port = 0; 245 246 #ifdef INET6 247 int ctrl_v4mapped = 0; 248 int epsv_all = 0; 249 int listen_v4 = 0; /* when set, listen on IPv4 socket in standalone mode */ 250 #endif 251 252 #ifdef VIRTUAL 253 char virtual_root[MAXPATHLEN]; 254 char virtual_banner[MAXPATHLEN]; 255 char virtual_email[MAXPATHLEN]; 256 257 char virtual_hostname[MAXHOSTNAMELEN]; 258 char virtual_address[MAXHOSTNAMELEN]; 259 260 extern int virtual_mode; 261 extern int virtual_ftpaccess; 262 #endif 263 264 #ifdef QUOTA 265 extern struct dqblk quota; 266 #endif 267 268 #if defined(USE_GSS) 269 #include "gssutil.h" 270 271 extern gss_info_t gss_info; 272 273 int allow_ccc = 0; 274 int ccc_ok = 0; 275 extern char *cur_auth_type; 276 #endif /* USE_GSS */ 277 278 int data; 279 jmp_buf errcatch; 280 JMP_BUF urgcatch; 281 int logged_in = 0; 282 struct passwd *pw; 283 char chroot_path[MAXPATHLEN]; 284 int debug = 0; 285 int disable_rfc931 = 0; 286 extern unsigned int timeout_idle; 287 extern unsigned int timeout_maxidle; 288 extern unsigned int timeout_data; 289 extern unsigned int timeout_accept; 290 extern unsigned int timeout_connect; 291 292 /* previously defaulted to 1, and -l or -L set them to 1, so that there was 293 no way to turn them *off*! Changed so that the manpage reflects common 294 sense. -L is way noisy; -l we'll change to be "just right". _H */ 295 int logging = 0; 296 int log_commands = 0; 297 int log_security = 0; 298 int syslogmsg = 0; 299 static int wtmp_logging = 1; 300 301 #ifdef SECUREOSF 302 #define SecureWare /* Does this mean it works for all SecureWare? */ 303 #endif 304 305 #ifdef HPUX_10_TRUSTED 306 #include <hpsecurity.h> 307 #endif 308 309 #if defined(SecureWare) || defined(HPUX_10_TRUSTED) 310 #include <prot.h> 311 #endif 312 313 int anonymous = 1; 314 int guest; 315 int type; 316 int form; 317 int stru; /* avoid C keyword */ 318 int mode; 319 int usedefault = 1; /* for data transfers */ 320 int pdata = -1; /* for passive mode */ 321 int transflag; 322 int ftwflag; 323 off_t file_size; 324 off_t byte_count; 325 int TCPwindowsize = 0; /* 0 = use system default */ 326 size_t sendbufsz; /* buffer size to use when sending data */ 327 size_t recvbufsz; /* buffer size to use when receiving data */ 328 329 #ifdef TRANSFER_COUNT 330 off_t data_count_total = 0; /* total number of data bytes */ 331 off_t data_count_in = 0; 332 off_t data_count_out = 0; 333 off_t byte_count_total = 0; /* total number of general traffic */ 334 off_t byte_count_in = 0; 335 off_t byte_count_out = 0; 336 int file_count_total = 0; /* total number of data files */ 337 int file_count_in = 0; 338 int file_count_out = 0; 339 int xfer_count_total = 0; /* total number of transfers */ 340 int xfer_count_in = 0; 341 int xfer_count_out = 0; 342 #ifdef TRANSFER_LIMIT 343 int file_limit_raw_in = 0; 344 int file_limit_raw_out = 0; 345 int file_limit_raw_total = 0; 346 int file_limit_data_in = 0; 347 int file_limit_data_out = 0; 348 int file_limit_data_total = 0; 349 off_t data_limit_raw_in = 0; 350 off_t data_limit_raw_out = 0; 351 off_t data_limit_raw_total = 0; 352 off_t data_limit_data_in = 0; 353 off_t data_limit_data_out = 0; 354 off_t data_limit_data_total = 0; 355 #ifdef RATIO /* 1998/08/04 K.Wakui */ 356 #define TRUNC_KB(n) ((n)/1024+(((n)%1024)?1:0)) 357 off_t total_free_dl = 0; 358 int upload_download_rate = 0; 359 int freefile; 360 int is_downloadfree( char * ); 361 #endif /* RATIO */ 362 #endif 363 #endif 364 365 int retrieve_is_data = 1; /* !0=data, 0=general traffic -- for 'ls' */ 366 char LastFileTransferred[MAXPATHLEN] = ""; 367 368 static char *RootDirectory = NULL; 369 370 #if !defined(CMASK) || CMASK == 0 371 #undef CMASK 372 #define CMASK 022 373 #endif 374 mode_t defumask = CMASK; /* default umask value */ 375 #ifdef ALTERNATE_CD 376 char defhome[] = "/"; 377 #endif 378 char tmpline[7]; 379 char hostname[MAXHOSTNAMELEN]; 380 char remotehost[MAXHOSTNAMELEN]; 381 char remoteaddr[MAXHOSTNAMELEN]; 382 char *remoteident = "[nowhere yet]"; 383 int rhlookup = TRUE; /* when TRUE lookup the remote hosts name */ 384 385 #if defined(SOLARIS_2) && !defined(NAME_SERVICE_DOOR) 386 #define NAME_SERVICE_DOOR "/var/run/name_service_door" 387 #endif 388 389 #if defined(SOLARIS_2) 390 int close_nsdoor(void *cb_data, int fd); 391 void cleanup_nscd(); 392 #endif 393 394 /* log failures 27-apr-93 ehk/bm */ 395 #define MAXUSERNAMELEN 256 396 char the_user[MAXUSERNAMELEN]; 397 398 /* Access control and logging passwords */ 399 /* OFF by default. _H */ 400 int use_accessfile = 0; 401 char guestpw[MAXHOSTNAMELEN]; 402 char privatepw[MAXHOSTNAMELEN]; 403 int nameserved = 0; 404 extern char authuser[]; 405 extern int authenticated; 406 extern int keepalive; 407 408 /* File transfer logging (xferlog) */ 409 int xferlog = 0; 410 int log_outbound_xfers = 0; 411 int log_incoming_xfers = 0; 412 char logfile[MAXPATHLEN]; 413 414 /* Allow use of lreply(); this is here since some older FTP clients don't 415 * support continuation messages. In violation of the RFCs... */ 416 int dolreplies = 1; 417 418 /* Spontaneous reply text. To be sent along with next reply to user */ 419 char *autospout = NULL; 420 int autospout_free = 0; 421 422 /* allowed on-the-fly file manipulations (compress, tar) */ 423 int mangleopts = 0; 424 425 /* number of login failures before attempts are logged and FTP *EXITS* */ 426 int lgi_failure_threshold = 5; 427 428 /* Timeout intervals for retrying connections to hosts that don't accept PORT 429 * cmds. This is a kludge, but given the problems with TCP... */ 430 #define SWAITMAX 90 /* wait at most 90 seconds */ 431 #define SWAITINT 5 /* interval between retries */ 432 433 int swaitmax = SWAITMAX; 434 int swaitint = SWAITINT; 435 436 SIGNAL_TYPE lostconn(int sig); 437 SIGNAL_TYPE randomsig(int sig); 438 SIGNAL_TYPE myoob(int sig); 439 FILE *getdatasock(char *mode); 440 FILE *dataconn(char *name, off_t size, char *mode); 441 void setproctitle(const char *fmt,...); 442 void initsetproctitle(int, char **, char **); 443 void reply(int, char *fmt,...); 444 void lreply(int, char *fmt,...); 445 446 #ifndef HAVE_VSNPRINTF 447 extern int vsnprintf(char *, size_t, const char *, va_list); 448 #endif 449 450 #ifndef HAVE_SNPRINTF 451 extern int snprintf(char *, size_t, const char *,...); 452 #endif 453 454 #ifdef NEED_SIGFIX 455 extern sigset_t block_sigmask; /* defined in sigfix.c */ 456 #endif 457 458 char proctitle[BUFSIZ]; /* initial part of title */ 459 460 #if defined(SKEY) && defined(OPIE) 461 #error YOU SHOULD NOT HAVE BOTH SKEY AND OPIE DEFINED!!!!! 462 #endif 463 464 #ifdef SKEY 465 #include <skey.h> 466 int pwok = 0; 467 #endif 468 469 #ifdef OPIE 470 #include <opie.h> 471 int pwok = 0; 472 int af_pwok = 0; 473 struct opie opiestate; 474 #endif 475 476 #ifdef KERBEROS 477 void init_krb(); 478 void end_krb(); 479 char krb_ticket_name[100]; 480 #endif /* KERBEROS */ 481 482 #ifdef ULTRIX_AUTH 483 int ultrix_check_pass(char *passwd, char *xpasswd); 484 #endif 485 486 #ifdef USE_PAM 487 #if defined(ULTRIX_AUTH) || defined(SECUREOSF) || defined(KERBEROS) || defined(SKEY) || defined (OPIE) || defined (BSD_AUTH) 488 #error No other auth methods are allowed with PAM. 489 #endif 490 #include <security/pam_appl.h> 491 static int pam_check_pass(char *user, char *passwd); 492 pam_handle_t *pamh; 493 #endif 494 495 #ifndef INTERNAL_LS 496 /* ls program commands and options for lreplies on and off */ 497 char ls_long[BUFSIZ * 2]; 498 char ls_short[BUFSIZ * 2]; 499 char ls_plain[BUFSIZ * 2]; 500 #endif 501 502 #define FTPD_OPTS ":4aAdiIlLoP:qQr:t:T:u:vVwWxX" 503 #if defined(DAEMON) 504 # define DAEMON_OPTS "p:sS" 505 #else /* !(defined(DAEMON)) */ 506 # define DAEMON_OPTS 507 #endif /* !(defined(DAEMON)) */ 508 #if defined(USE_GSS) 509 # define GSS_OPTS "CK" 510 #else /* !(defined(USE_GSS)) */ 511 # define GSS_OPTS 512 #endif /* !(defined(USE_GSS)) */ 513 514 /* Some systems use one format, some another. This takes care of the garbage */ 515 #ifndef L_FORMAT /* Autoconf detects this... */ 516 #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T) 517 #define L_FORMAT "qd" 518 #else 519 #ifdef _AIX42 520 #define L_FORMAT "lld" 521 #else 522 #ifdef SOLARIS_2 523 #define L_FORMAT "ld" 524 #else 525 #define L_FORMAT "d" 526 #endif 527 #endif 528 #endif 529 #endif 530 531 #ifdef DAEMON 532 int be_daemon = 0; /* Run standalone? */ 533 int daemon_port = 0; 534 static void do_daemon(void); 535 #endif 536 int Bypass_PID_Files = 0; 537 538 #ifdef OTHER_PASSWD 539 #include "getpwnam.h" 540 char _path_passwd[MAXPATHLEN]; 541 #ifdef SHADOW_PASSWORD 542 char _path_shadow[MAXPATHLEN]; 543 #endif 544 #endif 545 #if defined(USE_PAM) && defined(OTHER_PASSWD) 546 int use_pam = 1; 547 #else 548 int use_pam = 0; 549 #endif 550 551 void print_copyright(void); 552 char *mapping_getcwd(char *path, size_t size); 553 554 void dolog(struct SOCKSTORAGE *); 555 556 #ifdef THROUGHPUT 557 extern void throughput_calc(char *, int *, double *); 558 extern void throughput_adjust(char *); 559 #endif 560 561 time_t login_time; 562 time_t limit_time = 0; 563 564 int regexmatch(char *name, char *rgexp); 565 566 int pasv_allowed(char *remoteaddr); 567 int port_allowed(char *remoteaddr); 568 569 #if sparc && !__svr4__ 570 int fclose(FILE *); 571 #endif 572 573 static SIGNAL_TYPE alarm_signal(int sig) 574 { 575 } 576 577 static FILE *draconian_FILE = NULL; 578 579 static SIGNAL_TYPE draconian_alarm_signal(int sig) 580 { 581 if (draconian_FILE != NULL) { 582 fclose(draconian_FILE); 583 draconian_FILE = NULL; 584 } 585 (void) signal(SIGALRM, draconian_alarm_signal); 586 } 587 588 static void socket_flush_wait(FILE *file) 589 { 590 static int flushwait = TRUE; 591 static int first_time = TRUE; 592 char c; 593 int set; 594 int fd = fileno(file); 595 int serrno = errno; 596 struct aclmember *entry; 597 598 if (first_time) { 599 entry = NULL; 600 /* flush-wait yes|no [typelist] */ 601 while (getaclentry("flush-wait", &entry)) { 602 if (!ARG0) 603 continue; 604 if (strcasecmp(ARG0, "yes") == 0) 605 set = TRUE; 606 else if (strcasecmp(ARG0, "no") == 0) 607 set = FALSE; 608 else 609 continue; 610 611 if (!ARG1) 612 flushwait = set; 613 else if (type_match(ARG1)) { 614 flushwait = set; 615 break; 616 } 617 } 618 first_time = FALSE; 619 } 620 if (flushwait) { 621 if (draconian_FILE != NULL) 622 shutdown(fd, 1); 623 if (draconian_FILE != NULL) 624 read(fd, &c, 1); 625 } 626 errno = serrno; 627 /* 628 * GAL - the read() here should be checked to ensure it returned 0 (indicating 629 * EOF) or -1 (an error occurred). Anything else (real data) is a protocol 630 * error. 631 */ 632 } 633 634 static int IPClassOfService(const char *type) 635 { 636 int ipcos = -1, value; 637 char *endp; 638 struct aclmember *entry = NULL; 639 640 /* ipcos control|data <value> [<typelist>] */ 641 while (getaclentry("ipcos", &entry)) { 642 if (ARG0 && ARG1) { 643 if (strcasecmp(type, ARG0) == 0) { 644 if (!ARG2) { 645 errno = 0; 646 value = (int) strtol(ARG1, &endp, 0); 647 if ((errno == 0) && (value >= 0) && (*endp == '\0')) 648 ipcos = value; 649 } 650 else if (type_match(ARG2)) { 651 errno = 0; 652 value = (int) strtol(ARG1, &endp, 0); 653 if ((errno == 0) && (value >= 0) && (*endp == '\0')) { 654 ipcos = value; 655 break; 656 } 657 } 658 } 659 } 660 } 661 return ipcos; 662 } 663 664 int main(int argc, char **argv, char **envp) 665 { 666 #if defined(UNIXWARE) || defined(AIX) 667 size_t addrlen; 668 #else 669 int addrlen; 670 #endif 671 int on = 1; 672 int cos; 673 int c; 674 #ifndef INTERNAL_LS 675 int which; 676 #endif 677 extern int optopt; 678 extern char *optarg; 679 char *hp; 680 struct aclmember *entry; 681 #ifdef VIRTUAL 682 #if defined(UNIXWARE) || defined(AIX) 683 size_t virtual_len; 684 #else 685 int virtual_len; 686 #endif 687 struct SOCKSTORAGE virtual_addr; 688 #endif 689 struct servent *serv; 690 691 #ifdef AUX 692 setcompat(COMPAT_POSIX | COMPAT_BSDSETUGID); 693 #endif 694 695 closelog(); 696 #ifdef FACILITY 697 openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY); 698 #else 699 openlog("ftpd", LOG_PID); 700 #endif 701 702 #ifdef SecureWare 703 setluid(1); /* make sure there is a valid luid */ 704 set_auth_parameters(argc, argv); 705 setreuid(0, 0); 706 #endif 707 #if defined(M_UNIX) && !defined(_M_UNIX) 708 res_init(); /* bug in old (1.1.1) resolver */ 709 _res.retrans = 20; /* because of fake syslog in 3.2.2 */ 710 setlogmask(LOG_UPTO(LOG_INFO)); 711 #endif 712 713 while ((c = getopt(argc, argv, FTPD_OPTS DAEMON_OPTS GSS_OPTS)) != -1) { 714 switch (c) { 715 716 case '4': 717 #ifdef INET6 718 listen_v4 = 1; 719 #endif 720 break; 721 722 case 'a': 723 use_accessfile = 1; 724 break; 725 726 case 'A': 727 use_accessfile = 0; 728 break; 729 730 case 'v': 731 debug = 1; 732 break; 733 734 case 'd': 735 debug = 1; 736 break; 737 738 #if defined(USE_GSS) 739 case 'C': 740 gss_info.want_creds = 1; 741 break; 742 743 case 'K': 744 gss_info.must_gss_auth = 1; 745 break; 746 #endif /* USE_GSS */ 747 748 case 'l': 749 logging = 1; 750 break; 751 752 case 'L': 753 log_commands = 3; 754 break; 755 756 case 'i': 757 log_incoming_xfers = 3; 758 break; 759 760 case 'I': 761 disable_rfc931 = 1; 762 break; 763 764 case 'o': 765 log_outbound_xfers = 3; 766 break; 767 768 case 'q': 769 Bypass_PID_Files = 0; 770 break; 771 772 case 'Q': 773 Bypass_PID_Files = 1; 774 break; 775 776 case 'r': 777 if ((optarg != NULL) && (optarg[0] != '\0')) { 778 RootDirectory = malloc(strlen(optarg) + 1); 779 if (RootDirectory != NULL) 780 strcpy(RootDirectory, optarg); 781 } 782 break; 783 784 case 'P': 785 data_port = htons(atoi(optarg)); 786 break; 787 788 #ifdef DAEMON 789 case 'p': 790 daemon_port = atoi(optarg); 791 break; 792 793 case 's': 794 be_daemon = 1; 795 break; 796 797 case 'S': 798 be_daemon = 2; 799 break; 800 #endif /* DAEMON */ 801 802 case 't': 803 timeout_idle = atoi(optarg); 804 if (timeout_maxidle < timeout_idle) 805 timeout_maxidle = timeout_idle; 806 break; 807 808 case 'T': 809 timeout_maxidle = atoi(optarg); 810 if (timeout_idle > timeout_maxidle) 811 timeout_idle = timeout_maxidle; 812 break; 813 814 case 'u': 815 { 816 unsigned int val = 0; 817 818 while (*optarg && *optarg >= '0' && *optarg <= '7') 819 val = val * 8 + *optarg++ - '0'; 820 if (*optarg || val > 0777) 821 syslog(LOG_ERR, "bad value for -u"); 822 else 823 defumask = val; 824 break; 825 } 826 827 case 'V': 828 print_copyright(); 829 exit(0); 830 /* NOTREACHED */ 831 case 'w': 832 wtmp_logging = 1; 833 break; 834 835 case 'W': 836 wtmp_logging = 0; 837 break; 838 839 case 'x': 840 syslogmsg = 2; 841 break; 842 843 case 'X': 844 syslogmsg = 1; 845 break; 846 847 case ':': 848 syslog(LOG_ERR, "option -%c requires an argument", optopt); 849 break; 850 851 default: 852 syslog(LOG_ERR, "unknown option -%c ignored", optopt); 853 break; 854 } 855 } 856 initsetproctitle(argc, argv, envp); 857 (void) freopen(_PATH_DEVNULL, "w", stderr); 858 859 /* Checking for random signals ... */ 860 #ifdef NEED_SIGFIX 861 sigemptyset(&block_sigmask); 862 #endif 863 #ifndef SIG_DEBUG 864 #ifdef SIGHUP 865 (void) signal(SIGHUP, randomsig); 866 #ifdef NEED_SIGFIX 867 sigaddset(&block_sigmask, SIGHUP); 868 #endif 869 #endif 870 #ifdef SIGINT 871 (void) signal(SIGINT, randomsig); 872 #ifdef NEED_SIGFIX 873 sigaddset(&block_sigmask, SIGINT); 874 #endif 875 #endif 876 #ifdef SIGQUIT 877 (void) signal(SIGQUIT, randomsig); 878 #ifdef NEED_SIGFIX 879 sigaddset(&block_sigmask, SIGQUIT); 880 #endif 881 #endif 882 #ifdef SIGILL 883 (void) signal(SIGILL, randomsig); 884 #ifdef NEED_SIGFIX 885 sigaddset(&block_sigmask, SIGILL); 886 #endif 887 #endif 888 #ifdef SIGTRAP 889 (void) signal(SIGTRAP, randomsig); 890 #ifdef NEED_SIGFIX 891 sigaddset(&block_sigmask, SIGTRAP); 892 #endif 893 #endif 894 #ifdef SIGIOT 895 (void) signal(SIGIOT, randomsig); 896 #ifdef NEED_SIGFIX 897 sigaddset(&block_sigmask, SIGIOT); 898 #endif 899 #endif 900 #ifdef SIGEMT 901 (void) signal(SIGEMT, randomsig); 902 #ifdef NEED_SIGFIX 903 sigaddset(&block_sigmask, SIGEMT); 904 #endif 905 #endif 906 #ifdef SIGFPE 907 (void) signal(SIGFPE, randomsig); 908 #ifdef NEED_SIGFIX 909 sigaddset(&block_sigmask, SIGFPE); 910 #endif 911 #endif 912 #ifdef SIGKILL 913 (void) signal(SIGKILL, randomsig); 914 #ifdef NEED_SIGFIX 915 sigaddset(&block_sigmask, SIGKILL); 916 #endif 917 #endif 918 #ifdef SIGBUS 919 (void) signal(SIGBUS, randomsig); 920 #ifdef NEED_SIGFIX 921 sigaddset(&block_sigmask, SIGBUS); 922 #endif 923 #endif 924 #ifdef SIGSEGV 925 (void) signal(SIGSEGV, randomsig); 926 #ifdef NEED_SIGFIX 927 sigaddset(&block_sigmask, SIGSEGV); 928 #endif 929 #endif 930 #ifdef SIGSYS 931 (void) signal(SIGSYS, randomsig); 932 #ifdef NEED_SIGFIX 933 sigaddset(&block_sigmask, SIGSYS); 934 #endif 935 #endif 936 #ifdef SIGALRM 937 (void) signal(SIGALRM, randomsig); 938 #ifdef NEED_SIGFIX 939 sigaddset(&block_sigmask, SIGALRM); 940 #endif 941 #endif 942 #ifdef SIGSTOP 943 (void) signal(SIGSTOP, randomsig); 944 #ifdef NEED_SIGFIX 945 sigaddset(&block_sigmask, SIGSTOP); 946 #endif 947 #endif 948 #ifdef SIGTSTP 949 (void) signal(SIGTSTP, randomsig); 950 #ifdef NEED_SIGFIX 951 sigaddset(&block_sigmask, SIGTSTP); 952 #endif 953 #endif 954 #ifdef SIGTTIN 955 (void) signal(SIGTTIN, randomsig); 956 #ifdef NEED_SIGFIX 957 sigaddset(&block_sigmask, SIGTTIN); 958 #endif 959 #endif 960 #ifdef SIGTTOU 961 (void) signal(SIGTTOU, randomsig); 962 #ifdef NEED_SIGFIX 963 sigaddset(&block_sigmask, SIGTTOU); 964 #endif 965 #endif 966 #ifdef SIGIO 967 (void) signal(SIGIO, randomsig); 968 #ifdef NEED_SIGFIX 969 sigaddset(&block_sigmask, SIGIO); 970 #endif 971 #endif 972 #ifdef SIGXCPU 973 (void) signal(SIGXCPU, randomsig); 974 #ifdef NEED_SIGFIX 975 sigaddset(&block_sigmask, SIGXCPU); 976 #endif 977 #endif 978 #ifdef SIGXFSZ 979 (void) signal(SIGXFSZ, randomsig); 980 #ifdef NEED_SIGFIX 981 sigaddset(&block_sigmask, SIGXFSZ); 982 #endif 983 #endif 984 #ifdef SIGWINCH 985 (void) signal(SIGWINCH, randomsig); 986 #ifdef NEED_SIGFIX 987 sigaddset(&block_sigmask, SIGWINCH); 988 #endif 989 #endif 990 #ifdef SIGVTALRM 991 (void) signal(SIGVTALRM, randomsig); 992 #ifdef NEED_SIGFIX 993 sigaddset(&block_sigmask, SIGVTALRM); 994 #endif 995 #endif 996 #ifdef SIGPROF 997 (void) signal(SIGPROF, randomsig); 998 #ifdef NEED_SIGFIX 999 sigaddset(&block_sigmask, SIGPROF); 1000 #endif 1001 #endif 1002 #ifdef SIGUSR1 1003 (void) signal(SIGUSR1, randomsig); 1004 #ifdef NEED_SIGFIX 1005 sigaddset(&block_sigmask, SIGUSR1); 1006 #endif 1007 #endif 1008 #ifdef SIGUSR2 1009 (void) signal(SIGUSR2, randomsig); 1010 #ifdef NEED_SIGFIX 1011 sigaddset(&block_sigmask, SIGUSR2); 1012 #endif 1013 #endif 1014 1015 #ifdef SIGPIPE 1016 (void) signal(SIGPIPE, lostconn); 1017 #ifdef NEED_SIGFIX 1018 sigaddset(&block_sigmask, SIGPIPE); 1019 #endif 1020 #endif 1021 #ifdef SIGCHLD 1022 (void) signal(SIGCHLD, SIG_IGN); 1023 #ifdef NEED_SIGFIX 1024 sigaddset(&block_sigmask, SIGCHLD); 1025 #endif 1026 #endif 1027 1028 #ifdef SIGURG 1029 if (signal(SIGURG, myoob) == SIG_ERR) 1030 syslog(LOG_ERR, "signal: %m"); 1031 #ifdef NEED_SIGFIX 1032 sigaddset(&block_sigmask, SIGURG); 1033 #endif 1034 #endif 1035 #endif /* SIG_DEBUG */ 1036 1037 #ifdef VIRTUAL 1038 virtual_root[0] = '\0'; 1039 virtual_banner[0] = '\0'; 1040 #endif 1041 1042 setup_paths(); 1043 1044 #ifdef OTHER_PASSWD 1045 strcpy(_path_passwd, "/etc/passwd"); 1046 #ifdef SHADOW_PASSWORD 1047 strcpy(_path_shadow, "/etc/shadow"); 1048 #endif 1049 #endif 1050 1051 access_init(); 1052 1053 #ifdef DAEMON 1054 if (be_daemon != 0) 1055 do_daemon(); 1056 else { 1057 #endif 1058 addrlen = sizeof(his_addr); 1059 if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) { 1060 syslog(LOG_ERR, "getpeername: %m"); 1061 #ifndef DEBUG 1062 exit(1); 1063 #endif 1064 } 1065 #ifdef DAEMON 1066 } 1067 #endif 1068 addrlen = sizeof(ctrl_addr); 1069 if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) { 1070 syslog(LOG_ERR, "getsockname: %m"); 1071 #ifndef DEBUG 1072 exit(1); 1073 #endif 1074 } 1075 /* Sanity check */ 1076 if ((SOCK_FAMILY(ctrl_addr) != AF_INET) 1077 #ifdef INET6 1078 && (SOCK_FAMILY(ctrl_addr) != AF_INET6) 1079 #endif 1080 ) { 1081 syslog(LOG_ERR, "control connection address family (%d) not supported.", 1082 SOCK_FAMILY(ctrl_addr)); 1083 #ifndef DEBUG 1084 exit(1); 1085 #endif 1086 } 1087 #ifdef SOLARIS_BSM_AUDIT 1088 /* Set audit characteristics */ 1089 if (audit_settid(0)) { 1090 syslog(LOG_ERR, "audit failure"); 1091 exit(1); 1092 } 1093 #endif 1094 #ifdef INET6 1095 /* IP_TOS is an IPv4 socket option */ 1096 if (SOCK_FAMILY(ctrl_addr) == AF_INET) 1097 #endif 1098 if ((cos = IPClassOfService("control")) >= 0) { 1099 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &cos, sizeof(int)) < 0) 1100 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 1101 } 1102 1103 #ifdef TCP_NODELAY 1104 /* 1105 * Disable Nagle on the control channel so that we don't have to wait 1106 * for peer's ACK before issuing our next reply. 1107 */ 1108 if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0) 1109 syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m"); 1110 #endif 1111 1112 if (keepalive) 1113 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) 1114 syslog(LOG_ERR, "setsockopt SO_KEEPALIVE %m"); 1115 1116 /* Try to handle urgent data inline */ 1117 #ifdef SO_OOBINLINE 1118 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *) &on, sizeof(int)) < 0) 1119 syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m"); 1120 #endif 1121 1122 #ifdef F_SETOWN 1123 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) 1124 syslog(LOG_ERR, "fcntl F_SETOWN: %m"); 1125 #elif defined(SIOCSPGRP) 1126 { 1127 int pid; 1128 pid = getpid(); 1129 if (ioctl(fileno(stdin), SIOCSPGRP, &pid) == -1) 1130 syslog(LOG_ERR, "ioctl SIOCSPGRP: %m"); 1131 } 1132 #endif 1133 1134 #ifdef INET6 1135 if ((SOCK_FAMILY(ctrl_addr) == AF_INET6) && 1136 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&(ctrl_addr))->sin6_addr)) 1137 ctrl_v4mapped = 1; 1138 #endif 1139 1140 if (data_port == 0) { 1141 serv = getservbyname("ftp-data", "tcp"); 1142 if (serv != NULL) 1143 data_port = serv->s_port; 1144 else 1145 data_port = htons(ntohs(SOCK_PORT(ctrl_addr)) - 1); 1146 } 1147 1148 if (RootDirectory != NULL) { 1149 if ((chroot(RootDirectory) < 0) 1150 || (chdir("/") < 0)) { 1151 syslog(LOG_ERR, "Cannot chroot to initial directory, aborting."); 1152 exit(1); 1153 } 1154 } 1155 1156 load_timeouts(); 1157 1158 /* set resolver options */ 1159 set_res_options(); 1160 1161 dolog(&his_addr); 1162 /* Set up default state */ 1163 data = -1; 1164 type = TYPE_A; 1165 form = FORM_N; 1166 stru = STRU_F; 1167 mode = MODE_S; 1168 tmpline[0] = '\0'; 1169 yyerrorcalled = 0; 1170 1171 entry = (struct aclmember *) NULL; 1172 if ((getaclentry("hostname", &entry)) && ARG0) { 1173 (void) strncpy(hostname, ARG0, sizeof(hostname)); 1174 hostname[sizeof(hostname) - 1] = '\0'; 1175 } 1176 else { 1177 #ifdef HAVE_SYSINFO 1178 sysinfo(SI_HOSTNAME, hostname, sizeof(hostname)); 1179 #else 1180 (void) gethostname(hostname, sizeof(hostname)); 1181 #endif 1182 /* set the FQDN here */ 1183 hp = wu_gethostbyname(hostname); 1184 if (hp) { 1185 (void) strncpy(hostname, hp, sizeof(hostname)); 1186 hostname[sizeof(hostname) - 1] = '\0'; 1187 } 1188 } 1189 route_vectored = routevector(); 1190 conv_init(); 1191 1192 #ifdef MAIL_ADMIN 1193 incmails = 0; 1194 mailfrom = NULL; 1195 #endif /* MAIL_ADMIN */ 1196 #ifdef VIRTUAL 1197 /* 1198 ** If virtual_mode is set at this point then an alternate ftpaccess 1199 ** is in use. Otherwise we need to check the Master ftpaccess file 1200 ** to see if the site is only using the "virtual" directives to 1201 ** specify virtual site directives. 1202 ** 1203 ** In this manner an admin can put a virtual site in the ftpservers 1204 ** file if they need expanded configuration support or can use the 1205 ** minimal root/banner/logfile if they do not need any more than that. 1206 */ 1207 1208 if (virtual_mode) { 1209 /* Get the root of the virtual server directory */ 1210 entry = (struct aclmember *) NULL; 1211 if (getaclentry("root", &entry)) { 1212 if (ARG0) 1213 strcpy(virtual_root, ARG0); 1214 } 1215 1216 /* Get the logfile to use */ 1217 entry = (struct aclmember *) NULL; 1218 if (getaclentry("logfile", &entry)) { 1219 if (ARG0) 1220 strcpy(logfile, ARG0); 1221 } 1222 } 1223 else { 1224 virtual_hostname[0] = '\0'; 1225 virtual_address[0] = '\0'; 1226 virtual_len = sizeof(virtual_addr); 1227 if (getsockname(0, (struct sockaddr *) &virtual_addr, &virtual_len) == 0) { 1228 strcpy(virtual_address, inet_stop(&virtual_addr)); 1229 wu_gethostbyaddr(&virtual_addr, virtual_hostname, sizeof(virtual_hostname)); 1230 entry = (struct aclmember *) NULL; 1231 while (getaclentry("virtual", &entry)) { 1232 if (!ARG0 || !ARG1 || !ARG2) 1233 continue; 1234 if (hostmatch(ARG0, virtual_address, virtual_hostname)) { 1235 if (!strcasecmp(ARG1, "root")) { 1236 if (debug) 1237 syslog(LOG_DEBUG, "VirtualFTP Connect to: %s [%s]", 1238 virtual_hostname, virtual_address); 1239 virtual_mode = 1; 1240 strncpy(virtual_root, ARG2, sizeof(virtual_root)); 1241 virtual_root[sizeof(virtual_root) - 1] = '\0'; 1242 /* reset hostname to this virtual name */ 1243 (void) strcpy(hostname, virtual_hostname); 1244 virtual_email[0] = '\0'; 1245 } 1246 if (!strcasecmp(ARG1, "banner")) { 1247 strncpy(virtual_banner, ARG2, sizeof(virtual_banner)); 1248 virtual_banner[sizeof(virtual_banner) - 1] = '\0'; 1249 } 1250 if (!strcasecmp(ARG1, "logfile")) { 1251 strncpy(logfile, ARG2, sizeof(logfile)); 1252 logfile[sizeof(logfile) - 1] = '\0'; 1253 } 1254 if (!strcasecmp(ARG1, "hostname")) { 1255 strncpy(hostname, ARG2, sizeof(hostname)); 1256 hostname[sizeof(hostname) - 1] = '\0'; 1257 } 1258 if (!strcasecmp(ARG1, "email")) { 1259 strncpy(virtual_email, ARG2, sizeof(virtual_email)); 1260 virtual_email[sizeof(virtual_email) - 1] = '\0'; 1261 } 1262 #ifdef OTHER_PASSWD 1263 if (!strcasecmp(ARG1, "passwd")) { 1264 strncpy(_path_passwd, ARG2, sizeof(_path_passwd)); 1265 _path_passwd[sizeof(_path_passwd) - 1] = '\0'; 1266 #ifdef USE_PAM 1267 use_pam = 0; 1268 #endif 1269 } 1270 #ifdef SHADOW_PASSWORD 1271 if (!strcasecmp(ARG1, "shadow")) { 1272 strncpy(_path_shadow, ARG2, sizeof(_path_shadow)); 1273 _path_shadow[sizeof(_path_shadow) - 1] = '\0'; 1274 #ifdef USE_PAM 1275 use_pam = 0; 1276 #endif 1277 } 1278 #endif 1279 #endif 1280 #ifdef MAIL_ADMIN 1281 if (mailfrom == NULL) 1282 if (!strcasecmp(ARG1, "mailfrom")) { 1283 mailfrom = strdup(ARG2); 1284 } 1285 if (!strcasecmp(ARG1, "incmail")) { 1286 if (incmails < INCMAILS) 1287 incmail[incmails++] = strdup(ARG2); 1288 } 1289 #endif 1290 } 1291 } 1292 if (!virtual_mode) { 1293 entry = (struct aclmember *) NULL; 1294 while (getaclentry("defaultserver", &entry)) { 1295 if (!ARG0 || !ARG1) 1296 continue; 1297 #ifdef MAIL_ADMIN 1298 if (mailfrom == NULL) 1299 if (!strcasecmp(ARG0, "mailfrom")) { 1300 mailfrom = strdup(ARG1); 1301 } 1302 if (!strcasecmp(ARG0, "incmail")) { 1303 if (incmails < INCMAILS) 1304 incmail[incmails++] = strdup(ARG1); 1305 } 1306 #endif 1307 } 1308 } 1309 } 1310 } 1311 1312 #ifdef VIRTUAL_DEBUG 1313 lreply(220, "_path_ftpaccess == %s", _path_ftpaccess); 1314 lreply(220, "_path_ftpusers == %s", _path_ftpusers); 1315 lreply(220, "_path_ftphosts == %s", _path_ftphosts); 1316 lreply(220, "_path_private == %s", _path_private); 1317 lreply(220, "_path_cvt == %s", _path_cvt); 1318 if (virtual_mode) { 1319 if (virtual_ftpaccess) 1320 lreply(220, "VIRTUAL Mode: Using %s specific %s access file", 1321 hostname, _path_ftpaccess); 1322 else 1323 lreply(220, "VIRTUAL Mode: Using Master access file %s", 1324 _path_ftpaccess); 1325 1326 lreply(220, "virtual_root == %s", virtual_root); 1327 if (!virtual_ftpaccess) 1328 lreply(220, "virtual_banner == %s", virtual_banner); 1329 } 1330 lreply(220, "logfile == %s", logfile); 1331 #endif 1332 #endif 1333 1334 if (is_shutdown(1, 1) != 0) { 1335 syslog(LOG_INFO, "connection refused (server shut down) from %s", 1336 remoteident); 1337 reply(500, "%s FTP server shut down -- please try again later.", 1338 hostname); 1339 exit(0); 1340 } 1341 1342 #ifdef OPIE 1343 af_pwok = opieaccessfile(remotehost); 1344 #endif 1345 1346 /* check permitted access based on name and address lookup of remote host */ 1347 if (!check_rhost_reverse()) { 1348 exit(0); 1349 } 1350 if (!check_rhost_matches()) { 1351 exit(0); 1352 } 1353 1354 show_banner(220); 1355 1356 #ifndef INTERNAL_LS 1357 entry = (struct aclmember *) NULL; 1358 if (getaclentry("lslong", &entry) && ARG0 && (int) strlen(ARG0) > 0) { 1359 strcpy(ls_long, ARG0); 1360 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 1361 strcat(ls_long, " "); 1362 strcat(ls_long, ARG[which]); 1363 } 1364 } 1365 else { 1366 #if defined(SVR4) || defined(ISC) 1367 #if defined(AIX) || defined(SOLARIS_2) 1368 strcpy(ls_long, "/bin/ls -lA"); 1369 #else 1370 strcpy(ls_long, "/bin/ls -la"); 1371 #endif 1372 #else 1373 strcpy(ls_long, "/bin/ls -lgA"); 1374 #endif 1375 } 1376 strcat(ls_long, " %s"); 1377 1378 entry = (struct aclmember *) NULL; 1379 if (getaclentry("lsshort", &entry) && ARG0 && (int) strlen(ARG0) > 0) { 1380 strcpy(ls_short, ARG0); 1381 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 1382 strcat(ls_short, " "); 1383 strcat(ls_short, ARG[which]); 1384 } 1385 } 1386 else { 1387 #if defined(SVR4) || defined(ISC) 1388 #if defined(AIX) || defined(SOLARIS_2) 1389 strcpy(ls_short, "/bin/ls -lA"); 1390 #else 1391 strcpy(ls_short, "/bin/ls -la"); 1392 1393 #endif 1394 #else 1395 strcpy(ls_short, "/bin/ls -lgA"); 1396 #endif 1397 } 1398 strcat(ls_short, " %s"); 1399 1400 entry = (struct aclmember *) NULL; 1401 if (getaclentry("lsplain", &entry) && ARG0 && (int) strlen(ARG0) > 0) { 1402 strcpy(ls_plain, ARG0); 1403 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 1404 strcat(ls_plain, " "); 1405 strcat(ls_plain, ARG[which]); 1406 } 1407 } 1408 else 1409 strcpy(ls_plain, "/bin/ls"); 1410 strcat(ls_plain, " %s"); 1411 #endif /* ! INTERNAL_LS */ 1412 #ifdef MAIL_ADMIN 1413 mailservers = 0; 1414 entry = (struct aclmember *) NULL; 1415 while (getaclentry("mailserver", &entry) && ARG0 && mailservers < MAILSERVERS) 1416 mailserver[mailservers++] = strdup(ARG0); 1417 if (mailservers == 0) 1418 mailserver[mailservers++] = strdup("localhost"); 1419 if (incmails == 0) { 1420 entry = (struct aclmember *) NULL; 1421 while (getaclentry("incmail", &entry) && ARG0 && incmails < INCMAILS) 1422 incmail[incmails++] = strdup(ARG0); 1423 } 1424 if (mailfrom == NULL) { 1425 entry = (struct aclmember *) NULL; 1426 if (getaclentry("mailfrom", &entry) && ARG0) 1427 mailfrom = strdup(ARG0); 1428 else 1429 mailfrom = strdup("wu-ftpd"); 1430 } 1431 #endif /* MAIL_ADMIN */ 1432 { 1433 #define OUTPUT_LEN (BUFSIZ * 2) 1434 int version_option = 0; 1435 char output_text[OUTPUT_LEN + 1]; 1436 int which; 1437 1438 entry = NULL; 1439 if (getaclentry("greeting", &entry) && ARG0) { 1440 if (!strcasecmp(ARG0, "full")) 1441 version_option = 0; 1442 else if (!strcasecmp(ARG0, "text") && ARG1) 1443 version_option = 3; 1444 else if (!strcasecmp(ARG0, "terse")) 1445 version_option = 2; 1446 else if (!strcasecmp(ARG0, "brief")) 1447 version_option = 1; 1448 } 1449 switch (version_option) { 1450 default: 1451 reply(220, "%s FTP server (%s) ready.", hostname, version); 1452 break; 1453 case 1: 1454 reply(220, "%s FTP server ready.", hostname); 1455 break; 1456 case 2: 1457 reply(220, "FTP server ready."); 1458 break; 1459 case 3: 1460 output_text[0] = '\0'; 1461 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 1462 if (which > 1) 1463 (void) strlcat(output_text, " ", sizeof(output_text)); 1464 (void) strlcat(output_text, ARG[which], sizeof(output_text)); 1465 } 1466 reply(220, "%s", output_text); 1467 break; 1468 } 1469 } 1470 (void) setjmp(errcatch); 1471 1472 for (;;) 1473 (void) yyparse(); 1474 /* NOTREACHED */ 1475 } 1476 1477 1478 SIGNAL_TYPE randomsig(int sig) 1479 { 1480 #ifdef HAVE_SIGLIST 1481 syslog(LOG_ERR, "exiting on signal %d: %s", sig, sys_siglist[sig]); 1482 #else 1483 syslog(LOG_ERR, "exiting on signal %d", sig); 1484 #endif 1485 chdir("/"); 1486 signal(SIGIOT, SIG_DFL); 1487 signal(SIGILL, SIG_DFL); 1488 exit(1); 1489 /* dologout(-1); *//* NOTREACHED */ 1490 } 1491 1492 SIGNAL_TYPE lostconn(int sig) 1493 { 1494 #ifdef VERBOSE_ERROR_LOGING 1495 syslog(LOG_INFO, "lost connection to %s", remoteident); 1496 #else 1497 if (debug) 1498 syslog(LOG_DEBUG, "lost connection to %s", remoteident); 1499 #endif 1500 dologout(-1); 1501 } 1502 1503 static char ttyline[20]; 1504 1505 #ifdef MAPPING_CHDIR 1506 /* Keep track of the path the user has chdir'd into and respond with 1507 * that to pwd commands. This is to avoid having the absolue disk 1508 * path returned, which I want to avoid. 1509 */ 1510 char mapped_path[MAXPATHLEN] = "/"; 1511 1512 #if !defined(HAVE_GETCWD) 1513 char *mapping_getwd(char *path) 1514 { 1515 strcpy(path, mapped_path); 1516 return path; 1517 } 1518 #endif /* !defined(HAVE_GETCWD) */ 1519 1520 char *mapping_getcwd(char *path, size_t size) 1521 { 1522 (void) strlcpy(path, mapped_path, size); 1523 return path; 1524 } 1525 1526 /* Make these globals rather than local to mapping_chdir to avoid stack overflow */ 1527 char pathspace[MAXPATHLEN]; 1528 char old_mapped_path[MAXPATHLEN]; 1529 1530 void do_elem(char *dir) 1531 { 1532 /* . */ 1533 if (dir[0] == '.' && dir[1] == '\0') { 1534 /* ignore it */ 1535 return; 1536 } 1537 1538 /* .. */ 1539 if (dir[0] == '.' && dir[1] == '.' && dir[2] == '\0') { 1540 char *last; 1541 /* lop the last directory off the path */ 1542 if ((last = strrchr(mapped_path, '/'))) { 1543 /* If start of pathname leave the / */ 1544 if (last == mapped_path) 1545 last++; 1546 *last = '\0'; 1547 } 1548 return; 1549 } 1550 1551 /* append the dir part with a leading / unless at root */ 1552 if (!(mapped_path[0] == '/' && mapped_path[1] == '\0')) 1553 (void) strlcat(mapped_path, "/", sizeof(mapped_path)); 1554 (void) strlcat(mapped_path, dir, sizeof(mapped_path)); 1555 } 1556 1557 int mapping_chdir(char *orig_path) 1558 { 1559 int ret; 1560 char *sl, *path; 1561 1562 (void) strlcpy(old_mapped_path, mapped_path, sizeof(old_mapped_path)); 1563 (void) strlcpy(pathspace, orig_path, sizeof(pathspace)); 1564 path = pathspace; 1565 1566 /* / at start of path, set the start of the mapped_path to / */ 1567 if (path[0] == '/') { 1568 mapped_path[0] = '/'; 1569 mapped_path[1] = '\0'; 1570 path++; 1571 } 1572 1573 while ((sl = strchr(path, '/'))) { 1574 char *dir; 1575 dir = path; 1576 *sl = '\0'; 1577 path = sl + 1; 1578 if (*dir) 1579 do_elem(dir); 1580 if (*path == '\0') 1581 break; 1582 } 1583 if (*path) 1584 do_elem(path); 1585 1586 if ((ret = chdir(mapped_path)) < 0) { 1587 (void) strlcpy(mapped_path, old_mapped_path, sizeof(mapped_path)); 1588 } 1589 1590 return ret; 1591 } 1592 /* From now on use the mapping version */ 1593 1594 #define chdir(d) mapping_chdir(d) 1595 #define getwd(d) mapping_getwd(d) 1596 #define getcwd(d,u) mapping_getcwd((d),(u)) 1597 1598 #endif /* MAPPING_CHDIR */ 1599 1600 /* Helper function for sgetpwnam(). */ 1601 char *sgetsave(char *s) 1602 { 1603 char *new; 1604 1605 new = (char *) malloc(strlen(s) + 1); 1606 1607 if (new == NULL) { 1608 perror_reply(421, "Local resource failure: malloc"); 1609 dologout(1); 1610 /* NOTREACHED */ 1611 } 1612 (void) strcpy(new, s); 1613 return (new); 1614 } 1615 1616 /* Save the result of a getpwnam. Used for USER command, since the data 1617 * returned must not be clobbered by any other command (e.g., globbing). */ 1618 struct passwd *sgetpwnam(char *name) 1619 { 1620 static struct passwd save; 1621 register struct passwd *p; 1622 #ifdef M_UNIX 1623 struct passwd *ret = (struct passwd *) NULL; 1624 #endif 1625 char *sgetsave(char *s); 1626 #ifdef KERBEROS 1627 register struct authorization *q; 1628 #endif /* KERBEROS */ 1629 1630 #if defined(SecureWare) || defined(HPUX_10_TRUSTED) 1631 struct pr_passwd *pr; 1632 #endif 1633 1634 #ifdef KERBEROS 1635 init_krb(); 1636 q = getauthuid(p->pw_uid); 1637 end_krb(); 1638 #endif /* KERBEROS */ 1639 1640 #ifdef M_UNIX 1641 #if defined(SecureWare) || defined(HPUX_10_TRUSTED) 1642 if ((pr = getprpwnam(name)) == NULL) 1643 goto DONE; 1644 #endif /* SecureWare || HPUX_10_TRUSTED */ 1645 #ifdef OTHER_PASSWD 1646 if ((p = bero_getpwnam(name, _path_passwd)) == NULL) 1647 #else 1648 if ((p = getpwnam(name)) == NULL) 1649 #endif 1650 goto DONE; 1651 #else /* M_UNIX */ 1652 #if defined(SecureWare) || defined(HPUX_10_TRUSTED) 1653 if ((pr = getprpwnam(name)) == NULL) 1654 return ((struct passwd *) pr); 1655 #endif /* SecureWare || HPUX_10_TRUSTED */ 1656 #ifdef OTHER_PASSWD 1657 if ((p = bero_getpwnam(name, _path_passwd)) == NULL) 1658 #else 1659 if ((p = getpwnam(name)) == NULL) 1660 #endif 1661 return (p); 1662 #endif /* M_UNIX */ 1663 1664 if (save.pw_name) 1665 free(save.pw_name); 1666 if (save.pw_gecos) 1667 free(save.pw_gecos); 1668 if (save.pw_dir) 1669 free(save.pw_dir); 1670 if (save.pw_shell) 1671 free(save.pw_shell); 1672 if (save.pw_passwd) 1673 free(save.pw_passwd); 1674 1675 save = *p; 1676 1677 save.pw_name = sgetsave(p->pw_name); 1678 1679 #ifdef KERBEROS 1680 save.pw_passwd = sgetsave(q->a_password); 1681 #elif defined(SecureWare) || defined(HPUX_10_TRUSTED) 1682 if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt) 1683 save.pw_passwd = sgetsave(pr->ufld.fd_encrypt); 1684 else 1685 save.pw_passwd = sgetsave(""); 1686 #else 1687 save.pw_passwd = sgetsave(p->pw_passwd); 1688 #endif 1689 #ifdef SHADOW_PASSWORD 1690 if (p && (p->pw_passwd==NULL || strlen(p->pw_passwd)<8)) { 1691 struct spwd *spw; 1692 #ifdef OTHER_PASSWD 1693 if ((spw = bero_getspnam(p->pw_name, _path_shadow)) != NULL) { 1694 #else 1695 setspent(); 1696 if ((spw = getspnam(p->pw_name)) != NULL) { 1697 #endif 1698 int expired = 0; 1699 /*XXX Does this work on all Shadow Password Implementations? */ 1700 /* it is supposed to work on Solaris 2.x */ 1701 time_t now; 1702 long today; 1703 1704 now = time((time_t *) 0); 1705 today = now / (60 * 60 * 24); 1706 1707 if ((spw->sp_expire > 0) && (spw->sp_expire < today)) 1708 expired++; 1709 if ((spw->sp_max > 0) && (spw->sp_lstchg > 0) && 1710 (spw->sp_lstchg + spw->sp_max < today)) 1711 expired++; 1712 free(save.pw_passwd); 1713 save.pw_passwd = sgetsave(expired ? "" : spw->sp_pwdp); 1714 } 1715 /* Don't overwrite the password if the shadow read fails, getpwnam() is NIS 1716 aware but getspnam() is not. */ 1717 /* Shadow passwords are optional on Linux. --marekm */ 1718 #if !defined(LINUX) && !defined(UNIXWARE) 1719 else { 1720 free(save.pw_passwd); 1721 save.pw_passwd = sgetsave(""); 1722 } 1723 #endif 1724 /* marekm's fix for linux proc file system shadow passwd exposure problem */ 1725 #ifndef OTHER_PASSWD 1726 endspent(); 1727 #endif 1728 } 1729 #endif 1730 save.pw_gecos = sgetsave(p->pw_gecos); 1731 save.pw_dir = sgetsave(p->pw_dir); 1732 save.pw_shell = sgetsave(p->pw_shell); 1733 #ifdef M_UNIX 1734 ret = &save; 1735 DONE: 1736 endpwent(); 1737 #endif 1738 #if defined(SecureWare) || defined(HPUX_10_TRUSTED) 1739 endprpwent(); 1740 #endif 1741 #ifdef M_UNIX 1742 return (ret); 1743 #else 1744 return (&save); 1745 #endif 1746 } 1747 #if defined(SKEY) && !defined(__NetBSD__) 1748 /* 1749 * From Wietse Venema, Eindhoven University of Technology. 1750 */ 1751 /* skey_challenge - additional password prompt stuff */ 1752 1753 char *skey_challenge(char *name, struct passwd *pwd, int pwok) 1754 { 1755 static char buf[128]; 1756 char sbuf[40]; 1757 struct skey skey; 1758 1759 /* Display s/key challenge where appropriate. */ 1760 1761 if (pwd == NULL || skeychallenge(&skey, pwd->pw_name, sbuf)) 1762 sprintf(buf, "Password required for %s.", name); 1763 else 1764 sprintf(buf, "%s %s for %s.", sbuf, 1765 pwok ? "allowed" : "required", name); 1766 return (buf); 1767 } 1768 #endif 1769 1770 int login_attempts; /* number of failed login attempts */ 1771 int askpasswd; /* had user command, ask for passwd */ 1772 #ifndef HELP_CRACKERS 1773 int DenyLoginAfterPassword; 1774 char DelayedMessageFile[MAXPATHLEN]; 1775 extern void pr_mesg(int msgcode, char *msgfile); 1776 #endif 1777 1778 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 1779 static int defaultserver_allow(const char *username) 1780 { 1781 struct aclmember *entry = NULL; 1782 int which; 1783 1784 while (getaclentry("defaultserver", &entry)) 1785 if (ARG0 && !strcasecmp(ARG0, "allow")) 1786 for (which = 1; (which < MAXARGS) && ARG[which]; which++) 1787 if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) 1788 return (1); 1789 return (0); 1790 } 1791 1792 static int defaultserver_deny(const char *username) 1793 { 1794 struct aclmember *entry = NULL; 1795 int which; 1796 1797 while (getaclentry("defaultserver", &entry)) 1798 if (ARG0 && !strcasecmp(ARG0, "deny")) 1799 for (which = 1; (which < MAXARGS) && ARG[which]; which++) 1800 if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) 1801 return (1); 1802 return (0); 1803 } 1804 1805 static int defaultserver_private(void) 1806 { 1807 struct aclmember *entry = NULL; 1808 1809 while (getaclentry("defaultserver", &entry)) 1810 if (ARG0 && !strcasecmp(ARG0, "private")) 1811 return (1); 1812 return (0); 1813 } 1814 #endif 1815 1816 /* USER command. Sets global passwd pointer pw if named account exists and is 1817 * acceptable; sets askpasswd if a PASS command is expected. If logged in 1818 * previously, need to reset state. If name is "ftp" or "anonymous", the 1819 * name is not in the ftpusers file, and ftp account exists, set anonymous and 1820 * pw, then just return. If account doesn't exist, ask for passwd anyway. 1821 * Otherwise, check user requesting login privileges. Disallow anyone who 1822 * does not have a standard shell as returned by getusershell(). Disallow 1823 * anyone mentioned in the ftpusers file to allow people such as root and 1824 * uucp to be avoided. */ 1825 1826 /* 1827 char *getusershell(); 1828 */ 1829 void user(char *name) 1830 { 1831 char *cp; 1832 char *shell; 1833 #ifdef BSD_AUTH 1834 char *auth; 1835 #endif 1836 #if defined(USE_GSS) 1837 int gss_need_passwd = 1; 1838 #endif 1839 1840 /* H* fix: if we're logged in at all, we can't log in again. */ 1841 if (logged_in) { 1842 #ifdef VERBOSE_ERROR_LOGING 1843 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (already logged in as %s) FROM %s, %s", 1844 pw->pw_name, remoteident, name); 1845 #endif 1846 reply(530, "Already logged in."); 1847 return; 1848 } 1849 #ifndef HELP_CRACKERS 1850 askpasswd = 1; 1851 DenyLoginAfterPassword = 0; 1852 DelayedMessageFile[0] = '\0'; 1853 #endif 1854 #ifdef BSD_AUTH 1855 if ((auth = strchr(name, ':'))) 1856 *auth++ = 0; 1857 #endif 1858 1859 #ifdef HOST_ACCESS /* 19-Mar-93 BM */ 1860 if (!rhost_ok(name, remotehost, remoteaddr)) { 1861 #ifndef HELP_CRACKERS 1862 DenyLoginAfterPassword = 1; 1863 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (name in %s) FROM %s, %s", 1864 _path_ftphosts, remoteident, name); 1865 #else 1866 reply(530, "User %s access denied.", name); 1867 syslog(LOG_NOTICE, 1868 "FTP LOGIN REFUSED (name in %s) FROM %s, %s", 1869 _path_ftphosts, remoteident, name); 1870 return; 1871 #endif 1872 } 1873 #endif 1874 1875 strncpy(the_user, name, MAXUSERNAMELEN - 1); 1876 1877 anonymous = 0; 1878 guest = 0; 1879 1880 if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) { 1881 struct aclmember *entry = NULL; 1882 int machineok = 1; 1883 char guestservername[MAXHOSTNAMELEN]; 1884 guestservername[0] = '\0'; 1885 1886 #ifdef NO_ANONYMOUS_ACCESS 1887 reply(530, "Anonymous FTP access denied."); 1888 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp not supported) FROM %s, %s", 1889 remoteident, name); 1890 return; 1891 #else 1892 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 1893 if (!virtual_mode && defaultserver_private()) { 1894 #ifndef HELP_CRACKERS 1895 DenyLoginAfterPassword = 1; 1896 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s", 1897 remoteident, name); 1898 #else 1899 reply(530, "User %s access denied.", name); 1900 syslog(LOG_NOTICE, 1901 "FTP LOGIN REFUSED (anonymous ftp denied on default server) FROM %s, %s", 1902 remoteident, name); 1903 return; 1904 #endif 1905 } 1906 #endif 1907 if (checkuser("ftp") || checkuser("anonymous")) { 1908 #ifndef HELP_CRACKERS 1909 DenyLoginAfterPassword = 1; 1910 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s", 1911 _path_ftpusers, remoteident, name); 1912 #else 1913 reply(530, "User %s access denied.", name); 1914 syslog(LOG_NOTICE, 1915 "FTP LOGIN REFUSED (ftp in %s) FROM %s, %s", 1916 _path_ftpusers, remoteident, name); 1917 return; 1918 #endif 1919 1920 /* 1921 ** Algorithm used: 1922 ** - if no "guestserver" directive is present, 1923 ** anonymous access is allowed, for backward compatibility. 1924 ** - if a "guestserver" directive is present, 1925 ** anonymous access is restricted to the machines listed, 1926 ** usually the machine whose CNAME on the current domain 1927 ** is "ftp"... 1928 ** 1929 ** the format of the "guestserver" line is 1930 ** guestserver [<machine1> [<machineN>]] 1931 ** that is, "guestserver" will forbid anonymous access on all machines 1932 ** while "guestserver ftp inf" will allow anonymous access on 1933 ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr". 1934 ** 1935 ** if anonymous access is denied on the current machine, 1936 ** the user will be asked to use the first machine listed (if any) 1937 ** on the "guestserver" line instead: 1938 ** 530- Guest login not allowed on this machine, 1939 ** connect to ftp.enst.fr instead. 1940 ** 1941 ** -- <Nicolas.Pioch@enst.fr> 1942 */ 1943 } 1944 else if (getaclentry("guestserver", &entry)) { 1945 char *tmphost; 1946 1947 /* 1948 ** if a "guestserver" line is present, 1949 ** default is not to allow guest logins 1950 */ 1951 machineok = 0; 1952 1953 if (hostname[0] 1954 && ((tmphost = wu_gethostbyname(hostname)))) { 1955 1956 /* 1957 ** hostname is the only first part of the FQDN 1958 ** this may or may not correspond to the h_name value 1959 ** (machines with more than one IP#, CNAMEs...) 1960 ** -> need to fix that, calling gethostbyname on hostname 1961 ** 1962 ** WARNING! 1963 ** for SunOS 4.x, you need to have a working resolver in the libc 1964 ** for CNAMES to work properly. 1965 ** If you don't, add "-lresolv" to the libraries before compiling! 1966 */ 1967 char dns_localhost[MAXHOSTNAMELEN]; 1968 int machinecount; 1969 1970 strncpy(dns_localhost, tmphost, sizeof(dns_localhost)); 1971 dns_localhost[sizeof(dns_localhost) - 1] = '\0'; 1972 1973 for (machinecount = 0; 1974 (machinecount < MAXARGS) && entry->arg[machinecount]; 1975 machinecount++) { 1976 1977 if ((tmphost = wu_gethostbyname(entry->arg[machinecount]))) { 1978 /* 1979 ** remember the name of the first machine for redirection 1980 */ 1981 1982 if (!machinecount) { 1983 strncpy(guestservername, entry->arg[machinecount], 1984 sizeof(guestservername)); 1985 guestservername[sizeof(guestservername) - 1] = '\0'; 1986 } 1987 1988 if (!strcasecmp(tmphost, dns_localhost)) { 1989 machineok++; 1990 break; 1991 } 1992 } 1993 } 1994 } 1995 } 1996 if (!machineok) { 1997 if (guestservername[0]) 1998 reply(530, 1999 "Guest login not allowed on this machine, connect to %s instead.", 2000 guestservername); 2001 else 2002 reply(530, 2003 "Guest login not allowed on this machine."); 2004 syslog(LOG_NOTICE, 2005 "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s, %s", 2006 remoteident, name); 2007 /* End of the big patch -- Nap */ 2008 2009 dologout(0); 2010 } 2011 else if ((pw = sgetpwnam("ftp")) != NULL) { 2012 anonymous = 1; /* for the access_ok call */ 2013 if (access_ok(530) < 1) { 2014 #ifndef HELP_CRACKERS 2015 DenyLoginAfterPassword = 1; 2016 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", 2017 remoteident, name); 2018 reply(331, "Guest login ok, send your complete e-mail address as password."); 2019 #else 2020 reply(530, "User %s access denied.", name); 2021 syslog(LOG_NOTICE, 2022 "FTP LOGIN REFUSED (access denied) FROM %s, %s", 2023 remoteident, name); 2024 dologout(0); 2025 #endif 2026 } 2027 else { 2028 askpasswd = 1; 2029 /* H* fix: obey use_accessfile a little better. This way, things set on the 2030 command line [like xferlog stuff] don't get stupidly overridden. 2031 XXX: all these checks maybe should be in acl.c and access.c */ 2032 if (use_accessfile) 2033 acl_setfunctions(); 2034 reply(331, "Guest login ok, send your complete e-mail address as password."); 2035 } 2036 } 2037 else { 2038 #ifndef HELP_CRACKERS 2039 DenyLoginAfterPassword = 1; 2040 reply(331, "Guest login ok, send your complete e-mail address as password."); 2041 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s", 2042 remoteident, name); 2043 #else 2044 reply(530, "User %s unknown.", name); 2045 syslog(LOG_NOTICE, 2046 "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s, %s", 2047 remoteident, name); 2048 #endif 2049 #ifdef SOLARIS_BSM_AUDIT 2050 audit_ftpd_no_anon(); 2051 #endif 2052 } 2053 return; 2054 #endif 2055 } 2056 #ifdef ANON_ONLY 2057 /* H* fix: define the above to completely DISABLE logins by real users, 2058 despite ftpusers, shells, or any of that rot. You can always hang your 2059 "real" server off some other port, and access-control it. */ 2060 2061 else { /* "ftp" or "anon" -- MARK your conditionals, okay?! */ 2062 #ifndef HELP_CRACKERS 2063 DenyLoginAfterPassword = 1; 2064 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (not anonymous) FROM %s, %s", 2065 remoteident, name); 2066 reply(331, "Password required for %s.", name); 2067 #else 2068 reply(530, "User %s unknown.", name); 2069 syslog(LOG_NOTICE, 2070 "FTP LOGIN REFUSED (not anonymous) FROM %s, %s", 2071 remoteident, name); 2072 #endif 2073 return; 2074 } 2075 /* fall here if username okay in any case */ 2076 #endif /* ANON_ONLY */ 2077 2078 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 2079 if (!virtual_mode && defaultserver_deny(name) && !defaultserver_allow(name)) { 2080 #ifndef HELP_CRACKERS 2081 DenyLoginAfterPassword = 1; 2082 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s", 2083 remoteident, name); 2084 #else 2085 reply(530, "User %s access denied.", name); 2086 syslog(LOG_NOTICE, 2087 "FTP LOGIN REFUSED (ftp denied on default server) FROM %s, %s", 2088 remoteident, name); 2089 return; 2090 #endif 2091 } 2092 #endif 2093 2094 #if defined(USE_GSS) 2095 if (gss_info.must_gss_auth && 2096 (!IS_GSSAUTH(cur_auth_type) || 2097 !(gss_info.authstate & GSS_ADAT_DONE))) { 2098 reply(530, "Must perform authentication before identifying USER."); 2099 return; 2100 } 2101 #endif /* USE_GSS */ 2102 2103 if ((pw = sgetpwnam(name)) != NULL) { 2104 if ((denieduid(pw->pw_uid) && !alloweduid(pw->pw_uid)) 2105 || (deniedgid(pw->pw_gid) && !allowedgid(pw->pw_gid))) { 2106 #ifndef HELP_CRACKERS 2107 DenyLoginAfterPassword = 1; 2108 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s", 2109 remoteident, name); 2110 reply(331, "Password required for %s.", name); 2111 #else 2112 reply(530, "User %s access denied.", name); 2113 syslog(LOG_NOTICE, 2114 "FTP LOGIN REFUSED (username in denied-uid) FROM %s, %s", 2115 remoteident, name); 2116 #endif 2117 return; 2118 } 2119 #if defined(USE_GSS) 2120 if (IS_GSSAUTH(cur_auth_type) && 2121 (gss_info.authstate & GSS_ADAT_DONE)) { 2122 char buf[BUFSIZ]; 2123 2124 if (gss_user(pw)) 2125 gss_info.authstate |= GSS_USER_DONE; 2126 2127 if (gss_info.must_gss_auth && 2128 !GSSUSERAUTH_OK(gss_info)) { 2129 reply(530, "User %s access denied", name); 2130 if (logging) 2131 syslog(LOG_NOTICE, "FTP GSSAPI LOGIN REFUSED FROM %s, %s", 2132 remoteident, name); 2133 pw = NULL; 2134 return; 2135 } 2136 /* 2137 * If GSSAPI user auth failed, or it succeeded but creds were 2138 * not forwarded as required, prompt for password. 2139 */ 2140 gss_need_passwd = !GSSUSERAUTH_OK(gss_info) || 2141 (GSSUSERAUTH_OK(gss_info) && 2142 (gss_info.want_creds && !gss_info.have_creds)); 2143 if (gss_need_passwd) { 2144 snprintf(buf, sizeof(buf), 2145 "GSSAPI user %s is authorized as %s password required", 2146 gss_info.display_name, name); 2147 reply(331, "%s", buf); 2148 askpasswd = 1; 2149 syslog(LOG_DEBUG, "%s", buf); 2150 return; 2151 } 2152 } 2153 #endif /* defined(USE_GSS) */ 2154 2155 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) || defined(SOLARIS_2) /* PAM should be doing these checks, not ftpd */ 2156 #if defined(USE_PAM) && !defined(SOLARIS_2) 2157 if(!use_pam) { 2158 #endif 2159 if ((shell = pw->pw_shell) == NULL || *shell == 0) 2160 shell = _PATH_BSHELL; 2161 while ((cp = getusershell()) != NULL) 2162 if (strcmp(cp, shell) == 0) 2163 break; 2164 endusershell(); 2165 if (cp == NULL || checkuser(name)) { 2166 #ifndef HELP_CRACKERS 2167 DenyLoginAfterPassword = 1; 2168 if (cp == NULL) 2169 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name); 2170 else 2171 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name); 2172 reply(331, "Password required for %s.", name); 2173 #else 2174 reply(530, "User %s access denied.", name); 2175 if (cp == NULL) 2176 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (shell not in /etc/shells) FROM %s, %s", remoteident, name); 2177 else 2178 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (username in %s) FROM %s, %s", _path_ftpusers, remoteident, name); 2179 #endif /* HELP_CRACKERS */ 2180 pw = (struct passwd *) NULL; 2181 return; 2182 } 2183 #if defined(USE_PAM) && !defined(SOLARIS_2) 2184 } /* if(!use_pam) */ 2185 #endif 2186 #endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) || SOLARIS_2 */ 2187 /* if user is a member of any of the guestgroups, cause a chroot() */ 2188 /* after they log in successfully */ 2189 if (use_accessfile) { /* see above. _H */ 2190 guest = acl_guestgroup(pw); 2191 if (guest && acl_realgroup(pw)) 2192 guest = 0; 2193 } 2194 } 2195 if (access_ok(530) < 1) { 2196 #ifndef HELP_CRACKERS 2197 DenyLoginAfterPassword = 1; 2198 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", 2199 remoteident, name); 2200 reply(331, "Password required for %s.", name); 2201 #else 2202 reply(530, "User %s access denied.", name); 2203 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s, %s", 2204 remoteident, name); 2205 #endif 2206 return; 2207 } 2208 else if (use_accessfile) /* see above. _H */ 2209 acl_setfunctions(); 2210 2211 #ifdef BSD_AUTH 2212 if ((cp = start_auth(auth, name, pw)) != NULL) { 2213 char *s; 2214 2215 for (;;) { 2216 s = strsep(&cp, "\n"); 2217 if (cp == NULL || *cp == '\0') 2218 break; 2219 lreply(331, "%s", s); 2220 } 2221 reply(331, "%s", s); 2222 } 2223 else { 2224 #endif /* BSD_AUTH */ 2225 #ifdef SKEY 2226 #ifndef __NetBSD__ 2227 #ifdef SKEY_NAME 2228 /* this is the old way, but freebsd uses it */ 2229 pwok = skeyaccess(name, NULL, remotehost, remoteaddr); 2230 #else 2231 /* this is the new way */ 2232 pwok = skeyaccess(pw, NULL, remotehost, remoteaddr); 2233 #endif /* SKEY_NAME */ 2234 reply(331, "%s", skey_challenge(name, pw, pwok)); 2235 #else 2236 if (skey_haskey(name) == 0) { 2237 char *myskey; 2238 2239 myskey = skey_keyinfo(name); 2240 reply(331, "Password [%s] required for %s.", 2241 myskey ? myskey : "error getting challenge", name); 2242 } 2243 else 2244 reply(331, "Password required for %s.", name); 2245 #endif /* __NetBSD__ */ 2246 #else 2247 #ifdef OPIE 2248 { 2249 char prompt[OPIE_CHALLENGE_MAX + 1]; 2250 opiechallenge(&opiestate, name, prompt); 2251 2252 if (askpasswd == -1) { 2253 syslog(LOG_WARNING, "Invalid FTP user name %s attempted from %s", name, remotehost); 2254 pwok = 0; 2255 } 2256 else 2257 pwok = af_pwok && opiealways(pw->pw_dir); 2258 reply(331, "Response to %s %s for %s.", 2259 prompt, pwok ? "requested" : "required", name); 2260 } 2261 #else /* !SKEY */ 2262 2263 #if defined(USE_GSS) 2264 if (GSSUSERAUTH_OK(gss_info) && !gss_need_passwd) { 2265 /* 2266 * We got this far, we are allowing the GSSAPI authentication 2267 * to succeed without further passwd prompting. Jump 2268 * to "pass" processing. 2269 */ 2270 askpasswd = 0; 2271 logged_in = 1; 2272 pass(""); 2273 return; 2274 } 2275 #endif /* defined(USE_GSS) */ 2276 reply(331, "Password required for %s.", name); 2277 #endif /* OPIE */ 2278 #endif /* SKEY */ 2279 #ifdef BSD_AUTH 2280 } 2281 #endif /* BSD_AUTH */ 2282 2283 askpasswd = 1; 2284 /* Delay before reading passwd after first failed attempt to slow down 2285 * passwd-guessing programs. */ 2286 if (login_attempts) { 2287 enable_signaling(); /* we can allow signals once again: kinch */ 2288 sleep((unsigned) login_attempts); 2289 } 2290 return; 2291 } 2292 2293 /* Check if a user is in the ftpusers file */ 2294 int checkuser(char *name) 2295 { 2296 register FILE *fd; 2297 register char *p; 2298 char line[BUFSIZ]; 2299 2300 #ifdef SOLARIS_ETC_FTPUSERS 2301 static int etc_ftpusers = 0; 2302 2303 if (etc_ftpusers) { 2304 strcpy(_path_ftpusers, _PATH_FTPUSERS); 2305 etc_ftpusers = 0; 2306 } 2307 retry: 2308 #endif 2309 if ((fd = fopen(_path_ftpusers, "r")) != NULL) { 2310 while (fgets(line, sizeof(line), fd) != NULL) 2311 if ((p = strchr(line, '\n')) != NULL) { 2312 *p = '\0'; 2313 if (line[0] == '#') 2314 continue; 2315 if (strcasecmp(line, name) == 0) { 2316 (void) fclose(fd); 2317 #ifdef SOLARIS_BSM_AUDIT 2318 audit_ftpd_excluded(name); 2319 #endif 2320 #ifdef SOLARIS_ETC_FTPUSERS 2321 if (etc_ftpusers) 2322 syslog(LOG_NOTICE, "%s is deprecated, use %s instead", _path_ftpusers, _PATH_FTPUSERS); 2323 #endif 2324 return (1); 2325 } 2326 } 2327 (void) fclose(fd); 2328 } 2329 #ifdef SOLARIS_ETC_FTPUSERS 2330 if (!etc_ftpusers && (strcmp(_path_ftpusers, _PATH_FTPUSERS) == 0)) { 2331 strcpy(_path_ftpusers, "/etc/ftpusers"); 2332 etc_ftpusers = 1; 2333 goto retry; 2334 } 2335 #endif 2336 return (0); 2337 } 2338 2339 int uid_match(char *keyword, uid_t uid) 2340 { 2341 struct aclmember *entry = NULL; 2342 int which; 2343 char *ptr; 2344 struct passwd *pw; 2345 2346 /* 2347 * keyword <uid-range> [<uid-range> ...] 2348 * 2349 * uid-range may be a username or begin with '%' and be treated as numeric: 2350 * %<uid> A single numeric UID 2351 * %<uid>+ All UIDs greater or equal to UID 2352 * %<uid>- All UIDs greater or equal to UID 2353 * %-<uid> All UIDs less or equal to UID 2354 * %<uid>-<uid> All UIDs between the two (inclusive) 2355 * * All UIDs 2356 */ 2357 while (getaclentry(keyword, &entry)) { 2358 for (which = 0; (which < MAXARGS) && ARG[which]; which++) { 2359 if (!strcmp(ARG[which], "*")) 2360 return (1); 2361 if (ARG[which][0] == '%') { 2362 if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) { 2363 if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) { 2364 if (uid == strtoul(ARG[which] + 1, NULL, 0)) 2365 return (1); 2366 } 2367 else { 2368 *ptr++ = '\0'; 2369 if ((ARG[which][1] == '\0') 2370 || (uid >= strtoul(ARG[which] + 1, NULL, 0))) { 2371 *--ptr = '+'; 2372 return (1); 2373 } 2374 *--ptr = '+'; 2375 } 2376 } 2377 else { 2378 *ptr++ = '\0'; 2379 if (((ARG[which][1] == '\0') 2380 || (uid >= strtoul(ARG[which] + 1, NULL, 0))) 2381 && ((*ptr == '\0') 2382 || (uid <= strtoul(ptr, NULL, 0)))) { 2383 *--ptr = '-'; 2384 return (1); 2385 } 2386 *--ptr = '-'; 2387 } 2388 } 2389 else { 2390 #ifdef OTHER_PASSWD 2391 pw = bero_getpwnam(ARG[which], _path_passwd); 2392 #else 2393 pw = getpwnam(ARG[which]); 2394 #endif 2395 if (pw && (uid == pw->pw_uid)) 2396 return (1); 2397 } 2398 } 2399 } 2400 return (0); 2401 } 2402 2403 int gid_match(char *keyword, gid_t gid, char *username) 2404 { 2405 struct aclmember *entry = NULL; 2406 int which; 2407 char *ptr; 2408 struct group *grp; 2409 char **member; 2410 2411 /* 2412 * keyword <gid-range> [<gid-range> ...] 2413 * 2414 * gid-range may be a groupname or begin with '%' and be treated as numeric: 2415 * %<gid> A single GID 2416 * %<gid>+ All GIDs greater or equal to GID 2417 * %<gid>- All GIDs greater or equal to GID 2418 * %-<gid> All GIDs less or equal to GID 2419 * %<gid>-<gid> All GIDs between the two (inclusive) 2420 * * All GIDs 2421 */ 2422 while (getaclentry(keyword, &entry)) { 2423 for (which = 0; (which < MAXARGS) && ARG[which]; which++) { 2424 if (!strcmp(ARG[which], "*")) 2425 return (1); 2426 if (ARG[which][0] == '%') { 2427 if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) { 2428 if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) { 2429 if (gid == strtoul(ARG[which] + 1, NULL, 0)) 2430 return (1); 2431 } 2432 else { 2433 *ptr++ = '\0'; 2434 if ((ARG[which][1] == '\0') 2435 || (gid >= strtoul(ARG[which] + 1, NULL, 0))) { 2436 *--ptr = '+'; 2437 return (1); 2438 } 2439 *--ptr = '+'; 2440 } 2441 } 2442 else { 2443 *ptr++ = '\0'; 2444 if (((ARG[which][1] == '\0') 2445 || (gid >= strtoul(ARG[which] + 1, NULL, 0))) 2446 && ((*ptr == '\0') 2447 || (gid <= strtoul(ptr, NULL, 0)))) { 2448 *--ptr = '-'; 2449 return (1); 2450 } 2451 *--ptr = '-'; 2452 } 2453 } 2454 else { 2455 if ((grp = getgrnam(ARG[which]))) { 2456 if (gid == grp->gr_gid) 2457 return (1); 2458 if (username) { 2459 for (member = grp->gr_mem; *member; member++) 2460 if (!strcasecmp(*member, username)) 2461 return (1); 2462 } 2463 } 2464 } 2465 } 2466 } 2467 return (0); 2468 } 2469 2470 int denieduid(uid_t uid) 2471 { 2472 return uid_match("deny-uid", uid); 2473 } 2474 2475 int alloweduid(uid_t uid) 2476 { 2477 return uid_match("allow-uid", uid); 2478 } 2479 2480 int deniedgid(gid_t gid) 2481 { 2482 return gid_match("deny-gid", gid, NULL); 2483 } 2484 2485 int allowedgid(gid_t gid) 2486 { 2487 return gid_match("allow-gid", gid, NULL); 2488 } 2489 2490 /* Terminate login as previous user, if any, resetting state; used when USER 2491 * command is given or login fails. */ 2492 2493 void end_login(void) 2494 { 2495 delay_signaling(); /* we can't allow any signals while euid==0: kinch */ 2496 (void) seteuid((uid_t) 0); 2497 if (logged_in) { 2498 if (wtmp_logging) 2499 wu_logwtmp(ttyline, pw->pw_name, remotehost, 0); 2500 #ifdef USE_PAM 2501 if (!anonymous && pamh) { 2502 (void) pam_close_session(pamh, 0); 2503 (void) pam_end(pamh, PAM_SUCCESS); 2504 pamh = (pam_handle_t *)0; 2505 } 2506 #endif 2507 } 2508 pw = NULL; 2509 #ifdef AFS_AUTH 2510 ktc_ForgetAllTokens(); 2511 #endif 2512 logged_in = 0; 2513 anonymous = 0; 2514 guest = 0; 2515 } 2516 2517 int validate_eaddr(char *eaddr) 2518 { 2519 int i, host, state; 2520 2521 for (i = host = state = 0; eaddr[i] != '\0'; i++) { 2522 switch (eaddr[i]) { 2523 case '.': 2524 if (!host) 2525 return 0; 2526 if (state == 2) 2527 state = 3; 2528 host = 0; 2529 break; 2530 case '@': 2531 if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host)) 2532 return 0; 2533 state = 2; 2534 host = 0; 2535 break; 2536 case '!': 2537 case '%': 2538 if (!host || state > 1) 2539 return 0; 2540 state = 1; 2541 host = 0; 2542 break; 2543 case '-': 2544 break; 2545 default: 2546 host++; 2547 } 2548 } 2549 if (((state == 3) && host > 1) || ((state == 1) && host > 1)) 2550 return 1; 2551 else 2552 return 0; 2553 } 2554 2555 2556 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 2557 static int AllowVirtualUser(const char *username) 2558 { 2559 struct aclmember *entry = NULL; 2560 int which; 2561 2562 while (getaclentry("virtual", &entry)) 2563 if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname) 2564 && ARG1 && !strcasecmp(ARG1, "allow")) 2565 for (which = 2; (which < MAXARGS) && ARG[which]; which++) 2566 if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) 2567 return (1); 2568 return (0); 2569 } 2570 2571 static int DenyVirtualUser(const char *username) 2572 { 2573 struct aclmember *entry = NULL; 2574 int which; 2575 2576 while (getaclentry("virtual", &entry)) 2577 if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname) 2578 && ARG1 && !strcasecmp(ARG1, "deny")) 2579 for (which = 2; (which < MAXARGS) && ARG[which]; which++) 2580 if (!strcasecmp(username, ARG[which]) || !strcmp("*", ARG[which])) 2581 return (1); 2582 return (0); 2583 } 2584 2585 static int DenyVirtualAnonymous(void) 2586 { 2587 struct aclmember *entry = NULL; 2588 2589 while (getaclentry("virtual", &entry)) 2590 if (ARG0 && hostmatch(ARG0, virtual_address, virtual_hostname) 2591 && ARG1 && !strcasecmp(ARG1, "private")) 2592 return (1); 2593 return (0); 2594 } 2595 #endif 2596 2597 void pass(char *passwd) 2598 { 2599 2600 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) 2601 char *xpasswd, *salt; 2602 #endif 2603 2604 int passwarn = 0; 2605 int rval = 1; 2606 int success_code = 230; 2607 int cos; 2608 2609 #ifdef SECUREOSF 2610 struct pr_passwd *pr; 2611 int crypt_alg = 0; 2612 #endif 2613 2614 #ifdef BSD_AUTH 2615 extern int ext_auth; 2616 extern char *check_auth(); 2617 #endif 2618 2619 #ifdef ULTRIX_AUTH 2620 int numfails; 2621 #endif /* ULTRIX_AUTH */ 2622 2623 #ifdef HAS_PW_EXPIRE 2624 int set_expired = FALSE; 2625 #endif 2626 2627 #ifdef AFS_AUTH 2628 char *reason; 2629 #endif /* AFS_AUTH */ 2630 2631 #ifdef DCE_AUTH 2632 sec_passwd_rec_t pwr; 2633 sec_login_handle_t lhdl; 2634 boolean32 rstpwd; 2635 sec_login_auth_src_t asrc; 2636 error_status_t status; 2637 #endif /* DCE_AUTH */ 2638 2639 #if defined(USE_GSS) 2640 /* 2641 * LOGIC: 2642 * If [ the user presented GSSAPI creds and was authorized ] 2643 * jump down past the password validation code. 2644 */ 2645 if (GSSUSERAUTH_OK(gss_info) && logged_in) { 2646 /* 2647 * We could reply(202, "PASS command superfluous.") here, but 2648 * allow this for compat with some clients. 2649 */ 2650 success_code = 232; 2651 goto pwd_validation_done; 2652 } 2653 #endif /* defined(USE_GSS) */ 2654 2655 if (logged_in || askpasswd == 0) { 2656 #ifdef VERBOSE_ERROR_LOGING 2657 syslog(LOG_NOTICE, "FTP LOGIN REFUSED (PASS before USER) FROM %s", 2658 remoteident); 2659 #endif 2660 reply(503, "Login with USER first."); 2661 return; 2662 } 2663 askpasswd = 0; 2664 2665 /* Disable lreply() if the first character of the password is '-' since 2666 * some hosts don't understand continuation messages and hang... */ 2667 2668 if (*passwd == '-') 2669 dolreplies = 0; 2670 else 2671 dolreplies = 1; 2672 /* ******** REGULAR/GUEST USER PASSWORD PROCESSING ********** */ 2673 if (!anonymous) { /* "ftp" is only account allowed no password */ 2674 #ifndef HELP_CRACKERS 2675 if (DenyLoginAfterPassword) { 2676 pr_mesg(530, DelayedMessageFile); 2677 reply(530, "Login incorrect."); 2678 #ifdef SOLARIS_BSM_AUDIT 2679 audit_ftpd_failure(the_user); 2680 #endif 2681 acl_remove(); 2682 pw = NULL; 2683 if (++login_attempts >= lgi_failure_threshold) { 2684 syslog(LOG_NOTICE, "repeated login failures from %s", 2685 remoteident); 2686 exit(0); 2687 } 2688 return; 2689 } 2690 #endif 2691 if (*passwd == '-') 2692 passwd++; 2693 #ifdef USE_PAM 2694 #ifdef OTHER_PASSWD 2695 if (use_pam 2696 #if defined(USE_GSS) 2697 && !GSSUSERAUTH_OK(gss_info) 2698 #endif 2699 ) { 2700 #endif 2701 /* PAM authentication 2702 * If PAM authenticates a user we know nothing about on the local 2703 * system, use the generic guest account credentials. We should make 2704 * this somehow a configurable item somewhere; later more on that. 2705 * 2706 * For now assume the guest (not anonymous) identity, so the site 2707 * admins can still differentiate between the truw anonymous user and 2708 * a little bit more special ones. Otherwise he wouldn't go the extra 2709 * mile to have a different user database, right? 2710 * --gaftonc */ 2711 if (pam_check_pass(the_user, passwd)) { 2712 rval = 0; 2713 if (pw == NULL) { 2714 /* assume guest account identity */ 2715 pw = sgetpwnam("ftp"); 2716 anonymous = 0; 2717 guest = 1; 2718 /* even go as far as... */ 2719 if (pw != NULL && pw->pw_name != NULL) { 2720 free(pw->pw_name); 2721 pw->pw_name = sgetsave(the_user); 2722 } 2723 } 2724 } 2725 #ifdef OTHER_PASSWD 2726 } else { 2727 #endif 2728 #endif /* USE_PAM */ 2729 #if !defined(USE_PAM) || (defined(USE_PAM) && defined(OTHER_PASSWD)) 2730 #ifdef BSD_AUTH 2731 if (ext_auth) { 2732 if ((salt = check_auth(the_user, passwd))) { 2733 reply(530, "%s", salt); 2734 #ifdef LOG_FAILED /* 27-Apr-93 EHK/BM */ 2735 /* 2736 * To avoid logging passwords mistakenly entered as 2737 * usernames, only log the names of users which exist. 2738 */ 2739 syslog(LOG_INFO, "failed login from %s, %s", remoteident, 2740 (pw == NULL) ? "[unknown]" : the_user); 2741 #endif /* LOG_FAILED */ 2742 acl_remove(); 2743 pw = NULL; 2744 if (++login_attempts >= lgi_failure_threshold) { 2745 syslog(LOG_NOTICE, "repeated login failures from %s", 2746 remoteident); 2747 exit(0); 2748 } 2749 return; 2750 } 2751 } 2752 else { 2753 #endif /* BSD_AUTH */ 2754 *guestpw = '\0'; 2755 if (pw == NULL) 2756 salt = "xx"; 2757 else 2758 #ifndef OPIE 2759 salt = pw->pw_passwd; 2760 #ifdef SECUREOSF 2761 if ((pr = getprpwnam(pw->pw_name)) != NULL) { 2762 if (pr->uflg.fg_newcrypt) 2763 crypt_alg = pr->ufld.fd_newcrypt; 2764 else if (pr->sflg.fg_newcrypt) 2765 crypt_alg = pr->sfld.fd_newcrypt; 2766 else 2767 crypt_alg = 0; 2768 } 2769 else 2770 crypt_alg = 0; 2771 2772 xpasswd = dispcrypt(passwd, salt, crypt_alg); 2773 #elif defined(SecureWare) || defined(HPUX_10_TRUSTED) 2774 xpasswd = bigcrypt(passwd, salt); 2775 #elif defined(KERBEROS) 2776 xpasswd = crypt16(passwd, salt); 2777 #elif defined(SKEY) 2778 #ifndef __NetBSD__ 2779 xpasswd = skey_crypt(passwd, salt, pw, pwok); 2780 pwok = 0; 2781 #else 2782 if ((pw != NULL) && (pw->pw_name != NULL) && skey_haskey(pw->pw_name) == 0 && 2783 skey_passcheck(pw->pw_name, passwd) != -1) 2784 xpasswd = pw->pw_passwd; 2785 else 2786 xpasswd = crypt(passwd, salt); 2787 #endif 2788 #else /* !SKEY */ 2789 xpasswd = crypt(passwd, salt); 2790 #endif /* SKEY */ 2791 #else /* OPIE */ 2792 if (!opieverify(&opiestate, passwd)) 2793 rval = 0; 2794 xpasswd = crypt(passwd, pw->pw_passwd); 2795 #endif /* OPIE */ 2796 #ifdef ULTRIX_AUTH 2797 if ((numfails = ultrix_check_pass(passwd, xpasswd)) >= 0) { 2798 #else 2799 if (pw != NULL) { 2800 #ifdef AFS_AUTH 2801 if (strcmp(pw->pw_passwd, "X") == 0) 2802 if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION | KA_USERAUTH_DOSETPAG, pw->pw_name, "", 0, passwd, 0, 0, 0, &reason) == 0) 2803 rval = 0; 2804 else 2805 printf("230-AFS: %s", reason); 2806 else 2807 #endif /* AFS_AUTH */ 2808 /* The strcmp does not catch null passwords! */ 2809 #ifdef HAS_PW_EXPIRE 2810 if(pw->pw_expire != NULL) { 2811 if(pw->pw_expire && time(NULL) >= pw->pw_expire) { 2812 set_expired = TRUE; 2813 } 2814 } 2815 #endif 2816 2817 if (*pw->pw_passwd != '\0' && 2818 #ifdef HAS_PW_EXPIRE 2819 !set_expired && 2820 #endif 2821 strcmp(xpasswd, pw->pw_passwd) == 0) { 2822 #endif 2823 rval = 0; 2824 } 2825 #ifdef DCE_AUTH 2826 #ifndef ALWAYS_TRY_DCE 2827 else 2828 #endif /* ALWAYS_TRY_DCE */ 2829 { 2830 sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, sec_login_no_flags, &lhdl, &status); 2831 if (status == error_status_ok) { 2832 printf("230-sec_login_setup_identity OK\n"); 2833 pwr.key.tagged_union.plain = (idl_char *) passwd; 2834 pwr.key.key_type = sec_passwd_plain; 2835 pwr.pepper = 0; 2836 pwr.version_number = sec_passwd_c_version_none; 2837 /* validate password with login context */ 2838 sec_login_valid_and_cert_ident(lhdl, &pwr, &rstpwd, &asrc, &status); 2839 if (!rstpwd && (asrc == sec_login_auth_src_network) && (status == error_status_ok)) { 2840 printf("230-sec_login_valid_and_cert_ident OK\n"); 2841 sec_login_set_context(lhdl, &status); 2842 printf("230-sec_login_set_context finished\n"); 2843 if (status != error_status_ok) { 2844 int pstatus; 2845 dce_error_string_t s; 2846 printf("230-Error status: %d:\n", status); 2847 dce_error_inq_text(status, s, &pstatus); 2848 printf("230-%s\n", s); 2849 fflush(stderr); 2850 sec_login_purge_context(lhdl, &status); 2851 } 2852 else { 2853 /*sec_login_get_pwent(lhdl, &pw, &status); */ 2854 rval = 0; 2855 } 2856 } 2857 } 2858 } 2859 #endif /* DCE_AUTH */ 2860 } 2861 #ifdef USE_PAM 2862 } 2863 #endif 2864 #endif /* !USE_PAM || (USE_PAM && OTHER_PASSWD) */ 2865 if (rval) { 2866 reply(530, "Login incorrect."); 2867 2868 #ifdef LOG_FAILED /* 27-Apr-93 EHK/BM */ 2869 /* H* add-on: yell about attempts to use the trojan. This may alarm you 2870 if you're "stringsing" the binary and you see "NULL" pop out in just 2871 about the same place as it would have in 2.2c! */ 2872 if (!strcasecmp(passwd, "NULL")) 2873 syslog(LOG_NOTICE, "REFUSED \"NULL\" from %s, %s", 2874 remoteident, the_user); 2875 else { 2876 /* 2877 * To avoid logging passwords mistakenly entered as 2878 * usernames, only log the names of users which exist. 2879 */ 2880 syslog(LOG_INFO, "failed login from %s, %s", remoteident, 2881 (pw == NULL) ? "[unknown]" : the_user); 2882 } 2883 #endif 2884 #ifdef SOLARIS_BSM_AUDIT 2885 audit_ftpd_failure(the_user); 2886 #endif 2887 acl_remove(); 2888 2889 pw = NULL; 2890 if (++login_attempts >= lgi_failure_threshold) { 2891 syslog(LOG_NOTICE, "repeated login failures from %s", 2892 remoteident); 2893 exit(0); 2894 } 2895 return; 2896 } 2897 #ifdef BSD_AUTH 2898 } 2899 #endif 2900 /* ANONYMOUS USER PROCESSING STARTS HERE */ 2901 } 2902 else { 2903 char *pwin, *pwout = guestpw; 2904 struct aclmember *entry = NULL; 2905 int valid; 2906 int enforce = 0; 2907 2908 if (getaclentry("passwd-check", &entry) && 2909 ARG0 && strcasecmp(ARG0, "none")) { 2910 2911 if (!strcasecmp(ARG0, "rfc822")) 2912 valid = validate_eaddr(passwd); 2913 else if (!strcasecmp(ARG0, "trivial")) 2914 valid = (strchr(passwd, '@') == NULL) ? 0 : 1; 2915 else 2916 valid = 1; 2917 if (ARG1 && !strcasecmp(ARG1, "enforce")) 2918 enforce = 1; 2919 /* Block off "default" responses like mozilla@ and IE30User@ 2920 * (at the administrator's discretion). --AC 2921 */ 2922 entry = NULL; 2923 while (getaclentry("deny-email", &entry)) { 2924 if (ARG0 2925 && ((strcasecmp(passwd, ARG0) == 0) 2926 || regexmatch(passwd, ARG0) 2927 || ((*passwd == '-') 2928 && ((strcasecmp(passwd + 1, ARG0) == 0) 2929 || regexmatch(passwd + 1, ARG0))))) { 2930 valid = 0; 2931 break; 2932 } 2933 } 2934 if (!valid && enforce) { 2935 lreply(530, "The response '%s' is not valid", passwd); 2936 lreply(530, "Please use your e-mail address as your password"); 2937 lreply(530, " for example: %s@%s%s", 2938 authenticated ? authuser : "joe", remotehost, 2939 strchr(remotehost, '.') ? "" : ".network"); 2940 reply(530, "Login incorrect."); 2941 #ifdef VERBOSE_ERROR_LOGING 2942 syslog(LOG_NOTICE, "FTP ACCESS REFUSED (anonymous password not rfc822) from %s", 2943 remoteident); 2944 #endif 2945 #ifdef SOLARIS_BSM_AUDIT 2946 audit_ftpd_bad_pw(the_user); 2947 #endif 2948 acl_remove(); 2949 if (++login_attempts >= lgi_failure_threshold) { 2950 syslog(LOG_NOTICE, "repeated login failures from %s", 2951 remoteident); 2952 exit(0); 2953 } 2954 return; 2955 } 2956 else if (!valid) 2957 passwarn = 1; 2958 } 2959 if (!*passwd) { 2960 strcpy(guestpw, "[none_given]"); 2961 } 2962 else { 2963 int cnt = sizeof(guestpw) - 2; 2964 2965 for (pwin = passwd; *pwin && cnt--; pwin++) 2966 if (!isgraph(*pwin)) 2967 *pwout++ = '_'; 2968 else 2969 *pwout++ = *pwin; 2970 } 2971 #ifndef HELP_CRACKERS 2972 if (DenyLoginAfterPassword) { 2973 pr_mesg(530, DelayedMessageFile); 2974 reply(530, "Login incorrect."); 2975 #ifdef SOLARIS_BSM_AUDIT 2976 audit_ftpd_failure(the_user); 2977 #endif 2978 acl_remove(); 2979 pw = NULL; 2980 if (++login_attempts >= lgi_failure_threshold) { 2981 syslog(LOG_NOTICE, "repeated login failures from %s", 2982 remoteident); 2983 exit(0); 2984 } 2985 return; 2986 } 2987 #endif 2988 } 2989 2990 #if defined(USE_GSS) 2991 pwd_validation_done: 2992 #endif /* USE_GSS */ 2993 /* if logging is enabled, open logfile before chroot or set group ID */ 2994 if ((log_outbound_xfers || log_incoming_xfers) && (syslogmsg != 1)) { 2995 mode_t oldmask; 2996 oldmask = umask(0); 2997 xferlog = open(logfile, O_WRONLY | O_APPEND | O_CREAT, 0640); 2998 (void) umask(oldmask); 2999 if (xferlog < 0) { 3000 syslog(LOG_ERR, "cannot open logfile %s: %s", logfile, 3001 strerror(errno)); 3002 xferlog = 0; 3003 } 3004 } 3005 3006 #ifdef DEBUG 3007 /* I had a lot of trouble getting xferlog working, because of two factors: 3008 acl_setfunctions making stupid assumptions, and sprintf LOSING. _H */ 3009 /* 3010 * Actually, sprintf was not losing, but the rules changed... next release 3011 * this will be fixed the correct way, but right now, it works well enough 3012 * -- sob 3013 */ 3014 syslog(LOG_INFO, "-i %d,-o %d,xferlog %s: %d", 3015 log_incoming_xfers, log_outbound_xfers, logfile, xferlog); 3016 #endif 3017 enable_signaling(); /* we can allow signals once again: kinch */ 3018 /* if autogroup command applies to user's class change pw->pw_gid */ 3019 if (anonymous && use_accessfile) { /* see above. _H */ 3020 (void) acl_autogroup(pw); 3021 guest = acl_guestgroup(pw); /* the new group may be a guest */ 3022 if (guest && acl_realgroup(pw)) 3023 guest = 0; 3024 anonymous = !guest; 3025 } 3026 /* END AUTHENTICATION */ 3027 3028 /* SET GROUP ID STARTS HERE */ 3029 #ifndef AIX 3030 (void) setegid((gid_t) pw->pw_gid); 3031 #else 3032 (void) setgid((gid_t) pw->pw_gid); 3033 #endif 3034 (void) initgroups(pw->pw_name, pw->pw_gid); 3035 #ifdef DEBUG 3036 syslog(LOG_DEBUG, "initgroups has been called"); 3037 #endif 3038 /* WTMP PROCESSING STARTS HERE */ 3039 if (wtmp_logging) { 3040 /* open wtmp before chroot */ 3041 #if ((defined(BSD) && (BSD >= 199103)) || defined(sun)) 3042 (void) sprintf(ttyline, "ftp%ld", (long) getpid()); 3043 #else 3044 (void) sprintf(ttyline, "ftpd%d", getpid()); 3045 #endif 3046 #ifdef DEBUG 3047 syslog(LOG_DEBUG, "about to call wtmp"); 3048 #endif 3049 wu_logwtmp(ttyline, pw->pw_name, remotehost, 1); 3050 } 3051 logged_in = 1; 3052 3053 expand_id(); 3054 3055 #ifdef QUOTA 3056 memset("a, 0, sizeof(quota)); 3057 get_quota(pw->pw_dir, pw->pw_uid); 3058 #endif 3059 3060 restricted_user = 0; 3061 if (!anonymous) 3062 if ((restricteduid(pw->pw_uid) && !unrestricteduid(pw->pw_uid)) 3063 || (restrictedgid(pw->pw_gid) && !unrestrictedgid(pw->pw_gid))) 3064 restricted_user = 1; 3065 if (anonymous || guest) { 3066 char *sp; 3067 /* We MUST do a chdir() after the chroot. Otherwise the old current 3068 * directory will be accessible as "." outside the new root! */ 3069 #ifdef ALTERNATE_CD 3070 home = defhome; 3071 #endif 3072 #ifdef VIRTUAL 3073 if (virtual_mode && !guest) { 3074 #ifdef CLOSED_VIRTUAL_SERVER 3075 if (DenyVirtualAnonymous()) { 3076 #ifdef VERBOSE_ERROR_LOGING 3077 syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host anonymous access denied) for %s", 3078 remoteident); 3079 #endif 3080 reply(530, "Login incorrect."); 3081 if (++login_attempts >= lgi_failure_threshold) { 3082 syslog(LOG_NOTICE, "repeated login failures from %s", remoteident); 3083 dologout(0); 3084 } 3085 goto bad; 3086 } 3087 #endif 3088 /* Anonymous user in virtual_mode */ 3089 if (pw->pw_dir) 3090 free(pw->pw_dir); 3091 pw->pw_dir = sgetsave(virtual_root); 3092 } 3093 else 3094 #endif 3095 3096 /* 3097 * New chroot logic. 3098 * 3099 * If VIRTUAL is supported, the chroot for anonymous users on the 3100 * virtual host has already been determined. Otherwise the logic 3101 * below applies: 3102 * 3103 * If this is an anonymous user, the chroot directory is determined 3104 * by the "anonymous-root" clause and the home directory is taken 3105 * from the etc/passwd file found after chroot'ing. 3106 * 3107 * If this a guest user, the chroot directory is determined by the 3108 * "guest-root" clause and the home directory is taken from the 3109 * etc/passwd file found after chroot'ing. 3110 * 3111 * The effect of this logic is that the entire chroot environment 3112 * is under the control of the ftpaccess file and the supporting 3113 * files in the ftp environment. The system-wide passwd file is 3114 * used only to authenticate the user. 3115 */ 3116 3117 { 3118 struct aclmember *entry = NULL; 3119 char *root_path = NULL; 3120 3121 if (anonymous) { 3122 char class[BUFSIZ]; 3123 3124 (void) acl_getclass(class); 3125 while (getaclentry("anonymous-root", &entry) && ARG0) { 3126 if (!ARG1) { 3127 if (!root_path) 3128 root_path = ARG0; 3129 } 3130 else { 3131 int which; 3132 3133 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 3134 if (!strcmp(ARG[which], "*")) { 3135 if (!root_path) 3136 root_path = ARG0; 3137 } 3138 else { 3139 if (!strcasecmp(ARG[which], class)) 3140 root_path = ARG0; 3141 } 3142 } 3143 } 3144 } 3145 } 3146 else { /* (guest) */ 3147 while (getaclentry("guest-root", &entry) && ARG0) { 3148 if (!ARG1) { 3149 if (!root_path) 3150 root_path = ARG0; 3151 } 3152 else { 3153 int which; 3154 char *ptr; 3155 3156 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 3157 if (!strcmp(ARG[which], "*")) { 3158 if (!root_path) 3159 root_path = ARG0; 3160 } 3161 else { 3162 if (ARG[which][0] == '%') { 3163 if ((ptr = strchr(ARG[which] + 1, '-')) == NULL) { 3164 if ((ptr = strchr(ARG[which] + 1, '+')) == NULL) { 3165 if (pw->pw_uid == strtoul(ARG[which] + 1, NULL, 0)) 3166 root_path = ARG0; 3167 } 3168 else { 3169 *ptr++ = '\0'; 3170 if ((ARG[which][1] == '\0') 3171 || (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0))) 3172 root_path = ARG0; 3173 *--ptr = '+'; 3174 } 3175 } 3176 else { 3177 *ptr++ = '\0'; 3178 if (((ARG[which][1] == '\0') 3179 || (pw->pw_uid >= strtoul(ARG[which] + 1, NULL, 0))) 3180 && ((*ptr == '\0') 3181 || (pw->pw_uid <= strtoul(ptr, NULL, 0)))) 3182 root_path = ARG0; 3183 *--ptr = '-'; 3184 } 3185 } 3186 else { 3187 #ifdef OTHER_PASSWD 3188 struct passwd *guest_pw = bero_getpwnam(ARG[which], _path_passwd); 3189 #else 3190 struct passwd *guest_pw = getpwnam(ARG[which]); 3191 #endif 3192 if (guest_pw && (pw->pw_uid == guest_pw->pw_uid)) 3193 root_path = ARG0; 3194 } 3195 } 3196 } 3197 } 3198 } 3199 } 3200 3201 if (root_path) { 3202 struct passwd *chroot_pw = NULL; 3203 3204 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 3205 if (virtual_mode && strcmp(root_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) { 3206 #ifdef VERBOSE_ERROR_LOGING 3207 syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s", 3208 remoteident, pw->pw_name); 3209 #endif 3210 reply(530, "Login incorrect."); 3211 if (++login_attempts >= lgi_failure_threshold) { 3212 syslog(LOG_NOTICE, "repeated login failures from %s", remoteident); 3213 dologout(0); 3214 } 3215 goto bad; 3216 } 3217 #endif 3218 (void) strncpy(chroot_path, root_path, sizeof(chroot_path)); 3219 chroot_path[sizeof(chroot_path) - 1] = '\0'; 3220 if (pw->pw_dir) 3221 free(pw->pw_dir); 3222 pw->pw_dir = sgetsave(chroot_path); 3223 #if defined(SOLARIS_2) 3224 cleanup_nscd(); 3225 #endif 3226 if (chroot(root_path) < 0 || chdir("/") < 0) { 3227 #ifdef VERBOSE_ERROR_LOGING 3228 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s", 3229 remoteident, pw->pw_name); 3230 #endif 3231 reply(530, "Can't set guest privileges."); 3232 goto bad; 3233 } 3234 #ifdef OTHER_PASSWD 3235 if ((chroot_pw = bero_getpwuid(pw->pw_uid, _path_passwd)) != NULL) 3236 #else 3237 if ((chroot_pw = getpwuid(pw->pw_uid)) != NULL) 3238 #endif 3239 if (chdir(chroot_pw->pw_dir) >= 0) 3240 home = sgetsave(chroot_pw->pw_dir); 3241 goto slimy_hack; /* onea these days I'll make this structured code, honest ... */ 3242 } 3243 } 3244 3245 /* determine root and home directory */ 3246 3247 if ((sp = strstr(pw->pw_dir, "/./")) == NULL) { 3248 (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path)); 3249 chroot_path[sizeof(chroot_path) - 1] = '\0'; 3250 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 3251 if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) { 3252 #ifdef VERBOSE_ERROR_LOGING 3253 syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s", 3254 remoteident, pw->pw_name); 3255 #endif 3256 reply(530, "Login incorrect."); 3257 if (++login_attempts >= lgi_failure_threshold) { 3258 syslog(LOG_NOTICE, "repeated login failures from %s", remoteident); 3259 dologout(0); 3260 } 3261 goto bad; 3262 } 3263 #endif 3264 #if defined(SOLARIS_2) 3265 cleanup_nscd(); 3266 #endif 3267 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { 3268 #ifdef VERBOSE_ERROR_LOGING 3269 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s", 3270 remoteident, pw->pw_name); 3271 #endif 3272 reply(530, "Can't set guest privileges."); 3273 goto bad; 3274 } 3275 } 3276 else { 3277 *sp++ = '\0'; 3278 (void) strncpy(chroot_path, pw->pw_dir, sizeof(chroot_path)); 3279 chroot_path[sizeof(chroot_path) - 1] = '\0'; 3280 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 3281 if (virtual_mode && strcmp(chroot_path, virtual_root) && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) { 3282 #ifdef VERBOSE_ERROR_LOGING 3283 syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s", 3284 remoteident, pw->pw_name); 3285 #endif 3286 reply(530, "Login incorrect."); 3287 if (++login_attempts >= lgi_failure_threshold) { 3288 syslog(LOG_NOTICE, "repeated login failures from %s", remoteident); 3289 dologout(0); 3290 } 3291 goto bad; 3292 } 3293 #endif 3294 #if defined(SOLARIS_2) 3295 cleanup_nscd(); 3296 #endif 3297 if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) { 3298 #ifdef VERBOSE_ERROR_LOGING 3299 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set guest privileges) for %s, %s", 3300 remoteident, pw->pw_name); 3301 #endif 3302 reply(550, "Can't set guest privileges."); 3303 goto bad; 3304 } 3305 #ifdef ALTERNATE_CD 3306 home = sp; 3307 #endif 3308 } 3309 slimy_hack: 3310 /* shut up you stupid compiler! */ { 3311 int i = 0; 3312 i++; 3313 } 3314 } 3315 #if defined(VIRTUAL) && defined(CLOSED_VIRTUAL_SERVER) 3316 else if (virtual_mode && !(AllowVirtualUser(pw->pw_name) && !DenyVirtualUser(pw->pw_name))) { 3317 #ifdef VERBOSE_ERROR_LOGING 3318 syslog(LOG_NOTICE, "FTP LOGIN FAILED (virtual host access denied) for %s, %s", 3319 remoteident, pw->pw_name); 3320 #endif 3321 reply(530, "Login incorrect."); 3322 if (++login_attempts >= lgi_failure_threshold) { 3323 syslog(LOG_NOTICE, "repeated login failures from %s", remoteident); 3324 dologout(0); 3325 } 3326 goto bad; 3327 } 3328 #endif 3329 #ifdef AIX 3330 { 3331 /* AIX 3 lossage. Don't ask. It's undocumented. */ 3332 priv_t priv; 3333 3334 priv.pv_priv[0] = 0; 3335 priv.pv_priv[1] = 0; 3336 /* setgroups(NULL, NULL); */ 3337 if (setpriv(PRIV_SET | PRIV_INHERITED | PRIV_EFFECTIVE | PRIV_BEQUEATH, 3338 &priv, sizeof(priv_t)) < 0 || 3339 setuidx(ID_REAL | ID_EFFECTIVE, (uid_t) pw->pw_uid) < 0 || 3340 seteuid((uid_t) pw->pw_uid) < 0) { 3341 #ifdef VERBOSE_ERROR_LOGING 3342 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s", 3343 remoteident, pw->pw_name); 3344 #endif 3345 reply(530, "Can't set uid (AIX3)."); 3346 goto bad; 3347 } 3348 } 3349 #ifdef UID_DEBUG 3350 lreply(success_code, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL), 3351 getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN)); 3352 lreply(success_code, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL), 3353 getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN)); 3354 #endif 3355 #else /* AIX */ 3356 #ifdef HAVE_SETREUID 3357 if (setreuid(-1, (uid_t) pw->pw_uid) < 0) { 3358 #else 3359 if (seteuid((uid_t) pw->pw_uid) < 0) { 3360 #endif 3361 #ifdef VERBOSE_ERROR_LOGING 3362 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot set uid) for %s, %s", 3363 remoteident, pw->pw_name); 3364 #endif 3365 reply(530, "Can't set uid."); 3366 goto bad; 3367 } 3368 #endif /* AIX */ 3369 if (!anonymous && !guest) { 3370 if (chdir(pw->pw_dir) < 0) { 3371 #ifdef PARANOID 3372 #ifdef VERBOSE_ERROR_LOGING 3373 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s", 3374 remoteident, pw->pw_name); 3375 #endif 3376 reply(530, "User %s: can't change directory to %s.", 3377 pw->pw_name, pw->pw_dir); 3378 goto bad; 3379 #else /* PARANOID */ 3380 if (restricted_user || chdir("/") < 0) { 3381 #ifdef VERBOSE_ERROR_LOGING 3382 syslog(LOG_NOTICE, "FTP LOGIN FAILED (cannot chdir) for %s, %s", 3383 remoteident, pw->pw_name); 3384 #endif 3385 reply(530, "User %s: can't change directory to %s.", 3386 pw->pw_name, pw->pw_dir); 3387 goto bad; 3388 } 3389 else { 3390 lreply(success_code, "No directory! Logging in with home=/"); 3391 #ifdef ALTERNATE_CD 3392 home = defhome; 3393 #endif 3394 } 3395 #endif /* PARANOID */ 3396 } 3397 } 3398 3399 if (passwarn) { 3400 lreply(success_code, "The response '%s' is not valid", passwd); 3401 lreply(success_code, 3402 "Next time please use your e-mail address as your password"); 3403 lreply(success_code, " for example: %s@%s%s", 3404 authenticated ? authuser : "joe", remotehost, 3405 strchr(remotehost, '.') ? "" : ".network"); 3406 } 3407 3408 login_attempts = 0; /* this time successful */ 3409 3410 /* following two lines were inside the next scope... */ 3411 3412 show_message(success_code, LOG_IN); 3413 show_message(success_code, C_WD); 3414 show_readme(success_code, LOG_IN); 3415 show_readme(success_code, C_WD); 3416 3417 #ifdef ULTRIX_AUTH 3418 if (!anonymous && numfails > 0) { 3419 lreply(success_code, 3420 "There have been %d unsuccessful login attempts on your account", 3421 numfails); 3422 } 3423 #endif /* ULTRIX_AUTH */ 3424 3425 (void) is_shutdown(0, 0); /* display any shutdown messages now */ 3426 3427 if (anonymous) { 3428 3429 reply(success_code, "Guest login ok, access restrictions apply."); 3430 sprintf(proctitle, "%s: anonymous/%.*s", remotehost, 3431 (int) (sizeof(proctitle) - sizeof(remotehost) - 3432 sizeof(": anonymous/")), passwd); 3433 setproctitle("%s", proctitle); 3434 if (logging) 3435 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", 3436 remoteident, passwd); 3437 } 3438 else { 3439 reply(success_code, "User %s logged in.%s", pw->pw_name, guest ? 3440 " Access restrictions apply." : ""); 3441 sprintf(proctitle, "%s: %s", remotehost, pw->pw_name); 3442 setproctitle("%s", proctitle); 3443 if (logging) 3444 syslog(LOG_INFO, "FTP LOGIN FROM %s, %s", remoteident, pw->pw_name); 3445 /* H* mod: if non-anonymous user, copy it to "authuser" so everyone can 3446 see it, since whoever he was @foreign-host is now largely irrelevant. 3447 NMM mod: no, it isn't! Think about accounting for the transfers from or 3448 to a shared account. */ 3449 /* strcpy (authuser, pw->pw_name); */ 3450 } /* anonymous */ 3451 #ifdef ALTERNATE_CD 3452 if (!home) 3453 #endif 3454 home = pw->pw_dir; /* home dir for globbing */ 3455 (void) umask(defumask); 3456 time(&login_time); 3457 { 3458 struct aclmember *entry; 3459 entry = NULL; 3460 while (getaclentry("limit-time", &entry) && ARG0 && ARG1) 3461 if ((anonymous && strcasecmp(ARG0, "anonymous") == 0) 3462 || (guest && strcasecmp(ARG0, "guest") == 0) 3463 || ((guest | anonymous) && strcmp(ARG0, "*") == 0)) 3464 limit_time = strtoul(ARG1, NULL, 0); 3465 } 3466 3467 /* Need to reset here as user type/class now known */ 3468 #ifdef INET6 3469 /* IP_TOS is an IPv4 socket option */ 3470 if (SOCK_FAMILY(ctrl_addr) == AF_INET) 3471 #endif 3472 if ((cos = IPClassOfService("control")) >= 0) { 3473 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &cos, sizeof(int)) < 0) 3474 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 3475 } 3476 3477 #ifdef SOLARIS_BSM_AUDIT 3478 audit_ftpd_success(the_user); 3479 #endif 3480 init_privs(pw->pw_name); 3481 return; 3482 bad: 3483 /* Forget all about it... */ 3484 if (xferlog) 3485 close(xferlog); 3486 xferlog = 0; 3487 acl_remove(); 3488 #ifdef SOLARIS_BSM_AUDIT 3489 audit_ftpd_failure(the_user); 3490 #endif 3491 end_login(); 3492 return; 3493 } 3494 3495 int restricteduid(uid_t uid) 3496 { 3497 return uid_match("restricted-uid", uid); 3498 } 3499 3500 int unrestricteduid(uid_t uid) 3501 { 3502 return uid_match("unrestricted-uid", uid); 3503 } 3504 3505 int restrictedgid(gid_t gid) 3506 { 3507 return gid_match("restricted-gid", gid, NULL); 3508 } 3509 3510 int unrestrictedgid(gid_t gid) 3511 { 3512 return gid_match("unrestricted-gid", gid, NULL); 3513 } 3514 3515 char *opt_string(int options) 3516 { 3517 static char buf[100]; 3518 char *ptr = buf; 3519 3520 if ((options & O_COMPRESS) != 0) /* debian fixes: NULL -> 0 */ 3521 *ptr++ = 'C'; 3522 if ((options & O_TAR) != 0) 3523 *ptr++ = 'T'; 3524 if ((options & O_UNCOMPRESS) != 0) 3525 *ptr++ = 'U'; 3526 if (options == 0) 3527 *ptr++ = '_'; 3528 *ptr++ = '\0'; 3529 return (buf); 3530 } 3531 3532 #ifdef INTERNAL_LS 3533 char *rpad(char *s, unsigned int len) 3534 { 3535 char *a; 3536 a = (char *) malloc(len + 1); 3537 memset(a, ' ', len); 3538 a[len] = 0; 3539 if (strlen(s) <= len) 3540 memcpy(a, s, strlen(s)); 3541 else 3542 strncpy(a, s, len); 3543 return a; 3544 } 3545 3546 char *ls_file(const char *file, int nameonly, char remove_path, char classify) 3547 { 3548 static const char month[12][4] = 3549 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 3550 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 3551 3552 char *permissions; 3553 struct stat s; 3554 struct tm *t; 3555 char *ls_entry; 3556 char *owner, *ownerg; 3557 char *rpowner, *rpownerg; 3558 char *link; 3559 #ifndef LS_NUMERIC_UIDS 3560 struct passwd *pw; 3561 struct group *gr; 3562 #endif 3563 link = NULL; 3564 owner = NULL; 3565 ownerg = NULL; 3566 if (lstat(file, &s) != 0) /* File doesn't exist, or is not readable by user */ 3567 return NULL; 3568 ls_entry = (char *) malloc(312); 3569 memset(ls_entry, 0, 312); 3570 permissions = strdup("----------"); 3571 if (S_ISLNK(s.st_mode)) { 3572 permissions[0] = 'l'; 3573 if (classify) 3574 classify = '@'; 3575 } 3576 else if (S_ISDIR(s.st_mode)) { 3577 permissions[0] = 'd'; 3578 if (classify) 3579 classify = '/'; 3580 } 3581 else if (S_ISBLK(s.st_mode)) 3582 permissions[0] = 'b'; 3583 else if (S_ISCHR(s.st_mode)) 3584 permissions[0] = 'c'; 3585 else if (S_ISFIFO(s.st_mode)) { 3586 permissions[0] = 'p'; 3587 if (classify == 1) 3588 classify = '='; 3589 } 3590 #ifdef S_ISSOCK 3591 else if (S_ISSOCK(s.st_mode)) 3592 permissions[0] = 's'; 3593 #endif 3594 if ((s.st_mode & S_IRUSR) == S_IRUSR) 3595 permissions[1] = 'r'; 3596 if ((s.st_mode & S_IWUSR) == S_IWUSR) 3597 permissions[2] = 'w'; 3598 if ((s.st_mode & S_IXUSR) == S_IXUSR) { 3599 permissions[3] = 'x'; 3600 if (classify == 1) 3601 classify = '*'; 3602 #ifndef HIDE_SETUID 3603 if ((s.st_mode & S_ISUID) == S_ISUID) 3604 permissions[3] = 's'; 3605 #endif 3606 } 3607 #ifndef HIDE_SETUID 3608 else if ((s.st_mode & S_ISUID) == S_ISUID) 3609 permissions[3] = 'S'; 3610 #endif 3611 if ((s.st_mode & S_IRGRP) == S_IRGRP) 3612 permissions[4] = 'r'; 3613 if ((s.st_mode & S_IWGRP) == S_IWGRP) 3614 permissions[5] = 'w'; 3615 if ((s.st_mode & S_IXGRP) == S_IXGRP) { 3616 permissions[6] = 'x'; 3617 if (classify == 1) 3618 classify = '*'; 3619 #ifndef HIDE_SETUID 3620 if ((s.st_mode & S_ISGID) == S_ISGID) 3621 permissions[6] = 's'; 3622 #endif 3623 } 3624 #ifndef HIDE_SETUID 3625 else if ((s.st_mode & S_ISGID) == S_ISGID) 3626 permissions[6] = 'S'; 3627 #endif 3628 if ((s.st_mode & S_IROTH) == S_IROTH) 3629 permissions[7] = 'r'; 3630 if ((s.st_mode & S_IWOTH) == S_IWOTH) 3631 permissions[8] = 'w'; 3632 if ((s.st_mode & S_IXOTH) == S_IXOTH) { 3633 permissions[9] = 'x'; 3634 if (classify == 1) 3635 classify = '*'; 3636 #ifndef HIDE_SETUID 3637 if ((s.st_mode & S_ISVTX) == S_ISVTX) 3638 permissions[9] = 't'; 3639 #endif 3640 } 3641 #ifndef HIDE_SETUID 3642 else if ((s.st_mode & S_ISVTX) == S_ISVTX) 3643 permissions[9] = 'T'; 3644 #endif 3645 t = localtime(&s.st_mtime); 3646 #ifndef LS_NUMERIC_UIDS 3647 #ifdef OTHER_PASSWD 3648 pw = bero_getpwuid(s.st_uid, _path_passwd); 3649 #else 3650 pw = getpwuid(s.st_uid); 3651 #endif 3652 if (pw != NULL) 3653 owner = strdup(pw->pw_name); 3654 gr = getgrgid(s.st_gid); 3655 if (gr != NULL) 3656 ownerg = strdup(gr->gr_name); 3657 #endif 3658 if (owner == NULL) { /* Can't figure out username (or don't want to) */ 3659 if (s.st_uid == 0) 3660 owner = strdup("root"); 3661 else { 3662 owner = (char *) malloc(9); 3663 memset(owner, 0, 9); 3664 #ifdef SOLARIS_2 3665 snprintf(owner, 8, "%lu", s.st_uid); 3666 #else 3667 snprintf(owner, 8, "%u", s.st_uid); 3668 #endif 3669 } 3670 } 3671 if (ownerg == NULL) { /* Can't figure out groupname (or don't want to) */ 3672 if (s.st_gid == 0) 3673 ownerg = strdup("root"); 3674 else { 3675 ownerg = (char *) malloc(9); 3676 memset(ownerg, 0, 9); 3677 #ifdef SOLARIS_2 3678 snprintf(ownerg, 8, "%lu", s.st_gid); 3679 #else 3680 snprintf(ownerg, 8, "%u", s.st_gid); 3681 #endif 3682 } 3683 } 3684 3685 #ifdef HAVE_LSTAT 3686 if (S_ISLNK(s.st_mode)) { 3687 link = (char *) malloc(MAXPATHLEN); 3688 memset(link, 0, MAXPATHLEN); 3689 if (readlink(file, link, MAXPATHLEN) == -1) { 3690 free(link); 3691 link = NULL; 3692 } 3693 } 3694 #endif 3695 3696 if (remove_path != 0 && strchr(file, '/')) 3697 file = strrchr(file, '/') + 1; 3698 3699 rpowner = rpad(owner, 8); 3700 rpownerg = rpad(ownerg, 8); 3701 3702 #ifdef SOLARIS_2 3703 #define N_FORMAT "lu" 3704 #else 3705 #if defined(__FreeBSD__) || defined(__bsdi__) 3706 #define N_FORMAT "u" 3707 #else 3708 #define N_FORMAT "u" 3709 #endif 3710 #endif 3711 3712 if (nameonly) { 3713 sprintf(ls_entry, "%s", file); 3714 if (link != NULL) 3715 free(link); 3716 } 3717 else { 3718 if ((time(NULL) - s.st_mtime) > 6307200) { /* File is older than 6 months */ 3719 if (link == NULL) 3720 snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %5u %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file); 3721 else { 3722 snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %5u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, 1900 + t->tm_year, file, link); 3723 free(link); 3724 } 3725 } 3726 else if (link == NULL) 3727 snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %02u:%02u %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file); 3728 else { 3729 snprintf(ls_entry, 311, "%s %3" N_FORMAT " %s %s %8" L_FORMAT " %s %2u %02u:%02u %s -> %s", permissions, s.st_nlink, rpowner, rpownerg, s.st_size, month[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, file, link); 3730 free(link); 3731 } 3732 } 3733 free(rpowner); 3734 free(rpownerg); 3735 free(owner); 3736 free(ownerg); 3737 if (classify > 1) 3738 sprintf(ls_entry + strlen(ls_entry), "%c", classify); 3739 strcat(ls_entry, "\r\n"); 3740 free(permissions); 3741 return ls_entry; 3742 } 3743 3744 void ls_dir(char *d, char ls_a, char ls_F, char ls_l, char ls_R, char omit_total, FILE *out) 3745 { 3746 int total; 3747 char *realdir; /* fixed up value to pass to glob() */ 3748 char **subdirs; /* Subdirs to be scanned for ls -R */ 3749 int numSubdirs = 0; 3750 glob_t g; 3751 char isDir; /* 0: d is a file; 1: d is some files; 2: d is dir */ 3752 struct stat s; 3753 char *dirlist; 3754 unsigned long dl_size, dl_used; 3755 char *c; 3756 char *lsentry; 3757 int i; 3758 #ifndef GLOB_PERIOD 3759 char *dperiod; 3760 #endif 3761 3762 isDir = 0; 3763 realdir = (char *) malloc(strlen(d) + 3); 3764 memset(realdir, 0, strlen(d) + 3); 3765 strcpy(realdir, d); 3766 if (strcmp(realdir, ".") == 0) 3767 realdir[0] = '*'; 3768 if (strcmp(realdir + strlen(realdir) - 2, "/.") == 0) 3769 realdir[strlen(realdir) - 1] = '*'; 3770 if (realdir[strlen(realdir) - 1] == '/') 3771 strcat(realdir, "*"); 3772 if (strchr(realdir, '*') || strchr(realdir, '?')) 3773 isDir = 1; 3774 if (strcmp(realdir, "*") == 0 || strcmp(realdir + strlen(realdir) - 2, "/*") == 0) 3775 isDir = 2; 3776 else { 3777 if (lstat(realdir, &s) == 0) { 3778 if (S_ISDIR(s.st_mode)) { 3779 strcat(realdir, "/*"); 3780 isDir = 2; 3781 } 3782 } 3783 } 3784 3785 if (isDir == 0) { 3786 if (ls_l) { 3787 lsentry = ls_file(realdir, 0, 0, ls_F); 3788 if (lsentry != NULL) { 3789 if (draconian_FILE != NULL) { 3790 (void) signal(SIGALRM, draconian_alarm_signal); 3791 alarm(timeout_data); 3792 #if defined(USE_GSS) 3793 sec_fprintf(out, "%s", lsentry); 3794 #else 3795 fputs(lsentry, out); 3796 #endif /* defined(USE_GSS) */ 3797 (void) signal(SIGALRM, SIG_DFL); 3798 } 3799 free(lsentry); 3800 } 3801 } 3802 else { 3803 if (draconian_FILE != NULL) { 3804 (void) signal(SIGALRM, draconian_alarm_signal); 3805 alarm(timeout_data); 3806 #if defined(USE_GSS) 3807 sec_fprintf(out, "%s", realdir); 3808 #else 3809 fputs(realdir, out); 3810 #endif /* defined(USE_GSS) */ 3811 (void) signal(SIGALRM, SIG_DFL); 3812 } 3813 } 3814 free(realdir); 3815 } 3816 else { 3817 if (ls_R) { 3818 numSubdirs = 0; 3819 subdirs = (char **) malloc(200 * sizeof(char *)); 3820 memset(subdirs, 0, 200 * sizeof(char *)); 3821 } 3822 3823 dl_size = 65536; 3824 dirlist = (char *) malloc(65536); 3825 memset(dirlist, 0, 65536); 3826 dl_used = 0; 3827 3828 total = 0; 3829 memset(&g, 0, sizeof(g)); 3830 if (ls_a) { 3831 #ifdef GLOB_PERIOD 3832 if (glob(realdir, GLOB_ERR | GLOB_PERIOD, NULL, &g) != 0) 3833 g.gl_pathc = 0; 3834 #else 3835 dperiod = (char *) malloc(strlen(realdir) + 2); 3836 memset(dperiod, 0, strlen(realdir) + 2); 3837 strcpy(dperiod, "."); 3838 strcat(dperiod, realdir); 3839 if (glob(dperiod, GLOB_ERR, NULL, &g) != 0) 3840 g.gl_pathc = 0; 3841 glob(realdir, GLOB_ERR | GLOB_APPEND, NULL, &g); 3842 free(dperiod); 3843 #endif 3844 } 3845 else if (glob(realdir, GLOB_ERR, NULL, &g) != 0) 3846 g.gl_pathc = 0; 3847 free(realdir); 3848 for (i = 0; i < g.gl_pathc; i++) { 3849 c = g.gl_pathv[i]; 3850 if (lstat(c, &s) != -1) { 3851 if (ls_l) { 3852 total += s.st_blocks; 3853 lsentry = ls_file(c, 0, 1, ls_F); 3854 if (lsentry != NULL) { 3855 /* This can actually happen even though the lstat() worked - 3856 if someone deletes the file between the lstat() and ls_file() 3857 calls. Unlikely, but better safe than sorry... */ 3858 int flag = snprintf(dirlist + dl_used, dl_size - dl_used, "%s", lsentry); 3859 dl_used += (flag == -1 ? dl_size - dl_used : flag); 3860 free(lsentry); 3861 } 3862 } 3863 else { 3864 int flag; 3865 lsentry = ls_file(c, 1, 1, ls_F); 3866 if (lsentry != NULL) { 3867 flag = snprintf(dirlist + dl_used, dl_size - dl_used, "%s", lsentry); 3868 dl_used += (flag == -1 ? dl_size - dl_used : flag); 3869 free(lsentry); 3870 } 3871 } 3872 if ((ls_R != 0) && (S_ISDIR(s.st_mode)) 3873 && (strcmp(c, "..") != 0) && (strcmp(c, ".") != 0) 3874 && !(strlen(c) > 3 && strcmp(c + strlen(c) - 3, "/..") == 0) 3875 && !(strlen(c) > 2 && strcmp(c + strlen(c) - 2, "/.") == 0)) { 3876 subdirs[numSubdirs++] = strdup(c); 3877 if ((numSubdirs % 200) == 0) 3878 subdirs = (char **) realloc(subdirs, (numSubdirs + 200) * sizeof(char *)); 3879 } 3880 } 3881 if (dl_used + 512 >= dl_size) { 3882 dl_size += 65536; 3883 dirlist = (char *) realloc(dirlist, dl_size); 3884 } 3885 } 3886 globfree(&g); 3887 if (ls_l && isDir == 2 && omit_total == 0) { 3888 if (draconian_FILE != NULL) { 3889 (void) signal(SIGALRM, draconian_alarm_signal); 3890 alarm(timeout_data); 3891 #if defined(USE_GSS) 3892 sec_fprintf(out, "total %u\r\n", total); 3893 #else 3894 fprintf(out, "total %u\r\n", total); 3895 #endif /* defined(USE_GSS) */ 3896 } 3897 } 3898 if (draconian_FILE != NULL) { 3899 (void) signal(SIGALRM, draconian_alarm_signal); 3900 alarm(timeout_data); 3901 #if defined(USE_GSS) 3902 sec_fprintf(out, "%s", dirlist); 3903 #else 3904 fputs(dirlist, out); 3905 #endif /* defined(USE_GSS) */ 3906 } 3907 free(dirlist); 3908 if (ls_R) { 3909 for (i = 0; i < numSubdirs; i++) { 3910 if (draconian_FILE != NULL) { 3911 (void) signal(SIGALRM, draconian_alarm_signal); 3912 alarm(timeout_data); 3913 #if defined(USE_GSS) 3914 sec_fprintf(out, "\r\n%s:\r\n", subdirs[i]); 3915 #else 3916 fprintf(out, "\r\n%s:\r\n", subdirs[i]); 3917 #endif /* defined(USE_GSS) */ 3918 ls_dir(subdirs[i], ls_a, ls_F, ls_l, ls_R, 0, out); 3919 } 3920 free(subdirs[i]); 3921 } 3922 free(subdirs); 3923 } 3924 } 3925 } 3926 3927 void ls(char *file, char nlst) 3928 { 3929 FILE *out; 3930 char free_file = 0; 3931 char ls_l = 0, ls_a = 0, ls_R = 0, ls_F = 0; 3932 3933 if (nlst == 0) 3934 ls_l = 1; /* LIST defaults to ls -l */ 3935 if (file == NULL) { 3936 file = strdup("."); 3937 free_file = 1; 3938 } 3939 if (strcmp(file, "*") == 0) 3940 file[0] = '.'; 3941 3942 if (file[0] == '-') { /* options... */ 3943 if (strchr(file, ' ') == 0) { 3944 if (strchr(file, 'l')) 3945 ls_l = 1; 3946 if (strchr(file, 'a')) 3947 ls_a = 1; 3948 if (strchr(file, 'R')) 3949 ls_R = 1; 3950 if (strchr(file, 'F')) 3951 ls_F = 1; 3952 file = strdup("."); 3953 free_file = 1; 3954 } 3955 else { 3956 if (strchr(file, 'l') != NULL && strchr(file, 'l') < strchr(file, ' ')) 3957 ls_l = 1; 3958 if (strchr(file, 'a') != NULL && strchr(file, 'a') < strchr(file, ' ')) 3959 ls_a = 1; 3960 if (strchr(file, 'R') != NULL && strchr(file, 'R') < strchr(file, ' ')) 3961 ls_R = 1; 3962 if (strchr(file, 'F') != NULL && strchr(file, 'F') < strchr(file, ' ')) 3963 ls_F = 1; 3964 file = strchr(file, ' '); 3965 } 3966 } 3967 while (file[0] == ' ') /* ignore additional whitespaces between parameters */ 3968 file++; 3969 if (strlen(file) == 0) { 3970 file = strdup("."); 3971 free_file = 1; 3972 } 3973 3974 out = dataconn("directory listing", -1, "w"); 3975 draconian_FILE = out; 3976 3977 transflag++; 3978 3979 fixpath(file); 3980 if (file[0] == '\0') { 3981 if (free_file != 0) 3982 free(file); 3983 file = strdup("."); 3984 free_file = 1; 3985 } 3986 3987 ls_dir(file, ls_a, ls_F, ls_l, ls_R, 0, out); 3988 data = -1; 3989 pdata = -1; 3990 if (draconian_FILE != NULL) { 3991 (void) signal(SIGALRM, draconian_alarm_signal); 3992 alarm(timeout_data); 3993 #if defined(USE_GSS) 3994 if (sec_fflush(out) < 0) { 3995 draconian_FILE = NULL; 3996 alarm(0); 3997 transflag = 0; 3998 perror_reply(550, "Data connection"); 3999 fclose(out); 4000 goto ls_done; 4001 } 4002 #else 4003 fflush(out); 4004 #endif /* defined(USE_GSS) */ 4005 } 4006 if (draconian_FILE != NULL) { 4007 (void) signal(SIGALRM, draconian_alarm_signal); 4008 alarm(timeout_data); 4009 socket_flush_wait(out); 4010 } 4011 if (draconian_FILE != NULL) { 4012 (void) signal(SIGALRM, draconian_alarm_signal); 4013 alarm(timeout_data); 4014 fclose(out); 4015 draconian_FILE = NULL; 4016 } 4017 alarm(0); 4018 transflag = 0; 4019 reply(226, "Transfer complete."); 4020 ls_done: 4021 if (free_file != 0) 4022 free(file); 4023 } 4024 #endif /* INTERNAL_LS */ 4025 4026 void retrieve(char *cmd, char *name) 4027 { 4028 FILE *fin = NULL, *dout; 4029 struct stat st, junk; 4030 int (*closefunc) () = NULL; 4031 int options = 0; 4032 int ThisRetrieveIsData = retrieve_is_data; 4033 time_t start_time = time(NULL); 4034 char *logname; 4035 char namebuf[MAXPATHLEN]; 4036 char fnbuf[MAXPATHLEN]; 4037 static int TransferComplete; /* static as retrieve can call itself */ 4038 struct convert *cptr; 4039 char realname[MAXPATHLEN]; 4040 int stat_ret = -1; 4041 size_t buffersize; 4042 4043 TransferComplete = 0; 4044 wu_realpath(name, realname, chroot_path); 4045 4046 if (cmd == NULL && (stat_ret = stat(name, &st)) == 0) 4047 /* there isn't a command and the file exists */ 4048 if (use_accessfile && checknoretrieve(name)) { /* see above. _H */ 4049 if (log_security) 4050 if (anonymous) 4051 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (noretrieve)", 4052 guestpw, remoteident, realname); 4053 else 4054 syslog(LOG_NOTICE, "%s of %s tried to download %s (noretrieve)", 4055 pw->pw_name, remoteident, realname); 4056 return; 4057 } 4058 4059 #ifdef TRANSFER_COUNT 4060 #ifdef TRANSFER_LIMIT 4061 if (retrieve_is_data) 4062 if (((file_limit_data_out > 0) && (file_count_out >= file_limit_data_out)) 4063 || ((file_limit_data_total > 0) && (file_count_total >= file_limit_data_total)) 4064 || ((data_limit_data_out > 0) && (data_count_out >= data_limit_data_out)) 4065 || ((data_limit_data_total > 0) && (data_count_total >= data_limit_data_total))) { 4066 if (log_security) 4067 if (anonymous) 4068 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to retrieve %s (Transfer limits exceeded)", 4069 guestpw, remoteident, realname); 4070 else 4071 syslog(LOG_NOTICE, "%s of %s tried to retrieve %s (Transfer limits exceeded)", 4072 pw->pw_name, remoteident, realname); 4073 reply(553, "Permission denied on server. (Transfer limits exceeded)"); 4074 return; 4075 } 4076 if (((file_limit_raw_out > 0) && (xfer_count_out >= file_limit_raw_out)) 4077 || ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total)) 4078 || ((data_limit_raw_out > 0) && (byte_count_out >= data_limit_raw_out)) 4079 || ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) { 4080 if (log_security) 4081 if (anonymous) 4082 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to retrieve %s (Transfer limits exceeded)", 4083 guestpw, remoteident, realname); 4084 else 4085 syslog(LOG_NOTICE, "%s of %s tried to retrieve %s (Transfer limits exceeded)", 4086 pw->pw_name, remoteident, realname); 4087 reply(553, "Permission denied on server. (Transfer limits exceeded)"); 4088 return; 4089 } 4090 #ifdef RATIO 4091 if (retrieve_is_data && (upload_download_rate > 0) ) 4092 if( freefile = is_downloadfree(name) ) { 4093 syslog(LOG_INFO, "%s is download free.", name ); 4094 } 4095 else { 4096 if ((cmd == NULL) && ((data_count_in * upload_download_rate) < (data_count_out - total_free_dl))) { 4097 reply(550, "%s: Upload/Download ratio exceeded", name); 4098 goto done; 4099 } 4100 } 4101 #endif /* RATIO */ 4102 #endif 4103 #endif 4104 4105 logname = (char *) NULL; 4106 if (cmd == NULL && stat_ret != 0) { /* file does not exist */ 4107 char *ptr; 4108 4109 for (cptr = cvtptr; cptr != NULL; cptr = cptr->next) { 4110 if (!(mangleopts & O_COMPRESS) && (cptr->options & O_COMPRESS)) 4111 continue; 4112 if (!(mangleopts & O_UNCOMPRESS) && (cptr->options & O_UNCOMPRESS)) 4113 continue; 4114 if (!(mangleopts & O_TAR) && (cptr->options & O_TAR)) 4115 continue; 4116 4117 if ((cptr->stripfix) && (cptr->postfix)) { 4118 int pfxlen = strlen(cptr->postfix); 4119 int sfxlen = strlen(cptr->stripfix); 4120 int namelen = strlen(name); 4121 4122 if (namelen <= pfxlen) 4123 continue; 4124 if (((namelen - pfxlen + sfxlen) >= sizeof(fnbuf)) || 4125 (namelen >= sizeof(fnbuf))) 4126 continue; 4127 4128 (void) strcpy(fnbuf, name); 4129 if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix)) 4130 continue; 4131 *(fnbuf + namelen - pfxlen) = '\0'; 4132 (void) strcat(fnbuf, cptr->stripfix); 4133 if (stat(fnbuf, &st) != 0) 4134 continue; 4135 } 4136 else if (cptr->postfix) { 4137 int pfxlen = strlen(cptr->postfix); 4138 int namelen = strlen(name); 4139 4140 if ((namelen <= pfxlen) || (namelen >= sizeof(fnbuf))) 4141 continue; 4142 (void) strcpy(fnbuf, name); 4143 if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix)) 4144 continue; 4145 *(fnbuf + namelen - pfxlen) = (char) NULL; 4146 if (stat(fnbuf, &st) != 0) 4147 continue; 4148 } 4149 else if (cptr->stripfix) { 4150 if (strlen(name) + strlen(cptr->stripfix) >= sizeof(fnbuf)) 4151 continue; 4152 (void) strcpy(fnbuf, name); 4153 (void) strcat(fnbuf, cptr->stripfix); 4154 if (stat(fnbuf, &st) != 0) 4155 continue; 4156 } 4157 else { 4158 continue; 4159 } 4160 4161 if (S_ISDIR(st.st_mode)) { 4162 if (!cptr->types || !(cptr->types & T_DIR)) { 4163 reply(550, "Cannot %s directories.", cptr->name); 4164 return; 4165 } 4166 if ((cptr->options & O_TAR)) { 4167 strcpy(namebuf, fnbuf); 4168 if (strlcat(namebuf, "/.notar", sizeof(namebuf)) >= 4169 sizeof(namebuf)) 4170 continue; 4171 if (stat(namebuf, &junk) == 0) { 4172 if (log_security) 4173 if (anonymous) 4174 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to tar %s (.notar)", 4175 guestpw, remoteident, realname); 4176 else 4177 syslog(LOG_NOTICE, "%s of %s tried to tar %s (.notar)", 4178 pw->pw_name, remoteident, realname); 4179 reply(550, "Sorry, you may not TAR that directory."); 4180 return; 4181 } 4182 } 4183 } 4184 /* XXX: checknoretrieve() test is weak in that if I can't get /etc/passwd 4185 but I can tar /etc or /, I still win. Be careful out there... _H* 4186 but you could put .notar in / and /etc and stop that ! */ 4187 if (use_accessfile && checknoretrieve(fnbuf)) { 4188 if (log_security) 4189 if (anonymous) 4190 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (noretrieve)", 4191 guestpw, remoteident, realname); 4192 else 4193 syslog(LOG_NOTICE, "%s of %s tried to download %s (noretrieve)", 4194 pw->pw_name, remoteident, realname); 4195 return; 4196 } 4197 4198 if (S_ISREG(st.st_mode) && (!cptr->types || (cptr->types & T_REG) == 0)) { 4199 reply(550, "Cannot %s plain files.", cptr->name); 4200 return; 4201 } 4202 if (S_ISREG(st.st_mode) != 0 && S_ISDIR(st.st_mode) != 0) { 4203 reply(550, "Cannot %s special files.", cptr->name); 4204 return; 4205 } 4206 if ((!cptr->types || !(cptr->types & T_ASCII)) && deny_badasciixfer(550, "")) 4207 return; 4208 4209 logname = &fnbuf[0]; 4210 options |= cptr->options; 4211 4212 strcpy(namebuf, cptr->external_cmd); 4213 if ((ptr = strchr(namebuf, ' ')) != NULL) 4214 *ptr = '\0'; 4215 if (stat(namebuf, &junk) != 0) { 4216 syslog(LOG_ERR, "external command %s not found", namebuf); 4217 reply(550, 4218 "Local error: conversion program not found. Cannot %s file.", 4219 cptr->name); 4220 return; 4221 } 4222 (void) retrieve(cptr->external_cmd, logname); 4223 4224 goto logresults; /* transfer of converted file completed */ 4225 } 4226 } 4227 4228 if (cmd == NULL) { /* no command */ 4229 fin = fopen(name, "r"), closefunc = fclose; 4230 st.st_size = 0; 4231 } 4232 else { /* run command */ 4233 static char line[BUFSIZ]; 4234 4235 (void) snprintf(line, sizeof(line), cmd, name), name = line; 4236 fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose; 4237 st.st_size = -1; 4238 #ifdef HAVE_ST_BLKSIZE 4239 st.st_blksize = BUFSIZ; 4240 #endif 4241 } 4242 if (fin == NULL) { 4243 if (errno != 0) 4244 perror_reply(550, name); 4245 if ((errno == EACCES) || (errno == EPERM)) 4246 if (log_security) 4247 if (anonymous) 4248 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to download %s (file permissions)", 4249 guestpw, remoteident, realname); 4250 else 4251 syslog(LOG_NOTICE, "%s of %s tried to download %s (file permissions)", 4252 pw->pw_name, remoteident, realname); 4253 return; 4254 } 4255 if (cmd == NULL && 4256 (fstat(fileno(fin), &st) < 0 || (st.st_mode & S_IFMT) != S_IFREG)) { 4257 reply(550, "%s: not a plain file.", name); 4258 goto done; 4259 } 4260 if (restart_point) { 4261 if (type == TYPE_A) { 4262 register int c; 4263 off_t i; 4264 4265 i = 0; 4266 while (i++ < restart_point) { 4267 if ((c = getc(fin)) == EOF) { 4268 perror_reply(550, name); 4269 goto done; 4270 } 4271 if (c == '\n') 4272 i++; 4273 } 4274 } 4275 else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) { 4276 perror_reply(550, name); 4277 goto done; 4278 } 4279 } 4280 4281 dout = dataconn(name, st.st_size, "w"); 4282 if (dout == NULL) 4283 goto done; 4284 4285 if (sendbufsz > 0) { 4286 buffersize = sendbufsz; 4287 } 4288 else { 4289 #ifdef BUFFER_SIZE 4290 buffersize = BUFFER_SIZE; 4291 #elif HAVE_ST_BLKSIZE 4292 buffersize = st.st_blksize * 2; 4293 #else 4294 buffersize = BUFSIZ * 16; 4295 #endif 4296 } 4297 4298 #ifdef THROUGHPUT 4299 TransferComplete = send_data(name, fin, dout, buffersize); 4300 #else 4301 TransferComplete = send_data(fin, dout, buffersize); 4302 #endif 4303 #ifdef SIGPIPE 4304 (void) signal(SIGPIPE, SIG_IGN); 4305 #endif 4306 (void) fclose(dout); 4307 #ifdef SIGPIPE 4308 (void) signal(SIGPIPE, lostconn); 4309 #endif 4310 4311 logresults: 4312 if (ThisRetrieveIsData) 4313 fb_realpath((logname != NULL) ? logname : name, LastFileTransferred); 4314 4315 if (log_outbound_xfers && (xferlog || syslogmsg) && (cmd == NULL)) { 4316 char msg[MAXXFERSTRLEN]; /* see extensions.h */ 4317 int xfertime = time(NULL) - start_time; 4318 size_t msglen; 4319 4320 if (!xfertime) 4321 xfertime++; 4322 4323 /* Gather transfer statistics */ 4324 xfervalues.filename = (logname != NULL) ? logname : name; 4325 xfervalues.filesize = st.st_size; 4326 xfervalues.transfer_bytes = byte_count; 4327 xfervalues.transfer_direction = 'o'; 4328 xfervalues.transfer_type = (type == TYPE_A) ? 'a' : 'b'; 4329 xfervalues.transfer_time = xfertime; 4330 xfervalues.restart_offset = restart_point; 4331 strlcpy(xfervalues.special_action, opt_string(options), MAXSPACTCHARS); 4332 xfervalues.access_mode = anonymous ? 'a' : (guest ? 'g' : 'r'); 4333 xfervalues.auth = authenticated; 4334 xfervalues.completion = TransferComplete ? 'c' : 'i'; 4335 4336 xferdone = 1; 4337 msg_massage(xferlog_format, msg, sizeof(msg)); 4338 xferdone = 0; 4339 4340 /* Ensure msg always ends with '\n' */ 4341 msglen = strlen(msg); 4342 if (msglen == sizeof(msg) - 1) { 4343 msg[sizeof(msg) - 2] = '\n'; 4344 msg[sizeof(msg) - 1] = '\0'; 4345 } 4346 else { 4347 msg[msglen] = '\n'; 4348 msg[msglen + 1] = '\0'; 4349 } 4350 4351 if (syslogmsg != 1) 4352 write(xferlog, msg, strlen(msg)); 4353 if (syslogmsg != 0) { 4354 char *msgp = msg; 4355 /* 4356 * To preserve the behavior when the xferlog format was fixed, skip 4357 * over the time string if the message starts with the local time. 4358 */ 4359 if (strncmp(xferlog_format, "%T ", 3) == 0) 4360 msgp += 25; 4361 syslog(LOG_INFO, "xferlog (send): %s", msgp); 4362 } 4363 } 4364 data = -1; 4365 pdata = -1; 4366 done: 4367 if (closefunc) 4368 (*closefunc) (fin); 4369 } 4370 4371 void store(char *name, char *mode, int unique) 4372 { 4373 FILE *fout, *din; 4374 struct stat st; 4375 int TransferIncomplete = 1; 4376 char *gunique(char *local); 4377 time_t start_time = time(NULL); 4378 4379 struct aclmember *entry = NULL; 4380 4381 int fdout; 4382 char realname[MAXPATHLEN]; 4383 4384 #ifdef OVERWRITE 4385 int overwrite = 1; 4386 int exists = 0; 4387 4388 #endif /* OVERWRITE */ 4389 4390 int open_flags = 0; 4391 4392 #ifdef UPLOAD 4393 mode_t oldmask; 4394 uid_t uid; 4395 gid_t gid; 4396 uid_t oldid; 4397 int f_mode = -1, match_value = -1; 4398 int valid = 0; 4399 int ret, serrno; 4400 open_flags = (O_RDWR | O_CREAT | 4401 ((mode != NULL && *mode == 'a') ? O_APPEND : O_TRUNC)); 4402 #endif /* UPLOAD */ 4403 4404 wu_realpath(name, realname, chroot_path); 4405 4406 #ifdef TRANSFER_COUNT 4407 #ifdef TRANSFER_LIMIT 4408 if (((file_limit_data_in > 0) && (file_count_in >= file_limit_data_in)) 4409 || ((file_limit_data_total > 0) && (file_count_total >= file_limit_data_total)) 4410 || ((data_limit_data_in > 0) && (data_count_in >= data_limit_data_in)) 4411 || ((data_limit_data_total > 0) && (data_count_total >= data_limit_data_total))) { 4412 if (log_security) 4413 if (anonymous) 4414 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (Transfer limits exceeded)", 4415 guestpw, remoteident, realname); 4416 else 4417 syslog(LOG_NOTICE, "%s of %s tried to upload %s (Transfer limits exceeded)", 4418 pw->pw_name, remoteident, realname); 4419 reply(553, "Permission denied on server. (Transfer limits exceeded)"); 4420 return; 4421 } 4422 if (((file_limit_raw_in > 0) && (xfer_count_in >= file_limit_raw_in)) 4423 || ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total)) 4424 || ((data_limit_raw_in > 0) && (byte_count_in >= data_limit_raw_in)) 4425 || ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) { 4426 if (log_security) 4427 if (anonymous) 4428 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (Transfer limits exceeded)", 4429 guestpw, remoteident, realname); 4430 else 4431 syslog(LOG_NOTICE, "%s of %s tried to upload %s (Transfer limits exceeded)", 4432 pw->pw_name, remoteident, realname); 4433 reply(553, "Permission denied on server. (Transfer limits exceeded)"); 4434 return; 4435 } 4436 #endif 4437 #endif 4438 4439 if (unique && stat(name, &st) == 0 && 4440 (name = gunique(name)) == NULL) 4441 return; 4442 4443 /* 4444 * check the filename, is it legal? 4445 */ 4446 if ((fn_check(name)) <= 0) { 4447 if (log_security) 4448 if (anonymous) 4449 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload \"%s\" (path-filter)", 4450 guestpw, remoteident, realname); 4451 else 4452 syslog(LOG_NOTICE, "%s of %s tried to upload \"%s\" (path-filter)", 4453 pw->pw_name, remoteident, realname); 4454 return; 4455 } 4456 4457 #ifdef OVERWRITE 4458 /* if overwrite permission denied and file exists... then deny the user 4459 * permission to write the file. */ 4460 while (getaclentry("overwrite", &entry) && ARG0 && ARG1 != NULL) { 4461 if (type_match(ARG1)) 4462 if (strcasecmp(ARG0, "yes") != 0) { 4463 overwrite = 0; 4464 open_flags |= O_EXCL; 4465 } 4466 } 4467 4468 #ifdef PARANOID 4469 overwrite = 0; 4470 #endif 4471 if (!stat(name, &st)) 4472 exists = 1; 4473 4474 if (!overwrite && exists) { 4475 if (log_security) 4476 if (anonymous) 4477 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to overwrite %s", 4478 guestpw, remoteident, realname); 4479 else 4480 syslog(LOG_NOTICE, "%s of %s tried to overwrite %s", 4481 pw->pw_name, remoteident, realname); 4482 reply(553, "%s: Permission denied on server. (Overwrite)", name); 4483 return; 4484 } 4485 #endif /* OVERWRITE */ 4486 4487 #ifdef UPLOAD 4488 if ((match_value = upl_check(name, &uid, &gid, &f_mode, &valid)) < 0) { 4489 if (log_security) 4490 if (anonymous) 4491 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (upload denied)", 4492 guestpw, remoteident, realname); 4493 else 4494 syslog(LOG_NOTICE, "%s of %s tried to upload %s (upload denied)", 4495 pw->pw_name, remoteident, realname); 4496 return; 4497 } 4498 4499 /* do not truncate the file if we are restarting */ 4500 if (restart_point) 4501 open_flags &= ~O_TRUNC; 4502 4503 /* if the user has an explicit new file mode, than open the file using 4504 * that mode. We must take care to not let the umask affect the file 4505 * mode. 4506 * 4507 * else open the file and let the default umask determine the file mode. */ 4508 if (f_mode >= 0) { 4509 oldmask = umask(0000); 4510 fdout = open(name, open_flags, f_mode); 4511 umask(oldmask); 4512 } 4513 else 4514 fdout = open(name, open_flags, 0666); 4515 4516 if (fdout < 0) { 4517 if (log_security) 4518 if (anonymous) 4519 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (permissions)", 4520 guestpw, remoteident, realname); 4521 else 4522 syslog(LOG_NOTICE, "%s of %s tried to upload %s (permissions)", 4523 pw->pw_name, remoteident, realname); 4524 perror_reply(553, name); 4525 return; 4526 } 4527 /* if we have a uid and gid, then use them. */ 4528 4529 #ifdef OVERWRITE 4530 if (!exists) 4531 #endif 4532 if (valid > 0) { 4533 oldid = geteuid(); 4534 if (uid != 0) 4535 (void) seteuid((uid_t) uid); 4536 if ((uid == 0) || ((fchown(fdout, uid, gid)) < 0)) { 4537 chown_priv_on(0); 4538 ret = fchown(fdout, uid, gid); 4539 serrno = errno; 4540 chown_priv_off(oldid); 4541 if (ret < 0) { 4542 errno = serrno; 4543 perror_reply(550, "fchown"); 4544 return; 4545 } 4546 } 4547 else 4548 (void) seteuid(oldid); 4549 } 4550 #endif /* UPLOAD */ 4551 4552 if (restart_point && (open_flags & O_APPEND) == 0) 4553 mode = "r+"; 4554 4555 #ifdef UPLOAD 4556 fout = fdopen(fdout, mode); 4557 #else 4558 fout = fopen(name, mode); 4559 #endif /* UPLOAD */ 4560 4561 if (fout == NULL) { 4562 if (log_security) 4563 if (anonymous) 4564 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to upload %s (permissions)", 4565 guestpw, remoteident, realname); 4566 else 4567 syslog(LOG_NOTICE, "%s of %s tried to upload %s (permissions)", 4568 pw->pw_name, remoteident, realname); 4569 perror_reply(553, name); 4570 return; 4571 } 4572 if (restart_point && (open_flags & O_APPEND) == 0) { 4573 if (type == TYPE_A) { 4574 register int c; 4575 off_t i; 4576 4577 i = 0; 4578 while (i++ < restart_point) { 4579 if ((c = getc(fout)) == EOF) { 4580 perror_reply(550, name); 4581 goto done; 4582 } 4583 if (c == '\n') 4584 i++; 4585 } 4586 /* We must do this seek to "current" position because we are 4587 * changing from reading to writing. */ 4588 #if _FILE_OFFSET_BITS == 64 4589 if (fseeko(fout, 0L, SEEK_CUR) < 0) { 4590 #else 4591 if (fseek(fout, 0L, SEEK_CUR) < 0) { 4592 #endif 4593 perror_reply(550, name); 4594 goto done; 4595 } 4596 } 4597 else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 4598 perror_reply(550, name); 4599 goto done; 4600 } 4601 } 4602 din = dataconn(name, (off_t) - 1, "r"); 4603 if (din == NULL) 4604 goto done; 4605 TransferIncomplete = receive_data(din, fout); 4606 4607 if (fstat(fileno(fout), &st) != 0) { 4608 /* shouldn't fail, but just in case */ 4609 st.st_size = -1; 4610 } 4611 (void) fclose(din); 4612 if (TransferIncomplete == 0) { 4613 if (unique) 4614 reply(226, "Transfer complete (unique file name:%s).", name); 4615 else 4616 reply(226, "Transfer complete."); 4617 } 4618 4619 fb_realpath(name, LastFileTransferred); 4620 4621 #ifdef MAIL_ADMIN 4622 if (anonymous && incmails > 0) { 4623 FILE *sck = NULL; 4624 4625 unsigned char temp = 0, temp2 = 0; 4626 char pathname[MAXPATHLEN]; 4627 while ((temp < mailservers) && (sck == NULL)) 4628 sck = SockOpen(mailserver[temp++], 25); 4629 if (sck == NULL) { 4630 syslog(LOG_ERR, "Can't connect to a mailserver."); 4631 goto mailfail; 4632 } 4633 if (Reply(sck) != 220) { 4634 syslog(LOG_ERR, "Mailserver failed to initiate contact."); 4635 goto mailfail; 4636 } 4637 if (Send(sck, "HELO localhost\r\n") != 250) { 4638 syslog(LOG_ERR, "Mailserver doesn't understand HELO."); 4639 goto mailfail; 4640 } 4641 if (Send(sck, "MAIL FROM: <%s>\r\n", email(mailfrom)) != 250) { 4642 syslog(LOG_ERR, "Mailserver didn't accept MAIL FROM."); 4643 goto mailfail; 4644 } 4645 for (temp = 0; temp < incmails; temp++) { 4646 if (Send(sck, "RCPT TO: <%s>\r\n", email(incmail[temp])) == 250) 4647 temp2++; 4648 } 4649 if (temp2 == 0) { 4650 syslog(LOG_ERR, "Mailserver didn't accept any RCPT TO."); 4651 goto mailfail; 4652 } 4653 if (Send(sck, "DATA\r\n") != 354) { 4654 syslog(LOG_ERR, "Mailserver didn't accept DATA."); 4655 goto mailfail; 4656 } 4657 SockPrintf(sck, "From: wu-ftpd <%s>\r\n", mailfrom); 4658 SockPrintf(sck, "Subject: New file uploaded: %s\r\n\r\n", name); 4659 fb_realpath(name, pathname); 4660 SockPrintf(sck, "%s uploaded %s from %s.\r\nFile size is %" L_FORMAT ".\r\nPlease move the file where it belongs.\r\n", guestpw, pathname, remotehost, st.st_size); 4661 if (Send(sck, ".\r\n") != 250) 4662 syslog(LOG_ERR, "Message rejected by mailserver."); 4663 if (Send(sck, "QUIT\r\n") != 221) 4664 syslog(LOG_ERR, "Mailserver didn't accept QUIT."); 4665 mailfail: 4666 if (sck != NULL) 4667 fclose(sck); 4668 } 4669 #endif /* MAIL_ADMIN */ 4670 4671 if (log_incoming_xfers && (xferlog || syslogmsg)) { 4672 char msg[MAXXFERSTRLEN]; /* see extensions.h */ 4673 int xfertime = time(NULL) - start_time; 4674 size_t msglen; 4675 4676 if (!xfertime) 4677 xfertime++; 4678 4679 /* Gather transfer statistics */ 4680 xfervalues.filename = name; 4681 xfervalues.filesize = st.st_size; 4682 xfervalues.transfer_bytes = byte_count; 4683 xfervalues.transfer_direction = 'i'; 4684 xfervalues.transfer_type = (type == TYPE_A) ? 'a' : 'b'; 4685 xfervalues.transfer_time = xfertime; 4686 xfervalues.restart_offset = restart_point; 4687 strlcpy(xfervalues.special_action, opt_string(0), MAXSPACTCHARS); 4688 xfervalues.access_mode = anonymous ? 'a' : (guest ? 'g' : 'r'); 4689 xfervalues.auth = authenticated; 4690 xfervalues.completion = TransferIncomplete ? 'i' : 'c'; 4691 4692 xferdone = 1; 4693 msg_massage(xferlog_format, msg, sizeof(msg)); 4694 xferdone = 0; 4695 4696 /* Ensure msg always ends with '\n' */ 4697 msglen = strlen(msg); 4698 if (msglen == sizeof(msg) - 1) { 4699 msg[sizeof(msg) - 2] = '\n'; 4700 msg[sizeof(msg) - 1] = '\0'; 4701 } 4702 else { 4703 msg[msglen] = '\n'; 4704 msg[msglen + 1] = '\0'; 4705 } 4706 4707 if (syslogmsg != 1) 4708 write(xferlog, msg, strlen(msg)); 4709 if (syslogmsg != 0) { 4710 char *msgp = msg; 4711 /* 4712 * To preserve the behavior when the xferlog format was fixed, skip 4713 * over the time string if the message starts with the local time. 4714 */ 4715 if (strncmp(xferlog_format, "%T ", 3) == 0) 4716 msgp += 25; 4717 syslog(LOG_INFO, "xferlog (recv): %s", msgp); 4718 } 4719 } 4720 data = -1; 4721 pdata = -1; 4722 done: 4723 (void) fclose(fout); 4724 } 4725 4726 FILE *getdatasock(char *mode) 4727 { 4728 int s, on = 1, tries; 4729 4730 if (data >= 0) 4731 return (fdopen(data, mode)); 4732 port_priv_on(0); 4733 s = socket(SOCK_FAMILY(data_dest), SOCK_STREAM, 0); 4734 if (s < 0) 4735 goto bad; 4736 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 4737 (char *) &on, sizeof(on)) < 0) 4738 goto bad; 4739 if (keepalive) 4740 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)); 4741 if (TCPwindowsize) 4742 (void) setsockopt(s, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF), 4743 (char *) &TCPwindowsize, sizeof(TCPwindowsize)); 4744 /* anchor socket to avoid multi-homing problems */ 4745 #ifdef INET6 4746 if (SOCK_FAMILY(data_dest) == SOCK_FAMILY(ctrl_addr)) 4747 data_source = ctrl_addr; 4748 else if ((SOCK_FAMILY(data_dest) == AF_INET) && ctrl_v4mapped) { 4749 struct sockaddr_in6 *ctrl_sin6 = (struct sockaddr_in6 *)&ctrl_addr; 4750 struct sockaddr_in *data_sin = (struct sockaddr_in *)&data_source; 4751 4752 SET_SOCK_FAMILY(data_source, AF_INET); 4753 memcpy(&data_sin->sin_addr, &ctrl_sin6->sin6_addr.s6_addr[12], 4754 sizeof(struct in_addr)); 4755 } 4756 else { 4757 memset(&data_source, 0, sizeof(struct sockaddr_in6)); 4758 SET_SOCK_FAMILY(data_source, SOCK_FAMILY(data_dest)); 4759 SET_SOCK_ADDR_ANY(data_source); 4760 } 4761 #else 4762 data_source = ctrl_addr; 4763 #endif 4764 SET_SOCK_PORT(data_source, data_port); 4765 4766 #if defined(VIRTUAL) && defined(CANT_BIND) /* can't bind to virtual address */ 4767 SET_SOCK_ADDR_ANY(data_source); 4768 #endif 4769 for (tries = 1;; tries++) { 4770 if (bind(s, (struct sockaddr *) &data_source, SOCK_LEN(data_source)) >= 0) 4771 break; 4772 if (errno != EADDRINUSE || tries > 10) 4773 goto bad; 4774 sleep(tries); 4775 } 4776 #if defined(M_UNIX) && !defined(_M_UNIX) /* bug in old TCP/IP release */ 4777 { 4778 struct linger li; 4779 li.l_onoff = 1; 4780 li.l_linger = 900; 4781 if (setsockopt(s, SOL_SOCKET, SO_LINGER, 4782 (char *) &li, sizeof(struct linger)) < 0) { 4783 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 4784 goto bad; 4785 } 4786 } 4787 #endif 4788 port_priv_off((uid_t) pw->pw_uid); 4789 4790 #ifdef INET6 4791 /* IP_TOS is an IPv4 socket option */ 4792 if (SOCK_FAMILY(data_source) == AF_INET) 4793 #endif 4794 if ((on = IPClassOfService("data")) >= 0) { 4795 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(int)) < 0) 4796 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 4797 } 4798 #ifdef TCP_NOPUSH 4799 /* 4800 * Turn off push flag to keep sender TCP from sending short packets 4801 * at the boundaries of each write(). Should probably do a SO_SNDBUF 4802 * to set the send buffer size as well, but that may not be desirable 4803 * in heavy-load situations. 4804 */ 4805 on = 1; 4806 if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *) &on, sizeof on) < 0) 4807 syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); 4808 #endif 4809 4810 return (fdopen(s, mode)); 4811 bad: 4812 on = errno; /* hold errno for return */ 4813 port_priv_off((uid_t) pw->pw_uid); 4814 if (s != -1) 4815 (void) close(s); 4816 errno = on; 4817 return (NULL); 4818 } 4819 4820 FILE *dataconn(char *name, off_t size, char *mode) 4821 { 4822 char sizebuf[32]; 4823 FILE *file; 4824 int retry = 0; 4825 int on = 1; 4826 int cval, serrno; 4827 int cos; 4828 #ifdef THROUGHPUT 4829 int bps; 4830 double bpsmult; 4831 #endif 4832 4833 file_size = size; 4834 byte_count = 0; 4835 if (size != (off_t) - 1) 4836 (void) sprintf(sizebuf, " (%" L_FORMAT " bytes)", size); 4837 else 4838 (void) strcpy(sizebuf, ""); 4839 if (pdata >= 0) { 4840 struct SOCKSTORAGE from; 4841 char dataaddr[MAXHOSTNAMELEN]; 4842 #if defined(UNIXWARE) || defined(AIX) 4843 size_t fromlen = sizeof(from); 4844 #else 4845 int fromlen = sizeof(from); 4846 #endif 4847 int s; 4848 #ifdef FD_ZERO 4849 int rv; 4850 #endif 4851 4852 if (keepalive) 4853 (void) setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)); 4854 if (TCPwindowsize) 4855 (void) setsockopt(pdata, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF), 4856 (char *) &TCPwindowsize, sizeof(TCPwindowsize)); 4857 #ifdef FD_ZERO 4858 do { 4859 struct timeval timeout; 4860 fd_set set; 4861 4862 FD_ZERO(&set); 4863 FD_SET(pdata, &set); 4864 4865 timeout.tv_usec = 0; 4866 timeout.tv_sec = timeout_accept; 4867 #ifdef HPUX_SELECT 4868 rv = select(pdata + 1, (int *) &set, NULL, NULL, &timeout); 4869 #else 4870 rv = select(pdata + 1, &set, (fd_set *) 0, (fd_set *) 0, 4871 (struct timeval *) &timeout); 4872 #endif 4873 } while ((rv == -1) && (errno == EINTR)); 4874 if ((rv != -1) && (rv != 0)) 4875 s = accept(pdata, (struct sockaddr *) &from, &fromlen); 4876 else 4877 s = -1; 4878 #else /* FD_ZERO */ 4879 (void) signal(SIGALRM, alarm_signal); 4880 alarm(timeout_accept); 4881 s = accept(pdata, (struct sockaddr *) &from, &fromlen); 4882 alarm(0); 4883 #endif 4884 if (s == -1) { 4885 reply(425, "Can't open data connection."); 4886 (void) close(pdata); 4887 pdata = -1; 4888 return (NULL); 4889 } 4890 (void) close(pdata); 4891 pdata = s; 4892 #ifdef INET6 4893 /* IP_TOS is an IPv4 socket option */ 4894 if (SOCK_FAMILY(from) == AF_INET) 4895 #endif 4896 if ((cos = IPClassOfService("data")) >= 0) 4897 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&cos, sizeof(int)); 4898 (void) strncpy(dataaddr, inet_stop(&from), sizeof(dataaddr)); 4899 if (!pasv_allowed(dataaddr)) 4900 if (strcasecmp(dataaddr, remoteaddr) != 0) { 4901 /* 4902 * This will log when data connection comes from an address different 4903 * than the control connection. 4904 */ 4905 #ifdef FIGHT_PASV_PORT_RACE 4906 syslog(LOG_ERR, "%s of %s: data connect from %s for %s%s", 4907 anonymous ? guestpw : pw->pw_name, remoteident, 4908 dataaddr, name, sizebuf); 4909 reply(425, "Possible PASV port theft, cannot open data connection."); 4910 (void) close(pdata); 4911 pdata = -1; 4912 return (NULL); 4913 #else 4914 syslog(LOG_NOTICE, "%s of %s: data connect from %s for %s%s", 4915 anonymous ? guestpw : pw->pw_name, remoteident, 4916 dataaddr, name, sizebuf); 4917 #endif 4918 } 4919 #ifdef THROUGHPUT 4920 throughput_calc(name, &bps, &bpsmult); 4921 if (bps != -1) { 4922 lreply(150, "Opening %s mode data connection for %s%s.", 4923 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 4924 reply(150, "Restricting network throughput to %d bytes/s.", bps); 4925 } 4926 else 4927 #endif 4928 reply(150, "Opening %s mode data connection for %s%s.", 4929 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 4930 return (fdopen(pdata, mode)); 4931 } 4932 if (data >= 0) { 4933 reply(125, "Using existing data connection for %s%s.", 4934 name, sizebuf); 4935 usedefault = 1; 4936 return (fdopen(data, mode)); 4937 } 4938 if (usedefault) 4939 data_dest = his_addr; 4940 if (SOCK_PORT(data_dest) == 0) { 4941 reply(500, "Can't build data connection: no PORT specified"); 4942 return (NULL); 4943 } 4944 usedefault = 1; 4945 do { 4946 file = getdatasock(mode); 4947 if (file == NULL) { 4948 reply(425, "Can't create data socket (%s,%d): %s.", 4949 inet_stop(&data_source), ntohs(SOCK_PORT(data_source)), 4950 strerror(errno)); 4951 return (NULL); 4952 } 4953 data = fileno(file); 4954 (void) signal(SIGALRM, alarm_signal); 4955 alarm(timeout_connect); 4956 cval = connect(data, (struct sockaddr *) &data_dest, 4957 SOCK_LEN(data_dest)); 4958 serrno = errno; 4959 alarm(0); 4960 if (cval == -1) { 4961 /* 4962 * When connect fails, the state of the socket is unspecified so 4963 * it should be closed and a new socket created for each connection 4964 * attempt. This also prevents denial of service problems when 4965 * running on operating systems that only allow one non-connected 4966 * socket bound to the same local address. 4967 */ 4968 (void) fclose(file); 4969 data = -1; 4970 errno = serrno; 4971 if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) { 4972 sleep((unsigned) swaitint); 4973 retry += swaitint; 4974 } 4975 else { 4976 perror_reply(425, "Can't build data connection"); 4977 return (NULL); 4978 } 4979 } 4980 } while (cval == -1); 4981 if (keepalive) 4982 (void) setsockopt(data, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)); 4983 if (TCPwindowsize) 4984 (void) setsockopt(data, SOL_SOCKET, (*mode == 'w' ? SO_SNDBUF : SO_RCVBUF), 4985 (char *) &TCPwindowsize, sizeof(TCPwindowsize)); 4986 #ifdef THROUGHPUT 4987 throughput_calc(name, &bps, &bpsmult); 4988 if (bps != -1) { 4989 lreply(150, "Opening %s mode data connection for %s%s.", 4990 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 4991 reply(150, "Restricting network throughput to %d bytes/s.", bps); 4992 } 4993 else 4994 #endif 4995 reply(150, "Opening %s mode data connection for %s%s.", 4996 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); 4997 return (file); 4998 } 4999 5000 /* Tranfer the contents of "instr" to "outstr" peer using the appropriate 5001 * encapsulation of the data subject to Mode, Structure, and Type. 5002 * 5003 * NB: Form isn't handled. */ 5004 5005 int 5006 #ifdef THROUGHPUT 5007 send_data(char *name, FILE *instr, FILE *outstr, size_t blksize) 5008 #else 5009 send_data(FILE *instr, FILE *outstr, size_t blksize) 5010 #endif 5011 { 5012 register int c, cnt = 0; 5013 static char *buf; 5014 int netfd, filefd; 5015 #ifdef THROUGHPUT 5016 int bps; 5017 double bpsmult; 5018 time_t t1, t2; 5019 #endif 5020 #ifdef SENDFILE 5021 int use_sf = 0; 5022 size_t xferred; 5023 struct stat st; 5024 struct sendfilevec sfv; 5025 #endif 5026 5027 buf = NULL; 5028 if (wu_setjmp(urgcatch)) { 5029 draconian_FILE = NULL; 5030 alarm(0); 5031 transflag = 0; 5032 #ifdef SIGPIPE 5033 (void) signal(SIGPIPE, lostconn); 5034 #endif 5035 if (buf) 5036 (void) free(buf); 5037 retrieve_is_data = 1; 5038 return (0); 5039 } 5040 transflag++; 5041 5042 #ifdef THROUGHPUT 5043 throughput_calc(name, &bps, &bpsmult); 5044 #endif 5045 5046 switch (type) { 5047 5048 case TYPE_A: 5049 #ifdef SIGPIPE 5050 /* 5051 * Ignore SIGPIPE while sending data, necessary so lostconn() isn't 5052 * called if we write to the data connection after the client has 5053 * closed it. 5054 */ 5055 (void) signal(SIGPIPE, SIG_IGN); 5056 #endif 5057 draconian_FILE = outstr; 5058 (void) signal(SIGALRM, draconian_alarm_signal); 5059 alarm(timeout_data); 5060 #ifdef THROUGHPUT 5061 if (bps != -1) 5062 t1 = time(NULL); 5063 #endif 5064 while ((draconian_FILE != NULL) && ((c = getc(instr)) != EOF)) { 5065 if (++byte_count % 4096 == 0) 5066 alarm(timeout_data); 5067 if (c == '\n') { 5068 if (ferror(outstr)) 5069 goto data_err; 5070 if (++byte_count % 4096 == 0) 5071 alarm(timeout_data); 5072 #if defined(USE_GSS) 5073 if (sec_putc('\r', outstr) != '\r') 5074 goto data_err; 5075 #else 5076 (void) putc('\r', outstr); 5077 #endif 5078 #ifdef TRANSFER_COUNT 5079 if (retrieve_is_data) { 5080 data_count_total++; 5081 data_count_out++; 5082 } 5083 byte_count_total++; 5084 byte_count_out++; 5085 #endif 5086 } 5087 #if defined(USE_GSS) 5088 if (sec_putc(c, outstr) != c) 5089 goto data_err; 5090 #else 5091 (void) putc(c, outstr); 5092 #endif 5093 5094 #ifdef TRANSFER_COUNT 5095 if (retrieve_is_data) { 5096 data_count_total++; 5097 data_count_out++; 5098 } 5099 byte_count_total++; 5100 byte_count_out++; 5101 #endif 5102 #ifdef THROUGHPUT 5103 if (bps > 0 && (byte_count % bps) == 0) { 5104 t2 = time(NULL); 5105 if (t2 == t1) 5106 sleep(1); 5107 t1 = time(NULL); 5108 } 5109 #endif 5110 } 5111 #ifdef THROUGHPUT 5112 if (bps != -1) 5113 throughput_adjust(name); 5114 #endif 5115 if (draconian_FILE != NULL) { 5116 alarm(timeout_data); 5117 #if defined(USE_GSS) 5118 if (sec_fflush(outstr) < 0) 5119 goto data_err; 5120 #else 5121 fflush(outstr); 5122 #endif /* defined(USE_GSS) */ 5123 } 5124 if (draconian_FILE != NULL) { 5125 alarm(timeout_data); 5126 socket_flush_wait(outstr); 5127 } 5128 transflag = 0; 5129 if (ferror(instr)) 5130 goto file_err; 5131 if ((draconian_FILE == NULL) || ferror(outstr)) 5132 goto data_err; 5133 draconian_FILE = NULL; 5134 alarm(0); 5135 #ifdef SIGPIPE 5136 (void) signal(SIGPIPE, lostconn); 5137 #endif 5138 reply(226, "Transfer complete."); 5139 #ifdef TRANSFER_COUNT 5140 if (retrieve_is_data) { 5141 file_count_total++; 5142 file_count_out++; 5143 } 5144 xfer_count_total++; 5145 xfer_count_out++; 5146 #endif 5147 retrieve_is_data = 1; 5148 return (1); 5149 5150 case TYPE_I: 5151 case TYPE_L: 5152 #ifdef THROUGHPUT 5153 if (bps != -1) 5154 blksize = bps; 5155 #endif 5156 netfd = fileno(outstr); 5157 filefd = fileno(instr); 5158 #ifdef SENDFILE 5159 /* check the input file is a regular file */ 5160 if ((fstat(filefd, &st) == 0) && ((st.st_mode & S_IFMT) == S_IFREG)) { 5161 #if defined(USE_GSS) 5162 if (gss_info.data_prot == PROT_C || !IS_GSSAUTH(cur_auth_type) || 5163 !(gss_info.authstate & GSS_ADAT_DONE)) 5164 #endif /* defined(USE_GSS) */ 5165 { 5166 use_sf = 1; 5167 /* 5168 * Use a private sfv_flag SFV_NOWAIT to tell sendfilev(), 5169 * when zero-copy is enabled, not to wait for all data to be 5170 * ACKed before returning. This is important for throughput 5171 * performance when sendfilev() is called to send small piece 5172 * at a time. 5173 */ 5174 sfv.sfv_flag = SFV_NOWAIT; 5175 sfv.sfv_fd = filefd; 5176 sfv.sfv_off = restart_point; 5177 sfv.sfv_len = blksize; 5178 } 5179 } 5180 if (use_sf == 0) 5181 #endif 5182 if ((buf = (char *) malloc(blksize)) == NULL) { 5183 transflag = 0; 5184 perror_reply(451, "Local resource failure: malloc"); 5185 retrieve_is_data = 1; 5186 return (0); 5187 } 5188 #ifdef SIGPIPE 5189 /* 5190 * Ignore SIGPIPE while sending data, necessary so lostconn() isn't 5191 * called if we write to the data connection after the client has 5192 * closed it. 5193 */ 5194 (void) signal(SIGPIPE, SIG_IGN); 5195 #endif 5196 draconian_FILE = outstr; 5197 (void) signal(SIGALRM, draconian_alarm_signal); 5198 alarm(timeout_data); 5199 #ifdef THROUGHPUT 5200 if (bps != -1) 5201 t1 = time(NULL); 5202 #endif 5203 while ((draconian_FILE != NULL) && ( 5204 #ifdef SENDFILE 5205 (use_sf && (cnt = sendfilev(netfd, &sfv, 1, &xferred)) > 0) 5206 || (!use_sf && 5207 #endif 5208 ((cnt = read(filefd, buf, blksize)) > 0 && 5209 #if defined(USE_GSS) 5210 sec_write(netfd, buf, cnt) == cnt) 5211 #else 5212 write(netfd, buf, cnt) == cnt) 5213 #endif /* defined(USE_GSS) */ 5214 #ifdef SENDFILE 5215 ) 5216 #endif 5217 )) { 5218 alarm(timeout_data); 5219 #ifdef SENDFILE 5220 sfv.sfv_off += cnt; 5221 #endif 5222 byte_count += cnt; 5223 #ifdef TRANSFER_COUNT 5224 if (retrieve_is_data) { 5225 #ifdef RATIO 5226 if( freefile ) { 5227 total_free_dl += cnt; 5228 } 5229 #endif /* RATIO */ 5230 data_count_total += cnt; 5231 data_count_out += cnt; 5232 } 5233 byte_count_total += cnt; 5234 byte_count_out += cnt; 5235 #endif 5236 #ifdef THROUGHPUT 5237 if (bps != -1) { 5238 t2 = time(NULL); 5239 if (t2 == t1) 5240 sleep(1); 5241 t1 = time(NULL); 5242 } 5243 #endif /* THROUGHPUT */ 5244 } 5245 #ifdef THROUGHPUT 5246 if (bps != -1) 5247 throughput_adjust(name); 5248 #endif 5249 #if defined(USE_GSS) 5250 if (sec_fflush(outstr) < 0) 5251 goto data_err; 5252 #endif 5253 transflag = 0; 5254 if (buf) 5255 (void) free(buf); 5256 if (draconian_FILE != NULL) { 5257 alarm(timeout_data); 5258 socket_flush_wait(outstr); 5259 } 5260 if (cnt != 0) { 5261 #ifdef SENDFILE 5262 if (use_sf && cnt < 0 && errno == EPIPE) 5263 goto data_err; 5264 #endif 5265 if (cnt < 0) 5266 goto file_err; 5267 goto data_err; 5268 } 5269 if (draconian_FILE == NULL) 5270 goto data_err; 5271 draconian_FILE = NULL; 5272 alarm(0); 5273 #ifdef SIGPIPE 5274 (void) signal(SIGPIPE, lostconn); 5275 #endif 5276 reply(226, "Transfer complete."); 5277 #ifdef TRANSFER_COUNT 5278 if (retrieve_is_data) { 5279 file_count_total++; 5280 file_count_out++; 5281 } 5282 xfer_count_total++; 5283 xfer_count_out++; 5284 #endif 5285 retrieve_is_data = 1; 5286 return (1); 5287 default: 5288 transflag = 0; 5289 reply(550, "Unimplemented TYPE %d in send_data", type); 5290 retrieve_is_data = 1; 5291 return (0); 5292 } 5293 5294 data_err: 5295 draconian_FILE = NULL; 5296 alarm(0); 5297 transflag = 0; 5298 #ifdef SIGPIPE 5299 (void) signal(SIGPIPE, lostconn); 5300 #endif 5301 perror_reply(426, "Data connection"); 5302 retrieve_is_data = 1; 5303 return (0); 5304 5305 file_err: 5306 draconian_FILE = NULL; 5307 alarm(0); 5308 transflag = 0; 5309 #ifdef SIGPIPE 5310 (void) signal(SIGPIPE, lostconn); 5311 #endif 5312 perror_reply(551, "Error on input file"); 5313 retrieve_is_data = 1; 5314 return (0); 5315 } 5316 5317 /* Transfer data from peer to "outstr" using the appropriate encapulation of 5318 * the data subject to Mode, Structure, and Type. 5319 * 5320 * N.B.: Form isn't handled. */ 5321 5322 int receive_data(FILE *instr, FILE *outstr) 5323 { 5324 register int c; 5325 int rcnt = 0, n = 0, bare_lfs = 0; 5326 static char *buf; 5327 int netfd, filefd, wcnt; 5328 #ifdef BUFFER_SIZE 5329 size_t buffer_size = BUFFER_SIZE; 5330 #else 5331 size_t buffer_size = BUFSIZ * 16; 5332 #endif 5333 5334 buf = NULL; 5335 if (wu_setjmp(urgcatch)) { 5336 alarm(0); 5337 transflag = 0; 5338 if (buf) 5339 (void) free(buf); 5340 return (-1); 5341 } 5342 transflag++; 5343 switch (type) { 5344 5345 case TYPE_I: 5346 case TYPE_L: 5347 #if defined(USE_GSS) 5348 if (GSSUSERAUTH_OK(gss_info)) 5349 buffer_size = gss_getinbufsz(); 5350 else 5351 #endif 5352 if (recvbufsz > 0) 5353 buffer_size = recvbufsz; 5354 if ((buf = (char *) malloc(buffer_size)) == NULL) { 5355 transflag = 0; 5356 perror_reply(451, "Local resource failure: malloc"); 5357 return (-1); 5358 } 5359 netfd = fileno(instr); 5360 filefd = fileno(outstr); 5361 draconian_FILE = instr; 5362 (void) signal(SIGALRM, draconian_alarm_signal); 5363 alarm(timeout_data); 5364 5365 while ((draconian_FILE != NULL) && 5366 #if defined(USE_GSS) 5367 (rcnt = sec_read(netfd, buf, buffer_size)) > 0) { 5368 #else 5369 (rcnt = read(netfd, buf, buffer_size)) > 0) { 5370 #endif 5371 for (wcnt = 0; wcnt < rcnt; wcnt += n) { 5372 if ((n = write(filefd, &buf[wcnt], rcnt - wcnt)) == -1) 5373 break; 5374 } 5375 byte_count += wcnt; 5376 #ifdef TRANSFER_COUNT 5377 data_count_total += wcnt; 5378 data_count_in += wcnt; 5379 byte_count_total += wcnt; 5380 byte_count_in += wcnt; 5381 #endif 5382 if (n == -1) 5383 break; 5384 alarm(timeout_data); 5385 } 5386 transflag = 0; 5387 (void) free(buf); 5388 if ((rcnt == -1) || (draconian_FILE == NULL)) 5389 goto data_err; 5390 if (n == -1) 5391 goto file_err; 5392 draconian_FILE = NULL; 5393 alarm(0); 5394 #ifdef TRANSFER_COUNT 5395 file_count_total++; 5396 file_count_in++; 5397 xfer_count_total++; 5398 xfer_count_in++; 5399 #endif 5400 return (0); 5401 5402 case TYPE_E: 5403 reply(553, "TYPE E not implemented."); 5404 transflag = 0; 5405 return (-1); 5406 5407 case TYPE_A: 5408 draconian_FILE = instr; 5409 (void) signal(SIGALRM, draconian_alarm_signal); 5410 alarm(timeout_data); 5411 while ((draconian_FILE != NULL) && 5412 #if defined(USE_GSS) 5413 ((c = sec_getc(instr)) != EOF) 5414 #else 5415 ((c = getc(instr)) != EOF) 5416 #endif 5417 ) { 5418 if (++byte_count % 4096 == 0) 5419 alarm(timeout_data); 5420 if (c == '\n') 5421 bare_lfs++; 5422 while (c == '\r') { 5423 if (ferror(outstr)) 5424 goto file_err; 5425 alarm(timeout_data); 5426 if (draconian_FILE != NULL) { 5427 #if defined(USE_GSS) 5428 if ((c = sec_getc(instr)) != '\n') 5429 #else 5430 if ((c = getc(instr)) != '\n') 5431 #endif 5432 (void) putc('\r', outstr); 5433 #ifdef TRANSFER_COUNT 5434 data_count_total++; 5435 data_count_in++; 5436 byte_count_total++; 5437 byte_count_in++; 5438 #endif 5439 if (c == EOF) /* null byte fix, noid@cyborg.larc.nasa.gov */ 5440 goto contin2; 5441 if (++byte_count % 4096 == 0) 5442 alarm(timeout_data); 5443 } 5444 } 5445 (void) putc(c, outstr); 5446 #ifdef TRANSFER_COUNT 5447 data_count_total++; 5448 data_count_in++; 5449 byte_count_total++; 5450 byte_count_in++; 5451 #endif 5452 contin2:; 5453 } 5454 fflush(outstr); 5455 if ((draconian_FILE == NULL) || ferror(instr)) 5456 goto data_err; 5457 if (ferror(outstr)) 5458 goto file_err; 5459 transflag = 0; 5460 draconian_FILE = NULL; 5461 alarm(0); 5462 if (bare_lfs) { 5463 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); 5464 lreply(0, " File may not have transferred correctly."); 5465 } 5466 #ifdef TRANSFER_COUNT 5467 file_count_total++; 5468 file_count_in++; 5469 xfer_count_total++; 5470 xfer_count_in++; 5471 #endif 5472 return (0); 5473 default: 5474 reply(550, "Unimplemented TYPE %d in receive_data", type); 5475 transflag = 0; 5476 return (-1); 5477 } 5478 5479 data_err: 5480 draconian_FILE = NULL; 5481 alarm(0); 5482 transflag = 0; 5483 perror_reply(426, "Data Connection"); 5484 return (-1); 5485 5486 file_err: 5487 draconian_FILE = NULL; 5488 alarm(0); 5489 transflag = 0; 5490 perror_reply(452, "Error writing file"); 5491 return (-1); 5492 } 5493 5494 void statfilecmd(char *filename) 5495 { 5496 #ifndef INTERNAL_LS 5497 char line[BUFSIZ * 2], *ptr; 5498 FILE *fin; 5499 int c; 5500 #endif /* ! INTERNAL_LS */ 5501 5502 fixpath(filename); 5503 if (filename[0] == '\0') 5504 filename = "."; 5505 #ifndef INTERNAL_LS 5506 if (anonymous && dolreplies) 5507 (void) snprintf(line, sizeof(line), ls_long, filename); 5508 else 5509 (void) snprintf(line, sizeof(line), ls_short, filename); 5510 fin = ftpd_popen(line, "r", 0); 5511 #endif /* ! INTERNAL_LS */ 5512 lreply(213, "status of %s:", filename); 5513 #ifndef INTERNAL_LS 5514 /* 5515 while ((c = getc(fin)) != EOF) { 5516 if (c == '\n') { 5517 if (ferror(stdout)) { 5518 perror_reply(421, "control connection"); 5519 (void) ftpd_pclose(fin); 5520 dologout(1); 5521 / * NOTREACHED * / 5522 } 5523 if (ferror(fin)) { 5524 perror_reply(551, filename); 5525 (void) ftpd_pclose(fin); 5526 return; 5527 } 5528 (void) putc('\r', stdout); 5529 } 5530 (void) putc(c, stdout); 5531 } 5532 */ 5533 while (fgets(line, sizeof(line), fin) != NULL) { 5534 if ((ptr = strchr(line, '\n'))) /* clip out unnecessary newline */ 5535 *ptr = '\0'; 5536 lreply(0, "%s", line); 5537 } 5538 (void) ftpd_pclose(fin); 5539 #else /* INTERNAL_LS */ 5540 ls_dir(filename, 1, 0, 1, 0, 1, stdout); 5541 #endif /* INTERNAL_LS */ 5542 reply(213, "End of Status"); 5543 } 5544 5545 void statcmd(void) 5546 { 5547 struct SOCKSTORAGE *sin; 5548 u_char *a, *p; 5549 unsigned short port; 5550 #ifdef INET6 5551 int isv4 = 0; 5552 #endif 5553 5554 lreply(211, "%s FTP server status:", hostname); 5555 lreply(0, " %s", version); 5556 if (nameserved) 5557 lreply(0, " Connected to %s (%s)", remotehost, remoteaddr); 5558 else 5559 lreply(0, " Connected to %s", remotehost); 5560 5561 if (logged_in) { 5562 if (anonymous) 5563 lreply(0, " Logged in anonymously"); 5564 else 5565 lreply(0, " Logged in as %s", pw->pw_name); 5566 } 5567 else if (askpasswd) 5568 lreply(0, " Waiting for password"); 5569 else 5570 lreply(0, " Waiting for user name"); 5571 5572 if (type == TYPE_L) 5573 #ifdef NBBY 5574 lreply(0, " TYPE: %s %d; STRUcture: %s; transfer MODE: %s", 5575 typenames[type], NBBY, strunames[stru], modenames[mode]); 5576 #else 5577 lreply(0, " TYPE: %s %d; STRUcture: %s; transfer MODE: %s", 5578 typenames[type], bytesize, strunames[stru], modenames[mode]); 5579 #endif /* NBBY */ 5580 else 5581 lreply(0, " TYPE: %s%s%s; STRUcture: %s; transfer MODE: %s", 5582 typenames[type], (type == TYPE_A || type == TYPE_E) ? 5583 ", FORM: " : "", (type == TYPE_A || type == TYPE_E) ? 5584 formnames[form] : "", strunames[stru], modenames[mode]); 5585 if (data != -1) 5586 lreply(0, " Data connection open"); 5587 else if (pdata != -1 || usedefault == 0) { 5588 if (usedefault == 0) { 5589 sin = &data_dest; 5590 port = SOCK_PORT(data_dest); 5591 } 5592 else { 5593 port = SOCK_PORT(pasv_addr); 5594 if (route_vectored) 5595 sin = &vect_addr; 5596 else 5597 sin = &pasv_addr; 5598 } 5599 a = (u_char *) SOCK_ADDR(*sin); 5600 p = (u_char *) &port; 5601 #define UC(b) (((int) b) & 0xff) 5602 #ifdef INET6 5603 if (SOCK_FAMILY(*sin) == AF_INET) 5604 isv4 = 1; 5605 else if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sin)->sin6_addr)) 5606 { 5607 isv4 = 1; 5608 a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */ 5609 } 5610 if (epsv_all) 5611 lreply(0, " EPSV only mode (EPSV ALL)"); 5612 if (isv4 && !epsv_all) 5613 #endif 5614 lreply(0, " %s (%d,%d,%d,%d,%d,%d)", 5615 usedefault == 0 ? "PORT" : "PASV", 5616 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 5617 #ifdef INET6 5618 lreply(0, " %s (|%d|%s|%d|)", usedefault == 0 ? "EPRT" : "EPSV", 5619 isv4 ? 1 : 2, inet_stop(sin), ntohs(port)); 5620 if (!epsv_all) 5621 if (isv4) 5622 lreply(0, " %s (4,4,%d,%d,%d,%d,2,%d,%d)", 5623 usedefault == 0 ? "LPRT" : "LPSV", 5624 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 5625 UC(p[0]), UC(p[1])); 5626 else 5627 lreply(0, " %s (6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," 5628 "%d,%d,%d,%d,2,%d,%d)", 5629 usedefault == 0 ? "LPRT" : "LPSV", 5630 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 5631 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 5632 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 5633 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 5634 UC(p[0]), UC(p[1])); 5635 #endif 5636 #undef UC 5637 } 5638 else 5639 lreply(0, " No data connection"); 5640 #ifdef TRANSFER_COUNT 5641 lreply(0, " %" L_FORMAT " data bytes received in %d files", data_count_in, file_count_in); 5642 lreply(0, " %" L_FORMAT " data bytes transmitted in %d files", data_count_out, file_count_out); 5643 lreply(0, " %" L_FORMAT " data bytes total in %d files", data_count_total, file_count_total); 5644 lreply(0, " %" L_FORMAT " traffic bytes received in %d transfers", byte_count_in, xfer_count_in); 5645 lreply(0, " %" L_FORMAT " traffic bytes transmitted in %d transfers", byte_count_out, xfer_count_out); 5646 lreply(0, " %" L_FORMAT " traffic bytes total in %d transfers", byte_count_total, xfer_count_total); 5647 #endif 5648 reply(211, "End of status"); 5649 } 5650 5651 void fatal(char *s) 5652 { 5653 reply(451, "Error in server: %s\n", s); 5654 reply(221, "Closing connection due to server error."); 5655 dologout(0); 5656 /* NOTREACHED */ 5657 } 5658 5659 #define USE_REPLY_NOTFMT (1<<1) /* fmt is not a printf fmt (KLUDGE) */ 5660 #define USE_REPLY_LONG (1<<2) /* this is a long reply; use a - */ 5661 5662 void vreply(long flags, int n, char *fmt, va_list ap) 5663 { 5664 char buf[BUFSIZ * 16]; 5665 5666 flags &= USE_REPLY_NOTFMT | USE_REPLY_LONG; 5667 5668 if (n) /* if numeric is 0, don't output one; use n==0 in place of printf's */ 5669 sprintf(buf, "%03d%c", n, flags & USE_REPLY_LONG ? '-' : ' '); 5670 5671 /* This is somewhat of a kludge for autospout. I personally think that 5672 * autospout should be done differently, but that's not my department. -Kev 5673 */ 5674 if (flags & USE_REPLY_NOTFMT) 5675 snprintf(buf + (n ? 4 : 0), n ? sizeof(buf) - 4 : sizeof(buf), "%s", fmt); 5676 else 5677 vsnprintf(buf + (n ? 4 : 0), n ? sizeof(buf) - 4 : sizeof(buf), fmt, ap); 5678 5679 #if defined(USE_GSS) 5680 if (IS_GSSAUTH(cur_auth_type) && 5681 (gss_info.authstate & GSS_ADAT_DONE) && 5682 gss_info.ctrl_prot != PROT_C) { 5683 if (buf[strlen(buf)-1] != '\n') 5684 strlcat(buf, "\r\n", sizeof(buf)); 5685 (void) sec_reply(buf, sizeof(buf), n); 5686 } 5687 #endif 5688 5689 if (debug) /* debugging output :) */ 5690 syslog(LOG_DEBUG, "<--- %s", buf); 5691 5692 /* Yes, you want the debugging output before the client output; wrapping 5693 * stuff goes here, you see, and you want to log the cleartext and send 5694 * the wrapped text to the client. 5695 */ 5696 5697 printf("%s\r\n", buf); /* and send it to the client */ 5698 #ifdef TRANSFER_COUNT 5699 byte_count_total += strlen(buf); 5700 byte_count_out += strlen(buf); 5701 #endif 5702 /* 5703 * We dont need to worry about "sec_fflush" here since "sec_reply" 5704 * already wrapped the reply if necessary. 5705 */ 5706 fflush(stdout); 5707 } 5708 5709 void reply(int n, char *fmt,...) 5710 { 5711 VA_LOCAL_DECL 5712 5713 if (autospout != NULL) { /* deal with the autospout stuff... */ 5714 char *p, *ptr = autospout; 5715 5716 while (*ptr) { 5717 if ((p = strchr(ptr, '\n')) != NULL) /* step through line by line */ 5718 *p = '\0'; 5719 5720 /* send a line...(note that this overrides dolreplies!) */ 5721 vreply(USE_REPLY_LONG | USE_REPLY_NOTFMT, n, ptr, ap); 5722 5723 if (p) 5724 ptr = p + 1; /* set to the next line... (\0 is handled in the while) */ 5725 else 5726 break; /* oh, we're done; drop out of the loop */ 5727 } 5728 5729 if (autospout_free) { /* free autospout if necessary */ 5730 (void) free(autospout); 5731 autospout_free = 0; 5732 } 5733 autospout = 0; /* clear the autospout */ 5734 } 5735 5736 VA_START(fmt); 5737 5738 /* send the reply */ 5739 vreply(0L, n, fmt, ap); 5740 5741 VA_END; 5742 } 5743 5744 void lreply(int n, char *fmt,...) 5745 { 5746 VA_LOCAL_DECL 5747 5748 if (!dolreplies) /* prohibited from doing long replies? */ 5749 return; 5750 5751 VA_START(fmt); 5752 5753 /* send the reply */ 5754 vreply(USE_REPLY_LONG, n, fmt, ap); 5755 5756 VA_END; 5757 } 5758 5759 void ack(char *s) 5760 { 5761 reply(250, "%s command successful.", s); 5762 } 5763 5764 void nack(char *s) 5765 { 5766 reply(502, "%s command not implemented.", s); 5767 } 5768 5769 void yyerror(char *s) 5770 { 5771 char *cp; 5772 if (s == NULL || yyerrorcalled != 0) 5773 return; 5774 if ((cp = strchr(cbuf, '\n')) != NULL) 5775 *cp = '\0'; 5776 reply(500, "'%s': command not understood.", cbuf); 5777 yyerrorcalled = 1; 5778 return; 5779 } 5780 5781 void delete(char *name) 5782 { 5783 struct stat st; 5784 char realname[MAXPATHLEN]; 5785 5786 /* 5787 * delete permission? 5788 */ 5789 5790 wu_realpath(name, realname, chroot_path); 5791 5792 if ((del_check(name)) == 0) { 5793 if (log_security) 5794 if (anonymous) 5795 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete %s", 5796 guestpw, remoteident, realname); 5797 else 5798 syslog(LOG_NOTICE, "%s of %s tried to delete %s", 5799 pw->pw_name, remoteident, realname); 5800 return; 5801 } 5802 5803 if (lstat(name, &st) < 0) { 5804 perror_reply(550, name); 5805 return; 5806 } 5807 if ((st.st_mode & S_IFMT) == S_IFDIR) { 5808 uid_t uid; 5809 gid_t gid; 5810 int d_mode; 5811 int valid; 5812 5813 /* 5814 * check the directory, can we rmdir here? 5815 */ 5816 if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) { 5817 if (log_security) 5818 if (anonymous) 5819 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete directory %s", 5820 guestpw, remoteident, realname); 5821 else 5822 syslog(LOG_NOTICE, "%s of %s tried to delete directory %s", 5823 pw->pw_name, remoteident, realname); 5824 return; 5825 } 5826 5827 if (rmdir(name) < 0) { 5828 if (log_security) 5829 if (anonymous) 5830 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete directory %s (permissions)", 5831 guestpw, remoteident, realname); 5832 else 5833 syslog(LOG_NOTICE, "%s of %s tried to delete directory %s (permissions)", 5834 pw->pw_name, remoteident, realname); 5835 perror_reply(550, name); 5836 return; 5837 } 5838 goto done; 5839 } 5840 if (unlink(name) < 0) { 5841 if (log_security) 5842 if (anonymous) 5843 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to delete %s (permissions)", 5844 guestpw, remoteident, realname); 5845 else 5846 syslog(LOG_NOTICE, "%s of %s tried to delete %s (permissions)", 5847 pw->pw_name, remoteident, realname); 5848 perror_reply(550, name); 5849 return; 5850 } 5851 done: 5852 { 5853 char path[MAXPATHLEN]; 5854 5855 wu_realpath(name, path, chroot_path); 5856 5857 if (log_security) 5858 if ((st.st_mode & S_IFMT) == S_IFDIR) 5859 if (anonymous) { 5860 syslog(LOG_NOTICE, "%s of %s deleted directory %s", guestpw, remoteident, path); 5861 } 5862 else { 5863 syslog(LOG_NOTICE, "%s of %s deleted directory %s", pw->pw_name, 5864 remoteident, path); 5865 } 5866 else if (anonymous) { 5867 syslog(LOG_NOTICE, "%s of %s deleted %s", guestpw, 5868 remoteident, path); 5869 } 5870 else { 5871 syslog(LOG_NOTICE, "%s of %s deleted %s", pw->pw_name, 5872 remoteident, path); 5873 } 5874 } 5875 5876 ack("DELE"); 5877 } 5878 5879 void cwd(char *path) 5880 { 5881 struct aclmember *entry = NULL; 5882 char cdpath[MAXPATHLEN]; 5883 5884 if (chdir(path) < 0) { 5885 /* alias checking */ 5886 while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) { 5887 if (!strcasecmp(ARG0, path)) { 5888 if (chdir(ARG1) < 0) 5889 perror_reply(550, path); 5890 else { 5891 show_message(250, C_WD); 5892 show_readme(250, C_WD); 5893 ack("CWD"); 5894 } 5895 return; 5896 } 5897 } 5898 /* check for "cdpath" directories. */ 5899 entry = (struct aclmember *) NULL; 5900 while (getaclentry("cdpath", &entry) && ARG0 != NULL) { 5901 snprintf(cdpath, sizeof cdpath, "%s/%s", ARG0, path); 5902 if (chdir(cdpath) >= 0) { 5903 show_message(250, C_WD); 5904 show_readme(250, C_WD); 5905 ack("CWD"); 5906 return; 5907 } 5908 } 5909 perror_reply(550, path); 5910 } 5911 else { 5912 show_message(250, C_WD); 5913 show_readme(250, C_WD); 5914 ack("CWD"); 5915 } 5916 } 5917 5918 void makedir(char *name) 5919 { 5920 uid_t uid; 5921 gid_t gid; 5922 int d_mode; 5923 mode_t oldumask; 5924 int valid; 5925 int ret, serrno; 5926 uid_t oldid; 5927 char path[MAXPATHLEN + 1]; /* for realpath() later - cky */ 5928 char realname[MAXPATHLEN]; 5929 5930 wu_realpath(name, realname, chroot_path); 5931 /* 5932 * check the directory, can we mkdir here? 5933 */ 5934 if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) { 5935 if (log_security) 5936 if (anonymous) 5937 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s", 5938 guestpw, remoteident, realname); 5939 else 5940 syslog(LOG_NOTICE, "%s of %s tried to create directory %s", 5941 pw->pw_name, remoteident, realname); 5942 return; 5943 } 5944 5945 /* 5946 * check the filename, is it legal? 5947 */ 5948 if ((fn_check(name)) <= 0) { 5949 if (log_security) 5950 if (anonymous) 5951 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (path-filter)", 5952 guestpw, remoteident, realname); 5953 else 5954 syslog(LOG_NOTICE, "%s of %s tried to create directory %s (path-filter)", 5955 pw->pw_name, remoteident, realname); 5956 return; 5957 } 5958 5959 oldumask = umask(0000); 5960 if (valid <= 0) { 5961 d_mode = 0777; 5962 umask(oldumask); 5963 } 5964 5965 if (mkdir(name, d_mode) < 0) { 5966 if (errno == EEXIST) { 5967 if (log_security) 5968 if (anonymous) 5969 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (exists)", 5970 guestpw, remoteident, realname); 5971 else 5972 syslog(LOG_NOTICE, "%s of %s tried to create directory %s (exists)", 5973 pw->pw_name, remoteident, realname); 5974 fb_realpath(name, path); 5975 reply(521, "\"%s\" directory exists", path); 5976 } 5977 else { 5978 if (log_security) 5979 if (anonymous) 5980 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to create directory %s (permissions)", 5981 guestpw, remoteident, realname); 5982 else 5983 syslog(LOG_NOTICE, "%s of %s tried to create directory %s (permissions)", 5984 pw->pw_name, remoteident, realname); 5985 perror_reply(550, name); 5986 } 5987 umask(oldumask); 5988 return; 5989 } 5990 umask(oldumask); 5991 if (valid > 0) { 5992 oldid = geteuid(); 5993 if (uid != 0) 5994 (void) seteuid((uid_t) uid); 5995 if ((uid == 0) || ((chown(name, uid, gid)) < 0)) { 5996 chown_priv_on(0); 5997 ret = chown(name, uid, gid); 5998 serrno = errno; 5999 chown_priv_off(oldid); 6000 if (ret < 0) { 6001 errno = serrno; 6002 perror_reply(550, "chown"); 6003 return; 6004 } 6005 } 6006 else 6007 (void) seteuid(oldid); 6008 } 6009 wu_realpath(name, path, chroot_path); 6010 if (log_security) 6011 if (anonymous) { 6012 syslog(LOG_NOTICE, "%s of %s created directory %s", guestpw, remoteident, path); 6013 } 6014 else { 6015 syslog(LOG_NOTICE, "%s of %s created directory %s", pw->pw_name, 6016 remoteident, path); 6017 } 6018 fb_realpath(name, path); 6019 /* According to RFC 959: 6020 * The 257 reply to the MKD command must always contain the 6021 * absolute pathname of the created directory. 6022 * This is implemented here using similar code to the PWD command. 6023 * XXX - still need to do `quote-doubling'. 6024 */ 6025 reply(257, "\"%s\" new directory created.", path); 6026 } 6027 6028 void removedir(char *name) 6029 { 6030 uid_t uid; 6031 gid_t gid; 6032 int d_mode; 6033 int valid; 6034 char realname[MAXPATHLEN]; 6035 6036 wu_realpath(name, realname, chroot_path); 6037 6038 /* 6039 * delete permission? 6040 */ 6041 6042 if ((del_check(name)) == 0) 6043 return; 6044 /* 6045 * check the directory, can we rmdir here? 6046 */ 6047 if ((dir_check(name, &uid, &gid, &d_mode, &valid)) <= 0) { 6048 if (log_security) 6049 if (anonymous) 6050 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to remove directory %s", 6051 guestpw, remoteident, realname); 6052 else 6053 syslog(LOG_NOTICE, "%s of %s tried to remove directory %s", 6054 pw->pw_name, remoteident, realname); 6055 return; 6056 } 6057 6058 if (rmdir(name) < 0) { 6059 if (errno == EBUSY) 6060 perror_reply(450, name); 6061 else { 6062 if (log_security) 6063 if (anonymous) 6064 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to remove directory %s (permissions)", 6065 guestpw, remoteident, realname); 6066 else 6067 syslog(LOG_NOTICE, "%s of %s tried to remove directory %s (permissions)", 6068 pw->pw_name, remoteident, realname); 6069 perror_reply(550, name); 6070 } 6071 } 6072 else { 6073 char path[MAXPATHLEN]; 6074 6075 wu_realpath(name, path, chroot_path); 6076 6077 if (log_security) 6078 if (anonymous) { 6079 syslog(LOG_NOTICE, "%s of %s deleted directory %s", guestpw, remoteident, path); 6080 } 6081 else { 6082 syslog(LOG_NOTICE, "%s of %s deleted directory %s", pw->pw_name, 6083 remoteident, path); 6084 } 6085 ack("RMD"); 6086 } 6087 } 6088 6089 void pwd(void) 6090 { 6091 char path[MAXPATHLEN + 1]; 6092 char rhome[MAXPATHLEN + 1]; 6093 char *rpath = path; /* Path to return to client */ 6094 int pathlen; 6095 #ifndef MAPPING_CHDIR 6096 #ifdef HAVE_GETCWD 6097 extern char *getcwd(); 6098 #else 6099 extern char *getwd(char *); 6100 #endif 6101 #endif /* MAPPING_CHDIR */ 6102 6103 #ifdef HAVE_GETCWD 6104 if (getcwd(path, MAXPATHLEN) == (char *) NULL) 6105 #else 6106 if (getwd(path) == (char *) NULL) 6107 #endif 6108 /* Dink! If you couldn't get the path and the buffer is now likely to 6109 be undefined, why are you trying to PRINT it?! _H* 6110 reply(550, "%s.", path); */ 6111 { 6112 fb_realpath(".", path); /* realpath_on_steroids can deal */ 6113 } 6114 /* relative to home directory if restricted_user */ 6115 if (restricted_user) { 6116 /* 6117 * Re-adjust real path because previous call to getXwd() did 6118 * not resolve symlink. 6119 */ 6120 fb_realpath(".", path); 6121 fb_realpath(home, rhome); 6122 pathlen = strlen(rhome); 6123 if (pathlen && rhome[pathlen - 1] == '/') 6124 pathlen--; 6125 rpath = rpath + pathlen; 6126 if (!*rpath) 6127 strcpy(rpath, "/"); 6128 } 6129 reply(257, "\"%s\" is current directory.", rpath); 6130 } 6131 6132 char *renamefrom(char *name) 6133 { 6134 struct stat st; 6135 6136 if (lstat(name, &st) < 0) { 6137 perror_reply(550, name); 6138 return ((char *) 0); 6139 } 6140 reply(350, "File exists, ready for destination name"); 6141 return (name); 6142 } 6143 6144 void renamecmd(char *from, char *to) 6145 { 6146 int allowed = (anonymous ? 0 : 1); 6147 char realfrom[MAXPATHLEN]; 6148 char realto[MAXPATHLEN]; 6149 struct aclmember *entry = NULL; 6150 #ifdef PARANOID 6151 struct stat st; 6152 #endif 6153 wu_realpath(from, realfrom, chroot_path); 6154 wu_realpath(to, realto, chroot_path); 6155 /* 6156 * check the filename, is it legal? 6157 */ 6158 if ((fn_check(to)) == 0) { 6159 if (log_security) 6160 if (anonymous) 6161 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to \"%s\" (path-filter)", 6162 guestpw, remoteident, realfrom, realto); 6163 else 6164 syslog(LOG_NOTICE, "%s of %s tried to rename %s to \"%s\" (path-filter)", 6165 pw->pw_name, remoteident, realfrom, realto); 6166 return; 6167 } 6168 6169 /* 6170 * if rename permission denied and file exists... then deny the user 6171 * permission to rename the file. 6172 */ 6173 while (getaclentry("rename", &entry) && ARG0 && ARG1 != NULL) { 6174 if (type_match(ARG1)) 6175 if (anonymous) { 6176 if (*ARG0 == 'y') 6177 allowed = 1; 6178 } 6179 else if (*ARG0 == 'n') 6180 allowed = 0; 6181 } 6182 if (!allowed) { 6183 if (log_security) 6184 if (anonymous) 6185 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s", 6186 guestpw, remoteident, realfrom, realto); 6187 else 6188 syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s", 6189 pw->pw_name, remoteident, realfrom, realto); 6190 reply(553, "%s: Permission denied on server. (rename)", from); 6191 return; 6192 } 6193 6194 6195 #ifdef PARANOID 6196 /* Almost forgot about this. Don't allow renaming TO existing files -- 6197 otherwise someone can rename "trivial" to "warez", and "warez" is gone! 6198 XXX: This part really should do the same "overwrite" check as store(). */ 6199 if (!stat(to, &st)) { 6200 if (log_security) 6201 if (anonymous) 6202 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s", 6203 guestpw, remoteident, realfrom, realto); 6204 else 6205 syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s", 6206 pw->pw_name, remoteident, realfrom, realto); 6207 reply(550, "%s: Permission denied on server. (rename)", to); 6208 return; 6209 } 6210 #endif 6211 if (rename(from, to) < 0) { 6212 if (log_security) 6213 if (anonymous) 6214 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to rename %s to %s", 6215 guestpw, remoteident, realfrom, realto); 6216 else 6217 syslog(LOG_NOTICE, "%s of %s tried to rename %s to %s", 6218 pw->pw_name, remoteident, realfrom, realto); 6219 perror_reply(550, "rename"); 6220 } 6221 else { 6222 char frompath[MAXPATHLEN]; 6223 char topath[MAXPATHLEN]; 6224 6225 wu_realpath(from, frompath, chroot_path); 6226 wu_realpath(to, topath, chroot_path); 6227 6228 if (log_security) 6229 if (anonymous) { 6230 syslog(LOG_NOTICE, "%s of %s renamed %s to %s", guestpw, remoteident, frompath, topath); 6231 } 6232 else { 6233 syslog(LOG_NOTICE, "%s of %s renamed %s to %s", pw->pw_name, 6234 remoteident, frompath, topath); 6235 } 6236 ack("RNTO"); 6237 } 6238 } 6239 6240 void dolog(struct SOCKSTORAGE *sin) 6241 { 6242 char *blah; 6243 int rval; 6244 6245 blah = inet_stop(sin); 6246 (void) strncpy(remoteaddr, blah, sizeof(remoteaddr)); 6247 nameserved = 0; 6248 (void) strncpy(remotehost, remoteaddr, sizeof(remotehost)); 6249 6250 rhlookup = rhostlookup(remoteaddr); 6251 if (rhlookup) { 6252 if (!strcasecmp(remoteaddr, "0.0.0.0")) { 6253 nameserved = 1; 6254 strncpy(remotehost, "localhost", sizeof(remotehost)); 6255 } 6256 else { 6257 #ifdef DNS_TRYAGAIN 6258 int num_dns_tries = 0; 6259 /* 6260 * 27-Apr-93 EHK/BM 6261 * far away connections might take some time to get their IP address 6262 * resolved. That's why we try again -- maybe our DNS cache has the 6263 * PTR-RR now. This code is sloppy. Far better is to check what the 6264 * resolver returned so that in case of error, there's no need to 6265 * try again. 6266 */ 6267 dns_again: 6268 #endif /* DNS_TRYAGAIN */ 6269 6270 rval = wu_gethostbyaddr(sin, remotehost, sizeof(remotehost)); 6271 6272 #ifdef DNS_TRYAGAIN 6273 if (!rval && ++num_dns_tries <= 1) { 6274 sleep(3); 6275 goto dns_again; /* try DNS lookup once more */ 6276 } 6277 #endif /* DNS_TRYAGAIN */ 6278 6279 if (rval) 6280 nameserved = 1; 6281 } 6282 } 6283 6284 remotehost[sizeof(remotehost) - 1] = '\0'; 6285 sprintf(proctitle, "%s: connected", remotehost); 6286 setproctitle("%s", proctitle); 6287 6288 wu_authenticate(); 6289 /* Create a composite source identification string, to improve the logging 6290 * when RFC 931 is being used. */ 6291 { 6292 int n = 20 + strlen(remotehost) + strlen(remoteaddr) + 6293 (authenticated ? strlen(authuser + 5) : 0); 6294 if ((remoteident = malloc(n)) == NULL) { 6295 syslog(LOG_ERR, "malloc: %m"); 6296 #ifndef DEBUG 6297 exit(1); 6298 #endif 6299 } 6300 else if (authenticated) 6301 sprintf(remoteident, "%s @ %s [%s]", 6302 authuser, remotehost, remoteaddr); 6303 else 6304 sprintf(remoteident, "%s [%s]", remotehost, remoteaddr); 6305 } 6306 #ifdef DAEMON 6307 if (be_daemon && logging) 6308 syslog(LOG_INFO, "connection from %s", remoteident); 6309 #else 6310 #if 0 /* this is redundant unless the caller doesn't do *anything*, and 6311 tcpd will pick it up and deal with it better anyways. _H */ 6312 if (logging) 6313 syslog(LOG_INFO, "connection from %s", remoteident); 6314 #endif 6315 #endif 6316 } 6317 6318 /* Record logout in wtmp file and exit with supplied status. */ 6319 6320 void dologout(int status) 6321 { 6322 /* 6323 * Prevent reception of SIGURG from resulting in a resumption 6324 * back to the main program loop. 6325 */ 6326 transflag = 0; 6327 6328 /* 6329 * Cancel any pending alarm request, reception of SIGALRM would cause 6330 * dologout() to be called again from the SIGALRM handler toolong(). 6331 */ 6332 (void) alarm(0); 6333 6334 if (logged_in) { 6335 delay_signaling(); /* we can't allow any signals while euid==0: kinch */ 6336 #if defined(SOLARIS_BSM_AUDIT) && !defined(SOLARIS_NO_AUDIT_FTPD_LOGOUT) 6337 audit_ftpd_logout(); 6338 #endif 6339 (void) seteuid((uid_t) 0); 6340 if (wtmp_logging) 6341 wu_logwtmp(ttyline, pw->pw_name, remotehost, 0); 6342 #ifdef USE_PAM 6343 if (!anonymous && pamh) { 6344 (void) pam_close_session(pamh, 0); 6345 (void) pam_end(pamh, PAM_SUCCESS); 6346 pamh = (pam_handle_t *)0; 6347 } 6348 #endif 6349 } 6350 if (logging) 6351 syslog(LOG_INFO, "FTP session closed"); 6352 if (xferlog) 6353 close(xferlog); 6354 acl_remove(); 6355 if (data >= 0) 6356 close(data); 6357 if (pdata >= 0) 6358 close(pdata); 6359 #ifdef AFS_AUTH 6360 ktc_ForgetAllTokens(); 6361 #endif 6362 /* beware of flushing buffers after a SIGPIPE */ 6363 _exit(status); 6364 } 6365 6366 SIGNAL_TYPE myoob(int sig) 6367 { 6368 char *cp; 6369 #ifdef SIGPIPE 6370 void (*pipe_handler)(); 6371 #endif 6372 6373 /* only process if transfer occurring */ 6374 if (!transflag) { 6375 #ifdef SIGURG 6376 (void) signal(SIGURG, myoob); 6377 #endif 6378 return; 6379 } 6380 #ifdef SIGPIPE 6381 pipe_handler = signal(SIGPIPE, lostconn); 6382 #endif 6383 cp = tmpline; 6384 if (wu_getline(cp, sizeof(tmpline) - 1, stdin) == NULL) { 6385 reply(221, "You could at least say goodbye."); 6386 dologout(0); 6387 } 6388 upper(cp); 6389 if (strcasecmp(cp, "ABOR\r\n") == 0) { 6390 tmpline[0] = '\0'; 6391 reply(426, "Transfer aborted. Data connection closed."); 6392 reply(226, "Abort successful"); 6393 #ifdef SIGPIPE 6394 (void) signal(SIGPIPE, pipe_handler); 6395 #endif 6396 #ifdef SIGURG 6397 (void) signal(SIGURG, myoob); 6398 #endif 6399 if (ftwflag > 0) { 6400 ftwflag++; 6401 return; 6402 } 6403 wu_longjmp(urgcatch, 1); 6404 } 6405 if (strcasecmp(cp, "STAT\r\n") == 0) { 6406 tmpline[0] = '\0'; 6407 if (file_size != (off_t) - 1) 6408 reply(213, "Status: %" L_FORMAT " of %" L_FORMAT " bytes transferred", 6409 byte_count, file_size); 6410 else 6411 reply(213, "Status: %" L_FORMAT " bytes transferred", byte_count); 6412 } 6413 #ifdef SIGPIPE 6414 (void) signal(SIGPIPE, pipe_handler); 6415 #endif 6416 #ifdef SIGURG 6417 (void) signal(SIGURG, myoob); 6418 #endif 6419 } 6420 6421 /* Note: a response of 425 is not mentioned as a possible response to the 6422 * PASV command in RFC959. However, it has been blessed as a legitimate 6423 * response by Jon Postel in a telephone conversation with Rick Adams on 25 6424 * Jan 89. */ 6425 6426 void passive(int passive_mode, int proto) 6427 { 6428 /* First prime number after 2^n where 4 <= n <= 16 */ 6429 static int primes[] = {17,37,67,131,257,521,1031,2053,4099,8209,16411,32771,65537,0}; 6430 static int prime = 0; 6431 static int range; 6432 #if defined(UNIXWARE) || defined(AIX) 6433 size_t len; 6434 #else 6435 int len; 6436 #endif 6437 int bind_error, serrno; 6438 int on = 1; 6439 int i, j, inc, val; 6440 unsigned short port; 6441 register char *p, *a; 6442 struct SOCKSTORAGE *reply_addr; 6443 struct timeval tv; 6444 #ifdef INET6 6445 int isv4 = 0; 6446 #endif 6447 6448 /* H* fix: if we already *have* a passive socket, close it first. Prevents 6449 a whole variety of entertaining clogging attacks. */ 6450 if (pdata >= 0) { 6451 close(pdata); 6452 pdata = -1; 6453 } 6454 if (!logged_in) { 6455 reply(530, "Login with USER first."); 6456 return; 6457 } 6458 #ifdef INET6 6459 switch (proto) { 6460 case 0: 6461 if ((passive_mode == TYPE_PASV) && (SOCK_FAMILY(ctrl_addr) == AF_INET6) 6462 && !ctrl_v4mapped) { 6463 reply(501, "Network protocol mismatch"); 6464 return; 6465 } 6466 else 6467 pasv_addr = ctrl_addr; 6468 break; 6469 case 1: 6470 if (SOCK_FAMILY(ctrl_addr) == AF_INET) 6471 pasv_addr = ctrl_addr; 6472 else if (ctrl_v4mapped) { 6473 struct sockaddr_in6 *ctrl_sin6 = (struct sockaddr_in6 *)&ctrl_addr; 6474 struct sockaddr_in *pasv_sin = (struct sockaddr_in *)&pasv_addr; 6475 6476 SET_SOCK_FAMILY(pasv_addr, AF_INET); 6477 memcpy(&pasv_sin->sin_addr, &ctrl_sin6->sin6_addr.s6_addr[12], 6478 sizeof(struct in_addr)); 6479 } 6480 else { 6481 reply(522, "Network protocol mismatch, use (2)"); 6482 return; 6483 } 6484 break; 6485 case 2: 6486 if ((SOCK_FAMILY(ctrl_addr) == AF_INET6) && !ctrl_v4mapped) 6487 pasv_addr = ctrl_addr; 6488 else { 6489 reply(522, "Network protocol mismatch, use (1)"); 6490 return; 6491 } 6492 break; 6493 default: 6494 reply(522, "Network protocol not supported, use (1,2)"); 6495 return; 6496 } 6497 #else 6498 pasv_addr = ctrl_addr; 6499 #endif 6500 6501 if (passive_port_min == 0 && passive_port_max == 0) { 6502 /* let the kernel allocate the port */ 6503 SET_SOCK_PORT(pasv_addr, 0); 6504 } 6505 else if (prime == 0) { 6506 range = passive_port_max - passive_port_min + 1; 6507 6508 /* find the first prime greater than the range in the primes list */ 6509 for (i = 0; primes[i] != 0 && range >= primes[i]; i++) 6510 ; 6511 /* shouldn't happen, but check just in case */ 6512 if (primes[i] == 0) { 6513 syslog(LOG_ERR, "passive ports range too large %d-%d", passive_port_min, passive_port_max); 6514 /* let the kernel allocate the port */ 6515 SET_SOCK_PORT(pasv_addr, 0); 6516 } 6517 else 6518 prime = primes[i]; 6519 } 6520 len = SOCK_LEN(pasv_addr); 6521 6522 port_priv_on(0); /* necessary as port can be < 1024 */ 6523 pdata = socket(SOCK_FAMILY(pasv_addr), SOCK_STREAM, 0); 6524 if (pdata < 0) { 6525 serrno = errno; 6526 port_priv_off((uid_t) pw->pw_uid); 6527 errno = serrno; 6528 perror_reply(425, "Can't open passive connection"); 6529 return; 6530 } 6531 if (keepalive) 6532 (void) setsockopt(pdata, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)); 6533 if (TCPwindowsize) { 6534 (void) setsockopt(pdata, SOL_SOCKET, SO_SNDBUF, (char *) &TCPwindowsize, sizeof(TCPwindowsize)); 6535 (void) setsockopt(pdata, SOL_SOCKET, SO_RCVBUF, (char *) &TCPwindowsize, sizeof(TCPwindowsize)); 6536 } 6537 6538 bind_error = -1; 6539 errno = EADDRINUSE; 6540 6541 /* try each port in the specified range a maximum of 3 times */ 6542 for (i = 0; i < 3 && bind_error != 0 && \ 6543 ((errno == EADDRINUSE) || (errno == EACCES)); i++) { 6544 if (i > 0) 6545 sleep(i); 6546 if (SOCK_PORT(pasv_addr) == 0) 6547 bind_error = bind(pdata, (struct sockaddr *) &pasv_addr, len); 6548 else { 6549 gettimeofday(&tv, NULL); 6550 srand(tv.tv_usec + tv.tv_sec); 6551 inc = 1 + (int) ((1.0 * (prime - 1) * rand()) / (RAND_MAX + 1.0)); 6552 val = (int) ((1.0 * range * rand()) / (RAND_MAX + 1.0)); 6553 /* 6554 * Using the modulus operator with a prime number allows us to 6555 * try each port in the range once. 6556 */ 6557 for (j = 0; j < range && bind_error != 0 && \ 6558 ((errno == EADDRINUSE) || (errno == EACCES)); j++) { 6559 while ((val = ((val + inc) % prime)) >= range) 6560 ; 6561 SET_SOCK_PORT(pasv_addr, htons(val + passive_port_min)); 6562 bind_error = bind(pdata, (struct sockaddr *) &pasv_addr, len); 6563 } 6564 } 6565 } 6566 serrno = errno; 6567 port_priv_off((uid_t) pw->pw_uid); 6568 if (bind_error != 0) { 6569 errno = serrno; 6570 goto pasv_error; 6571 } 6572 6573 /* if the kernel allocated the port, find out which one */ 6574 if ((SOCK_PORT(pasv_addr) == 0) && 6575 (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)) 6576 goto pasv_error; 6577 6578 if (listen(pdata, 1) < 0) 6579 goto pasv_error; 6580 usedefault = 1; 6581 if (route_vectored) 6582 reply_addr = &vect_addr; 6583 else 6584 reply_addr = &pasv_addr; 6585 a = (char *) SOCK_ADDR(*reply_addr); 6586 port = SOCK_PORT(pasv_addr); 6587 p = (char *) &port; 6588 6589 #define UC(b) (((int) b) & 0xff) 6590 6591 if (debug) { 6592 char *s = calloc(128 + strlen(remoteident), sizeof(char)); 6593 if (s) { 6594 int i = ntohs(port); 6595 sprintf(s, "PASV port %i assigned to %s", i, remoteident); 6596 syslog(LOG_DEBUG, "%s", s); 6597 free(s); 6598 } 6599 } 6600 #ifdef INET6 6601 if (SOCK_FAMILY(*reply_addr) == AF_INET) 6602 isv4 = 1; 6603 else if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)reply_addr)->sin6_addr)) { 6604 isv4 = 1; 6605 a += 12; /* move to the IPv4 part of an IPv4-mapped IPv6 address */ 6606 } 6607 switch (passive_mode) { 6608 case TYPE_PASV: 6609 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", 6610 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 6611 return; 6612 case TYPE_EPSV: 6613 reply(229, "Entering Extended Passive Mode (|||%d|)", ntohs(port)); 6614 return; 6615 case TYPE_LPSV: 6616 if (isv4) { 6617 reply(228, "Entering Long Passive Mode " 6618 "(%d,%d,%d,%d,%d,%d,%d,%d,%d)", 6619 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 6620 2, UC(p[0]), UC(p[1])); 6621 } 6622 else { 6623 reply(228, "Entering Long Passive Mode " 6624 "(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," 6625 "%d,%d,%d,%d,%d)", 6, 16, 6626 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 6627 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 6628 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 6629 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 6630 2, UC(p[0]), UC(p[1])); 6631 } 6632 return; 6633 } 6634 #else 6635 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), 6636 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); 6637 return; 6638 #endif /* INET6 */ 6639 6640 pasv_error: 6641 perror_reply(425, "Can't open passive connection"); 6642 (void) close(pdata); 6643 pdata = -1; 6644 if (debug) { 6645 char *s = calloc(128 + strlen(remoteident), sizeof(char)); 6646 if (s) { 6647 sprintf(s, "PASV port assignment assigned for %s", remoteident); 6648 syslog(LOG_DEBUG, "%s", s); 6649 free(s); 6650 } 6651 } 6652 return; 6653 } 6654 6655 /* 6656 * Generate unique name for file with basename "local". The file named 6657 * "local" is already known to exist. Generates failure reply on error. 6658 */ 6659 char *gunique(char *local) 6660 { 6661 static char new[MAXPATHLEN]; 6662 struct stat st; 6663 char *cp = strrchr(local, '/'); 6664 int count = 0; 6665 6666 if (cp) 6667 *cp = '\0'; 6668 if (stat(cp ? local : ".", &st) < 0) { 6669 perror_reply(553, cp ? local : "."); 6670 return ((char *) 0); 6671 } 6672 if (cp) 6673 *cp = '/'; 6674 (void) strncpy(new, local, (sizeof new) - 3); 6675 new[sizeof(new) - 3] = '\0'; 6676 cp = new + strlen(new); 6677 *cp++ = '.'; 6678 for (count = 1; count < 100; count++) { 6679 if (count == 10) { 6680 cp -= 2; 6681 *cp++ = '.'; 6682 } 6683 (void) sprintf(cp, "%d", count); 6684 if (stat(new, &st) < 0) 6685 return (new); 6686 } 6687 reply(452, "Unique file name cannot be created."); 6688 return ((char *) 0); 6689 } 6690 6691 /* Format and send reply containing system error number. */ 6692 6693 void perror_reply(int code, char *string) 6694 { 6695 /* 6696 * If restricted user and string starts with home dir path, strip it off 6697 * and return only the relative path. 6698 */ 6699 if (restricted_user && (home != NULL) && (home[0] != '\0')) { 6700 size_t len = strlen (home); 6701 if (strncmp (home, string, len) == 0) { 6702 if (string[len - 1] == '/') 6703 string += len - 1; 6704 else if (string[len] == '/') 6705 string += len; 6706 else if (string[len] == '\0') 6707 string = "/"; 6708 } 6709 } 6710 reply(code, "%s: %s.", string, strerror(errno)); 6711 } 6712 6713 static char *onefile[] = 6714 {"", 0}; 6715 6716 extern char **ftpglob(register char *v, boolean_t check_ncargs); 6717 extern char *globerr; 6718 6719 void send_file_list(char *whichfiles) 6720 { 6721 /* static so not clobbered by longjmp(), volatile would also work */ 6722 static FILE *dout; 6723 static DIR *dirp; 6724 static char **sdirlist; 6725 static char *wildcard = NULL; 6726 6727 struct stat st; 6728 6729 register char **dirlist, *dirname; 6730 int simple = 0; 6731 int statret; 6732 /* This is ANSI/ISO C .. strpbrk should be in <string.h> which we've 6733 ** already included so we don't need the following line. 'sides, it 6734 ** breaks the GNU EGCS C compiler 6735 ** extern char *strpbrk(const char *, const char *); 6736 */ 6737 6738 #ifdef TRANSFER_COUNT 6739 #ifdef TRANSFER_LIMIT 6740 if (((file_limit_raw_out > 0) && (xfer_count_out >= file_limit_raw_out)) 6741 || ((file_limit_raw_total > 0) && (xfer_count_total >= file_limit_raw_total)) 6742 || ((data_limit_raw_out > 0) && (byte_count_out >= data_limit_raw_out)) 6743 || ((data_limit_raw_total > 0) && (byte_count_total >= data_limit_raw_total))) { 6744 if (log_security) 6745 if (anonymous) 6746 syslog(LOG_NOTICE, "anonymous(%s) of %s tried to list files (Transfer limits exceeded)", 6747 guestpw, remoteident); 6748 else 6749 syslog(LOG_NOTICE, "%s of %s tried to list files (Transfer limits exceeded)", 6750 pw->pw_name, remoteident); 6751 reply(553, "Permission denied on server. (Transfer limits exceeded)"); 6752 return; 6753 } 6754 #endif 6755 #endif 6756 6757 draconian_FILE = NULL; 6758 dout = NULL; 6759 dirp = NULL; 6760 sdirlist = NULL; 6761 wildcard = NULL; 6762 if (strpbrk(whichfiles, "~{[*?") == NULL) { 6763 if (whichfiles[0] == '\0') { 6764 wildcard = strdup("*"); 6765 if (wildcard == NULL) { 6766 reply(550, "Memory allocation error"); 6767 goto globfree; 6768 } 6769 whichfiles = wildcard; 6770 } 6771 else { 6772 if (statret=stat(whichfiles, &st) < 0) 6773 statret=lstat(whichfiles, &st); /* Check if it's a dangling symlink */ 6774 if (statret >= 0) { 6775 if ((st.st_mode & S_IFMT) == S_IFDIR) { 6776 wildcard = malloc(strlen(whichfiles) + 3); 6777 if (wildcard == NULL) { 6778 reply(550, "Memory allocation error"); 6779 goto globfree; 6780 } 6781 strcpy(wildcard, whichfiles); 6782 strcat(wildcard, "/*"); 6783 whichfiles = wildcard; 6784 } 6785 } 6786 } 6787 } 6788 if (strpbrk(whichfiles, "~{[*?") != NULL) { 6789 globerr = NULL; 6790 dirlist = ftpglob(whichfiles, B_FALSE); 6791 sdirlist = dirlist; /* save to free later */ 6792 if (globerr != NULL) { 6793 reply(550, "%s", globerr); 6794 goto globfree; 6795 } 6796 else if (dirlist == NULL) { 6797 errno = ENOENT; 6798 perror_reply(550, whichfiles); 6799 goto globfree; 6800 } 6801 } 6802 else { 6803 onefile[0] = whichfiles; 6804 dirlist = onefile; 6805 simple = 1; 6806 } 6807 6808 if (wu_setjmp(urgcatch)) { 6809 transflag = 0; 6810 if (dout != NULL) 6811 (void) fclose(dout); 6812 if (dirp != NULL) 6813 (void) closedir(dirp); 6814 data = -1; 6815 pdata = -1; 6816 goto globfree; 6817 } 6818 while ((dirname = *dirlist++) != NULL) { 6819 statret=stat(dirname, &st); 6820 if (statret < 0) 6821 statret=lstat(dirname, &st); /* Could be a dangling symlink */ 6822 if (statret < 0) { 6823 /* If user typed "ls -l", etc, and the client used NLST, do what 6824 * the user meant. */ 6825 if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) { 6826 retrieve_is_data = 0; 6827 #ifndef INTERNAL_LS 6828 retrieve(ls_plain, dirname); 6829 #else 6830 ls(dirname, 1); 6831 #endif 6832 retrieve_is_data = 1; 6833 goto globfree; 6834 } 6835 perror_reply(550, dirname); 6836 if (dout != NULL) { 6837 (void) fclose(dout); 6838 transflag = 0; 6839 data = -1; 6840 pdata = -1; 6841 } 6842 goto globfree; 6843 } 6844 #ifndef NLST_SHOWS_DIRS 6845 if ((st.st_mode & S_IFMT) != S_IFDIR) 6846 #endif 6847 { 6848 if (dout == NULL) { 6849 dout = dataconn("file list", (off_t) - 1, "w"); 6850 if (dout == NULL) 6851 goto globfree; 6852 transflag++; 6853 draconian_FILE = dout; 6854 } 6855 if (draconian_FILE != NULL) { 6856 (void) signal(SIGALRM, draconian_alarm_signal); 6857 alarm(timeout_data); 6858 #if defined(USE_GSS) 6859 (void) sec_fprintf(dout, "%s%s\n", dirname, 6860 type == TYPE_A ? "\r" : ""); 6861 #else 6862 fprintf(dout, "%s%s\n", dirname, 6863 type == TYPE_A ? "\r" : ""); 6864 #endif /* USE_GSS */ 6865 } 6866 byte_count += strlen(dirname) + 1; 6867 #ifdef TRANSFER_COUNT 6868 byte_count_total += strlen(dirname) + 1; 6869 byte_count_out += strlen(dirname) + 1; 6870 if (type == TYPE_A) { 6871 byte_count_total++; 6872 byte_count_out++; 6873 } 6874 #endif 6875 } 6876 } 6877 6878 if (dout != NULL) { 6879 if (draconian_FILE != NULL) { 6880 (void) signal(SIGALRM, draconian_alarm_signal); 6881 alarm(timeout_data); 6882 #if defined(USE_GSS) 6883 if (sec_fflush(dout) < 0) { 6884 alarm(0); 6885 perror_reply(550, "Data connection"); 6886 goto sfl_cleanup; /* send file list cleanup */ 6887 } 6888 #else 6889 fflush(dout); 6890 #endif /* USE_GSS */ 6891 } 6892 if (draconian_FILE != NULL) { 6893 (void) signal(SIGALRM, draconian_alarm_signal); 6894 alarm(timeout_data); 6895 socket_flush_wait(dout); 6896 } 6897 } 6898 if (dout == NULL) 6899 reply(550, "No files found."); 6900 else if ((draconian_FILE == NULL) || ferror(dout) != 0) { 6901 alarm(0); 6902 perror_reply(550, "Data connection"); 6903 } 6904 else { 6905 #ifdef TRANSFER_COUNT 6906 xfer_count_total++; 6907 xfer_count_out++; 6908 #endif 6909 alarm(0); 6910 reply(226, "Transfer complete."); 6911 } 6912 sfl_cleanup: 6913 transflag = 0; 6914 if ((dout != NULL) && (draconian_FILE != NULL)) 6915 (void) fclose(dout); 6916 data = -1; 6917 pdata = -1; 6918 globfree: 6919 if (wildcard != NULL) { 6920 free(wildcard); 6921 wildcard = NULL; 6922 } 6923 if (sdirlist) { 6924 blkfree(sdirlist); 6925 free((char *) sdirlist); 6926 } 6927 } 6928 6929 /* 6930 ** SETPROCTITLE -- set process title for ps 6931 ** 6932 ** Parameters: 6933 ** fmt -- a printf style format string. 6934 ** a, b, c -- possible parameters to fmt. 6935 ** 6936 ** Returns: 6937 ** none. 6938 ** 6939 ** Side Effects: 6940 ** Clobbers argv of our main procedure so ps(1) will 6941 ** display the title. 6942 */ 6943 6944 #define SPT_NONE 0 /* don't use it at all */ 6945 #define SPT_REUSEARGV 1 /* cover argv with title information */ 6946 #define SPT_BUILTIN 2 /* use libc builtin */ 6947 #define SPT_PSTAT 3 /* use pstat(PSTAT_SETCMD, ...) */ 6948 #define SPT_PSSTRINGS 4 /* use PS_STRINGS->... */ 6949 #define SPT_SYSMIPS 5 /* use sysmips() supported by NEWS-OS 6 */ 6950 #define SPT_SCO 6 /* write kernel u. area */ 6951 #define SPT_CHANGEARGV 7 /* write our own strings into argv[] */ 6952 #define MAXLINE 2048 /* max line length for setproctitle */ 6953 #define SPACELEFT(buf, ptr) (sizeof buf - ((ptr) - buf)) 6954 6955 #ifndef SPT_TYPE 6956 #define SPT_TYPE SPT_REUSEARGV 6957 #endif 6958 6959 #if SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN 6960 6961 #if SPT_TYPE == SPT_PSTAT 6962 #include <sys/pstat.h> 6963 #endif 6964 #if SPT_TYPE == SPT_PSSTRINGS 6965 #include <machine/vmparam.h> 6966 #include <sys/exec.h> 6967 #ifndef PS_STRINGS /* hmmmm.... apparently not available after all */ 6968 #undef SPT_TYPE 6969 #define SPT_TYPE SPT_REUSEARGV 6970 #else 6971 #ifndef NKPDE /* FreeBSD 2.0 */ 6972 #define NKPDE 63 6973 typedef unsigned int *pt_entry_t; 6974 #endif 6975 #endif 6976 #endif 6977 6978 #if SPT_TYPE == SPT_PSSTRINGS || SPT_TYPE == SPT_CHANGEARGV 6979 #define SETPROC_STATIC static 6980 #else 6981 #define SETPROC_STATIC 6982 #endif 6983 6984 #if SPT_TYPE == SPT_SYSMIPS 6985 #include <sys/sysmips.h> 6986 #include <sys/sysnews.h> 6987 #endif 6988 6989 #if SPT_TYPE == SPT_SCO 6990 #ifdef UNIXWARE 6991 #include <sys/exec.h> 6992 #include <sys/ksym.h> 6993 #include <sys/proc.h> 6994 #include <sys/user.h> 6995 #else /* UNIXWARE */ 6996 #include <sys/immu.h> 6997 #include <sys/dir.h> 6998 #include <sys/user.h> 6999 #include <sys/fs/s5param.h> 7000 #endif /* UNIXWARE */ 7001 #if PSARGSZ > MAXLINE 7002 #define SPT_BUFSIZE PSARGSZ 7003 #endif 7004 #ifndef _PATH_KMEM 7005 #define _PATH_KMEM "/dev/kmem" 7006 #endif /* _PATH_KMEM */ 7007 #endif /* SPT_SCO */ 7008 7009 #ifndef SPT_PADCHAR 7010 #define SPT_PADCHAR ' ' 7011 #endif 7012 7013 #ifndef SPT_BUFSIZE 7014 #define SPT_BUFSIZE MAXLINE 7015 #endif 7016 7017 #endif /* SPT_TYPE != SPT_NONE && SPT_TYPE != SPT_BUILTIN */ 7018 7019 #if SPT_TYPE == SPT_REUSEARGV || SPT_TYPE == SPT_CHANGEARGV 7020 char **Argv = NULL; /* pointer to argument vector */ 7021 #endif 7022 7023 #if SPT_TYPE == SPT_REUSEARGV 7024 char *LastArgv = NULL; /* end of argv */ 7025 #endif 7026 7027 /* 7028 ** Pointers for setproctitle. 7029 ** This allows "ps" listings to give more useful information. 7030 */ 7031 void initsetproctitle(argc, argv, envp) 7032 int argc; 7033 char **argv; 7034 char **envp; 7035 { 7036 #if SPT_TYPE == SPT_REUSEARGV 7037 register int i, envpsize = 0; 7038 char **newenviron; 7039 extern char **environ; 7040 7041 /* 7042 ** Save start and extent of argv for setproctitle. 7043 */ 7044 7045 LastArgv = argv[argc - 1] + strlen(argv[argc - 1]); 7046 if (envp != NULL) { 7047 /* 7048 ** Move the environment so setproctitle can use the space at 7049 ** the top of memory. 7050 */ 7051 for (i = 0; envp[i] != NULL; i++) 7052 envpsize += strlen(envp[i]) + 1; 7053 newenviron = (char **) malloc(sizeof(char *) * (i + 1)); 7054 if (newenviron) { 7055 int err = 0; 7056 for (i = 0; envp[i] != NULL; i++) { 7057 if ((newenviron[i] = strdup(envp[i])) == NULL) { 7058 err = 1; 7059 break; 7060 } 7061 } 7062 if (err) { 7063 for (i = 0; newenviron[i] != NULL; i++) 7064 free(newenviron[i]); 7065 free(newenviron); 7066 i = 0; 7067 } 7068 else { 7069 newenviron[i] = NULL; 7070 environ = newenviron; 7071 } 7072 } 7073 else { 7074 i = 0; 7075 } 7076 7077 /* 7078 ** Find the last environment variable within wu-ftpd's 7079 ** process memory area. 7080 */ 7081 while (i > 0 && (envp[i - 1] < argv[0] || 7082 envp[i - 1] > (argv[argc - 1] + strlen(argv[argc - 1]) + 7083 1 + envpsize))) 7084 i--; 7085 7086 if (i > 0) 7087 LastArgv = envp[i - 1] + strlen(envp[i - 1]); 7088 } 7089 #endif /* SPT_TYPE == SPT_REUSEARGV */ 7090 7091 #if SPT_TYPE == SPT_REUSEARGV || SPT_TYPE == SPT_CHANGEARGV 7092 Argv = argv; 7093 #endif 7094 } 7095 7096 7097 #if SPT_TYPE != SPT_BUILTIN 7098 7099 /*VARARGS1 */ 7100 void setproctitle(const char *fmt,...) 7101 { 7102 #if SPT_TYPE != SPT_NONE 7103 register char *p; 7104 register int i; 7105 SETPROC_STATIC char buf[SPT_BUFSIZE]; 7106 VA_LOCAL_DECL 7107 #if SPT_TYPE == SPT_PSTAT 7108 union pstun pst; 7109 #endif 7110 #if SPT_TYPE == SPT_SCO 7111 static off_t seek_off; 7112 static int kmemfd = -1; 7113 static int kmempid = -1; 7114 #ifdef UNIXWARE 7115 off_t offset; 7116 void *ptr; 7117 struct mioc_rksym rks; 7118 #endif /* UNIXWARE */ 7119 #endif /* SPT_SCO */ 7120 7121 p = buf; 7122 7123 /* print ftpd: heading for grep */ 7124 (void) strcpy(p, "ftpd: "); 7125 p += strlen(p); 7126 7127 /* print the argument string */ 7128 VA_START(fmt); 7129 (void) vsnprintf(p, SPACELEFT(buf, p), fmt, ap); 7130 VA_END; 7131 7132 i = strlen(buf); 7133 7134 #if SPT_TYPE == SPT_PSTAT 7135 pst.pst_command = buf; 7136 pstat(PSTAT_SETCMD, pst, i, 0, 0); 7137 #endif 7138 #if SPT_TYPE == SPT_PSSTRINGS 7139 PS_STRINGS->ps_nargvstr = 1; 7140 PS_STRINGS->ps_argvstr = buf; 7141 #endif 7142 #if SPT_TYPE == SPT_SYSMIPS 7143 sysmips(SONY_SYSNEWS, NEWS_SETPSARGS, buf); 7144 #endif 7145 #if SPT_TYPE == SPT_SCO 7146 if (kmemfd < 0 || kmempid != getpid()) { 7147 if (kmemfd >= 0) 7148 close(kmemfd); 7149 if ((kmemfd = open(_PATH_KMEM, O_RDWR, 0)) < 0) 7150 return; 7151 (void) fcntl(kmemfd, F_SETFD, 1); 7152 kmempid = getpid(); 7153 #ifdef UNIXWARE 7154 seek_off = 0; 7155 rks.mirk_symname = "upointer"; 7156 rks.mirk_buf = &ptr; 7157 rks.mirk_buflen = sizeof(ptr); 7158 if (ioctl(kmemfd, MIOC_READKSYM, &rks) < 0) 7159 return; 7160 offset = (off_t) ptr + (off_t) & ((struct user *) 0)->u_procp; 7161 if (lseek(kmemfd, offset, SEEK_SET) != offset) 7162 return; 7163 if (read(kmemfd, &ptr, sizeof(ptr)) != sizeof(ptr)) 7164 return; 7165 offset = (off_t) ptr + (off_t) & ((struct proc *) 0)->p_execinfo; 7166 if (lseek(kmemfd, offset, SEEK_SET) != offset) 7167 return; 7168 if (read(kmemfd, &ptr, sizeof(ptr)) != sizeof(ptr)) 7169 return; 7170 seek_off = (off_t) ptr + (off_t) ((struct execinfo *) 0)->ei_psargs; 7171 #else /* UNIXWARE */ 7172 seek_off = UVUBLK + (off_t) & ((struct user *) 0)->u_psargs; 7173 #endif /* UNIXWARE */ 7174 } 7175 #ifdef UNIXWARE 7176 if (seek_off == 0) 7177 return; 7178 #endif /* UNIXWARE */ 7179 buf[PSARGSZ - 1] = '\0'; 7180 if (lseek(kmemfd, (off_t) seek_off, SEEK_SET) == seek_off) 7181 (void) write(kmemfd, buf, PSARGSZ); 7182 #endif /* SPT_SCO */ 7183 #if SPT_TYPE == SPT_REUSEARGV 7184 if (i > LastArgv - Argv[0] - 2) { 7185 i = LastArgv - Argv[0] - 2; 7186 buf[i] = '\0'; 7187 } 7188 (void) strcpy(Argv[0], buf); 7189 p = &Argv[0][i]; 7190 while (p < LastArgv) 7191 *p++ = SPT_PADCHAR; 7192 Argv[1] = NULL; 7193 #endif 7194 #if SPT_TYPE == SPT_CHANGEARGV 7195 Argv[0] = buf; 7196 Argv[1] = 0; 7197 #endif 7198 #endif /* SPT_TYPE != SPT_NONE */ 7199 } 7200 7201 #endif /* SPT_TYPE != SPT_BUILTIN */ 7202 7203 #ifdef KERBEROS 7204 /* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */ 7205 7206 void init_krb() 7207 { 7208 char hostname[100]; 7209 7210 #ifdef HAVE_SYSINFO 7211 if (sysinfo(SI_HOSTNAME, hostname, sizeof(hostname)) < 0) { 7212 perror("sysinfo"); 7213 #else 7214 if (gethostname(hostname, sizeof(hostname)) < 0) { 7215 perror("gethostname"); 7216 #endif 7217 exit(1); 7218 } 7219 if (strchr(hostname, '.')) 7220 *(strchr(hostname, '.')) = 0; 7221 7222 sprintf(krb_ticket_name, "/var/dss/kerberos/tkt/tkt.%d", getpid()); 7223 krb_set_tkt_string(krb_ticket_name); 7224 7225 config_auth(); 7226 7227 if (krb_svc_init("hesiod", hostname, (char *) NULL, 0, (char *) NULL, 7228 (char *) NULL) != KSUCCESS) { 7229 fprintf(stderr, "Couldn't initialize Kerberos\n"); 7230 exit(1); 7231 } 7232 } 7233 7234 void end_krb() 7235 { 7236 unlink(krb_ticket_name); 7237 } 7238 7239 #endif /* KERBEROS */ 7240 7241 #ifdef ULTRIX_AUTH 7242 static int ultrix_check_pass(char *passwd, char *xpasswd) 7243 { 7244 struct svcinfo *svp; 7245 int auth_status; 7246 7247 if ((svp = getsvc()) == (struct svcinfo *) NULL) { 7248 syslog(LOG_WARNING, "getsvc() failed in ultrix_check_pass"); 7249 return -1; 7250 } 7251 if (pw == (struct passwd *) NULL) { 7252 return -1; 7253 } 7254 if (((svp->svcauth.seclevel == SEC_UPGRADE) && 7255 (!strcmp(pw->pw_passwd, "*"))) 7256 || (svp->svcauth.seclevel == SEC_ENHANCED)) { 7257 if ((auth_status = authenticate_user(pw, passwd, "/dev/ttypXX")) >= 0) { 7258 /* Indicate successful validation */ 7259 return auth_status; 7260 } 7261 if (auth_status < 0 && errno == EPERM) { 7262 /* Log some information about the failed login attempt. */ 7263 switch (abs(auth_status)) { 7264 case A_EBADPASS: 7265 break; 7266 case A_ESOFTEXP: 7267 syslog(LOG_NOTICE, "password will expire soon for user %s", 7268 pw->pw_name); 7269 break; 7270 case A_EHARDEXP: 7271 syslog(LOG_NOTICE, "password has expired for user %s", 7272 pw->pw_name); 7273 break; 7274 case A_ENOLOGIN: 7275 syslog(LOG_NOTICE, "user %s attempted login to disabled acct", 7276 pw->pw_name); 7277 break; 7278 } 7279 } 7280 } 7281 else { 7282 if ((*pw->pw_passwd != '\0') && (!strcmp(xpasswd, pw->pw_passwd))) { 7283 /* passwd in /etc/passwd isn't empty && encrypted passwd matches */ 7284 return 0; 7285 } 7286 } 7287 return -1; 7288 } 7289 #endif /* ULTRIX_AUTH */ 7290 7291 #ifdef USE_PAM 7292 /* This is rather an abuse of PAM, but the FTP protocol doesn't allow much 7293 * flexibility here. :-( 7294 */ 7295 7296 /* Static variables used to communicate between the conversation function 7297 * and the server_login function 7298 */ 7299 static char *PAM_password; 7300 7301 /* PAM conversation function 7302 * Here we assume (for now, at least) that echo on means login name, and 7303 * echo off means password. 7304 */ 7305 #ifdef SOLARIS_2 7306 /* Workaround bug 4430970/4413889 which causes a compiler warning, necessary 7307 * as usr/src/Makefile.master now includes "-errwarn=%all". 7308 */ 7309 static int PAM_conv(int num_msg, struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) 7310 #else 7311 static int PAM_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) 7312 #endif 7313 { 7314 int replies = 0; 7315 struct pam_response *reply = NULL; 7316 7317 #define COPY_STRING(s) (s) ? strdup(s) : NULL 7318 7319 reply = malloc(sizeof(struct pam_response) * num_msg); 7320 if (!reply) 7321 return PAM_CONV_ERR; 7322 7323 for (replies = 0; replies < num_msg; replies++) { 7324 switch (msg[replies]->msg_style) { 7325 case PAM_PROMPT_ECHO_ON: 7326 return PAM_CONV_ERR; 7327 break; 7328 case PAM_PROMPT_ECHO_OFF: 7329 reply[replies].resp_retcode = PAM_SUCCESS; 7330 reply[replies].resp = COPY_STRING(PAM_password); 7331 /* PAM frees resp */ 7332 break; 7333 case PAM_TEXT_INFO: 7334 /* ignore it... */ 7335 reply[replies].resp_retcode = PAM_SUCCESS; 7336 reply[replies].resp = NULL; 7337 break; 7338 case PAM_ERROR_MSG: 7339 /* ignore it... */ 7340 reply[replies].resp_retcode = PAM_SUCCESS; 7341 reply[replies].resp = NULL; 7342 break; 7343 default: 7344 /* Must be an error of some sort... */ 7345 return PAM_CONV_ERR; 7346 } 7347 } 7348 *resp = reply; 7349 return PAM_SUCCESS; 7350 } 7351 static struct pam_conv PAM_conversation = 7352 { 7353 &PAM_conv, 7354 NULL 7355 }; 7356 7357 static int pam_check_pass(char *user, char *passwd) 7358 { 7359 char tty[20]; 7360 int pam_session = 0; 7361 7362 /* Now use PAM to do authentication and session logging. Bail out if 7363 * there are any errors. Since this is a limited protocol, and an even 7364 * more limited function within a server speaking this protocol, we 7365 * can't be as verbose as would otherwise make sense. 7366 */ 7367 PAM_password = passwd; 7368 pamh = (pam_handle_t *)0; 7369 if (pam_start("ftp", user, &PAM_conversation, &pamh) != PAM_SUCCESS) 7370 return 0; 7371 7372 #if ((defined(BSD) && (BSD >= 199103)) || defined(sun)) 7373 (void) sprintf(tty, "/dev/ftp%ld", (long) getpid()); 7374 #else 7375 (void) sprintf(tty, "/dev/ftpd%d", getpid()); 7376 #endif 7377 7378 if (pam_set_item(pamh, PAM_TTY, tty) != PAM_SUCCESS) 7379 goto pam_fail; 7380 if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS) 7381 goto pam_fail; 7382 if (pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS) { 7383 #ifdef SOLARIS_BSM_AUDIT 7384 audit_ftpd_bad_pw(user); 7385 #endif 7386 goto pam_fail; 7387 } 7388 if (pam_acct_mgmt(pamh, 0) != PAM_SUCCESS) { 7389 #ifdef SOLARIS_BSM_AUDIT 7390 audit_ftpd_bad_pw(user); 7391 #endif 7392 goto pam_fail; 7393 } 7394 if (pam_open_session(pamh, 0) != PAM_SUCCESS) 7395 goto pam_fail; 7396 pam_session = 1; 7397 #ifdef PAM_ESTABLISH_CRED 7398 if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) 7399 goto pam_fail; 7400 #else 7401 if (pam_setcred(pamh, PAM_CRED_ESTABLISH) != PAM_SUCCESS) 7402 goto pam_fail; 7403 #endif 7404 /* If this point is reached, the user has been authenticated. */ 7405 return 1; 7406 7407 pam_fail: 7408 if (pam_session) 7409 (void) pam_close_session(pamh, 0); 7410 (void) pam_end(pamh, 0); 7411 pamh = (pam_handle_t *)0; 7412 return 0; 7413 } 7414 #endif 7415 7416 #ifdef DAEMON 7417 7418 #ifdef INET6 7419 static struct in6_addr acl_DaemonAddress6(void) 7420 { 7421 struct in6_addr rv = in6addr_any; 7422 struct aclmember *entry = NULL; 7423 7424 if (getaclentry("daemonaddress", &entry) && ARG0) { 7425 if (inet_pton6(ARG0, &rv) != 1) 7426 rv = in6addr_any; 7427 } 7428 return rv; 7429 } 7430 #endif /* INET6 */ 7431 static unsigned long int acl_DaemonAddress(void) 7432 { 7433 unsigned long int rv = INADDR_ANY; 7434 struct aclmember *entry = NULL; 7435 7436 if (getaclentry("daemonaddress", &entry) && ARG0) { 7437 rv = inet_addr(ARG0); 7438 if (rv == -1) 7439 rv = INADDR_ANY; 7440 } 7441 return rv; 7442 } 7443 7444 /* I am running as a standalone daemon (not under inetd) */ 7445 static void do_daemon(void) 7446 { 7447 struct SOCKSTORAGE server; 7448 struct servent *serv; 7449 int pgrp; 7450 int lsock; 7451 int one = 1; 7452 FILE *pidfile; 7453 int i; 7454 #if defined(UNIXWARE) || defined(AIX) 7455 size_t addrlen; 7456 #else 7457 int addrlen; 7458 #endif 7459 7460 /* Some of this is "borrowed" from inn - lots of it isn't */ 7461 7462 if (be_daemon == 2) { 7463 /* Fork - so I'm not the owner of the process group any more */ 7464 i = fork(); 7465 if (i < 0) { 7466 syslog(LOG_ERR, "cant fork %m"); 7467 exit(1); 7468 } 7469 /* No need for the parent any more */ 7470 if (i > 0) 7471 exit(0); 7472 7473 #ifdef NO_SETSID 7474 pgrp = setpgrp(0, getpid()); 7475 #else 7476 pgrp = setsid(); 7477 #endif 7478 if (pgrp < 0) { 7479 syslog(LOG_ERR, "cannot daemonise: %m"); 7480 exit(1); 7481 } 7482 } 7483 7484 if (!Bypass_PID_Files) 7485 if ((pidfile = fopen(_PATH_FTPD_PID, "w"))) { 7486 fprintf(pidfile, "%ld\n", (long) getpid()); 7487 fclose(pidfile); 7488 } 7489 else { 7490 syslog(LOG_ERR, "Cannot write pidfile: %m"); 7491 } 7492 7493 /* Close off all file descriptors and reopen syslog */ 7494 if (be_daemon == 2) { 7495 closelog(); 7496 closefds(0); 7497 (void) open(_PATH_DEVNULL, O_RDWR); 7498 (void) dup2(0, 1); 7499 /* junk stderr */ 7500 (void) freopen(_PATH_DEVNULL, "w", stderr); 7501 7502 #ifdef FACILITY 7503 openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY); 7504 #else 7505 openlog("ftpd", LOG_PID); 7506 #endif 7507 } 7508 7509 if (RootDirectory != NULL) { 7510 if ((chroot(RootDirectory) < 0) 7511 || (chdir("/") < 0)) { 7512 syslog(LOG_ERR, "Cannot chroot to initial directory, aborting."); 7513 exit(1); 7514 } 7515 free(RootDirectory); 7516 RootDirectory = NULL; 7517 } 7518 7519 if (!use_accessfile) 7520 syslog(LOG_WARNING, "FTP server started without ftpaccess file"); 7521 7522 syslog(LOG_INFO, "FTP server (%s) ready.", version); 7523 7524 /* Create a socket to listen on */ 7525 #ifdef INET6 7526 if (listen_v4 == 0) 7527 lsock = socket(AF_INET6, SOCK_STREAM, 0); 7528 else 7529 #endif 7530 lsock = socket(AF_INET, SOCK_STREAM, 0); 7531 if (lsock < 0) { 7532 syslog(LOG_ERR, "Cannot create socket to listen on: %m"); 7533 exit(1); 7534 } 7535 if (setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) < 0) { 7536 syslog(LOG_ERR, "Cannot set SO_REUSEADDR option: %m"); 7537 exit(1); 7538 } 7539 if (keepalive) 7540 (void) setsockopt(lsock, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, sizeof(one)); 7541 7542 #ifdef INET6 7543 if (listen_v4 == 0) { 7544 struct sockaddr_in6 *server_sin6 = (struct sockaddr_in6 *)&server; 7545 7546 memset(&server, 0, sizeof(struct sockaddr_in6)); 7547 server_sin6->sin6_family = AF_INET6; 7548 server_sin6->sin6_addr = acl_DaemonAddress6(); 7549 } 7550 else { 7551 struct sockaddr_in *server_sin = (struct sockaddr_in *)&server; 7552 7553 server_sin->sin_family = AF_INET; 7554 server_sin->sin_addr.s_addr = acl_DaemonAddress(); 7555 } 7556 #else 7557 server.sin_family = AF_INET; 7558 server.sin_addr.s_addr = acl_DaemonAddress(); 7559 #endif 7560 if (daemon_port == 0) { 7561 if (!(serv = getservbyname("ftp", "tcp"))) { 7562 syslog(LOG_ERR, "Cannot find service ftp: %m"); 7563 exit(1); 7564 } 7565 SET_SOCK_PORT(server, serv->s_port); 7566 daemon_port = ntohs(serv->s_port); 7567 } 7568 else 7569 SET_SOCK_PORT(server, htons(daemon_port)); 7570 7571 if (bind(lsock, (struct sockaddr *) &server, SOCK_LEN(server)) < 0) { 7572 syslog(LOG_ERR, "Cannot bind socket: %m"); 7573 exit(1); 7574 } 7575 7576 listen(lsock, MAX_BACKLOG); 7577 7578 sprintf(proctitle, "accepting connections on port %i", daemon_port); 7579 setproctitle("%s", proctitle); 7580 7581 while (1) { 7582 int pid; 7583 int msgsock; 7584 7585 addrlen = sizeof(his_addr); 7586 msgsock = accept(lsock, (struct sockaddr *) &his_addr, &addrlen); 7587 if (msgsock < 0) { 7588 int severity = LOG_ERR; 7589 7590 if (errno == EINTR || errno == ECONNABORTED) 7591 severity = LOG_INFO; 7592 syslog(severity, "Accept failed: %m"); 7593 sleep(1); 7594 continue; 7595 } 7596 7597 /* Fork off a handler */ 7598 pid = fork(); 7599 if (pid < 0) { 7600 syslog(LOG_ERR, "failed to fork: %m"); 7601 close(msgsock); 7602 sleep(1); 7603 continue; 7604 } 7605 if (pid == 0) { 7606 /* I am that forked off child */ 7607 /* Only parent needs lsock */ 7608 close(lsock); 7609 closelog(); 7610 /* Make sure that stdin/stdout are the new socket */ 7611 dup2(msgsock, 0); 7612 dup2(msgsock, 1); 7613 if (msgsock != 0 && msgsock != 1) 7614 close(msgsock); 7615 #ifdef FACILITY 7616 openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY); 7617 #else 7618 openlog("ftpd", LOG_PID); 7619 #endif 7620 setup_paths(); 7621 access_init(); 7622 return; 7623 } 7624 7625 /* I am the parent */ 7626 close(msgsock); 7627 7628 /* Quick check to see if any of the forked off children have 7629 * terminated. */ 7630 while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0) { 7631 /* A child has finished */ 7632 } 7633 7634 access_init(); 7635 } 7636 } 7637 7638 #endif /* DAEMON */ 7639 7640 #ifdef RATIO 7641 int is_downloadfree(char *fname) 7642 { 7643 char rpath[MAXPATHLEN]; 7644 char class[BUFSIZ]; 7645 char *cp; 7646 int which; 7647 struct aclmember *entry = NULL; 7648 7649 if( wu_realpath(fname,rpath,chroot_path) == NULL ) 7650 return 0; 7651 7652 (void) acl_getclass(class); 7653 7654 if (debug) 7655 syslog(LOG_DEBUG, "class: %s, fname: %s, rpath: %s", class, fname, rpath); 7656 7657 while( getaclentry("dl-free-dir",&entry) ) { 7658 if( ARG0 == NULL ) 7659 continue; 7660 if( strncmp(rpath,ARG0,strlen(ARG0)) == 0 ) { 7661 if( ARG1 == NULL ) 7662 return 1; 7663 else for(which = 1; (which < MAXARGS) && ARG[which]; which++) { 7664 if( strcmp(class,ARG[which]) == 0 ) 7665 return 1; 7666 } 7667 } 7668 } 7669 while( getaclentry("dl-free",&entry) ) { 7670 if( ARG0 == NULL ) 7671 continue; 7672 if( *(ARG0) != '/' ) { /* compare basename */ 7673 if( (cp = strrchr(rpath,'/')) == NULL ) { 7674 cp = rpath; 7675 } 7676 else { 7677 ++cp; 7678 } 7679 if( strcmp(cp,ARG0) == 0 ) { 7680 if( ARG1 == NULL ) 7681 return 1; 7682 else for(which = 1; (which < MAXARGS) && ARG[which]; which++) { 7683 if( strcmp(class,ARG[which]) == 0 ) 7684 return 1; 7685 } 7686 } 7687 } 7688 else { /* compare real path */ 7689 if( strcmp(rpath,ARG0) == 0 ) { 7690 if( ARG1 == NULL ) 7691 return 1; 7692 else for(which = 1; (which < MAXARGS) && ARG[which] ; which++) { 7693 if( strcmp(class,ARG[which]) == 0 ) 7694 return 1; 7695 } 7696 } 7697 } 7698 } 7699 return 0; 7700 } 7701 #endif /* RATIO */ 7702 7703 int pasv_allowed(char *remoteaddr) 7704 { 7705 char class[MAXPATHLEN]; 7706 int which; 7707 struct aclmember *entry = NULL; 7708 (void) acl_getclass(class); 7709 while (getaclentry("pasv-allow", &entry)) { 7710 if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0)) 7711 for (which = 1; (which < MAXARGS) && (ARG[which] != NULL); which++) { 7712 if (hostmatch(ARG[which], remoteaddr, NULL)) 7713 return 1; 7714 } 7715 } 7716 return 0; 7717 } 7718 7719 int port_allowed(char *remoteaddr) 7720 { 7721 char class[MAXPATHLEN]; 7722 int which; 7723 struct aclmember *entry = NULL; 7724 (void) acl_getclass(class); 7725 while (getaclentry("port-allow", &entry)) { 7726 if ((ARG0 != NULL) && (strcasecmp(class, ARG0) == 0)) 7727 for (which = 1; (which < MAXARGS) && (ARG[which] != NULL); which++) { 7728 if (hostmatch(ARG[which], remoteaddr, NULL)) 7729 return 1; 7730 } 7731 } 7732 return 0; 7733 } 7734 7735 #ifdef MAIL_ADMIN 7736 char *email(char *full_address) 7737 { 7738 /* Get the plain address part from an e-mail address 7739 (i.e. remove realname) */ 7740 7741 static char *email_buf = NULL; 7742 char *addr, *ptr; 7743 7744 if (email_buf != NULL) 7745 free(email_buf); 7746 7747 email_buf = (char *) malloc(strlen(full_address) + 1); 7748 addr = email_buf; 7749 memset(addr, 0, strlen(full_address) + 1); 7750 strcpy(addr, full_address); 7751 7752 /* Realname <user@host> type address */ 7753 if ((ptr = (char *) strchr(addr, '<')) != NULL) { 7754 addr = ++ptr; 7755 if ((ptr = (char *) strchr(addr, '>')) != NULL) 7756 *ptr = '\0'; 7757 } 7758 7759 /* user@host (Realname) type address */ 7760 if (((char *) strchr(addr, ' ')) != NULL) 7761 addr[strchr(addr, ' ') - addr] = '\0'; 7762 7763 return addr; 7764 } 7765 7766 FILE *SockOpen(char *host, int clientPort) 7767 { 7768 int sock; 7769 unsigned long inaddr; 7770 struct sockaddr_in ad; 7771 FILE *fp; 7772 #ifdef INET6 7773 struct sockaddr_in6 ad6; 7774 struct addrinfo hints, *result, *res; 7775 int af = AF_INET; 7776 #else 7777 struct hostent *hp; 7778 #endif 7779 7780 memset(&ad, 0, sizeof(ad)); 7781 ad.sin_family = AF_INET; 7782 7783 #ifdef INET6 7784 memset(&ad6, 0, sizeof(ad6)); 7785 ad6.sin6_family = AF_INET6; 7786 7787 memset(&hints, 0, sizeof(hints)); 7788 hints.ai_flags = AI_CANONNAME; 7789 hints.ai_family = PF_UNSPEC; 7790 7791 if (getaddrinfo(host, NULL, &hints, &result) != 0) 7792 return (FILE *) NULL; 7793 7794 for (res = result; res; res = res->ai_next) { 7795 af = res->ai_family; 7796 if (af == AF_INET) 7797 memcpy(&ad.sin_addr, &((struct sockaddr_in *)res->ai_addr)->sin_addr, sizeof(struct in_addr)); 7798 else if (af == AF_INET6) 7799 memcpy(&ad6.sin6_addr, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 7800 else 7801 continue; 7802 7803 if (af == AF_INET6) { 7804 ad6.sin6_port = htons(clientPort); 7805 sock = socket(AF_INET6, SOCK_STREAM, 0); 7806 if (sock < 0) 7807 continue; 7808 if (connect(sock, (struct sockaddr *) &ad6, sizeof(ad6)) != -1) 7809 break; 7810 close(sock); 7811 } 7812 else { 7813 ad.sin_port = htons(clientPort); 7814 sock = socket(AF_INET, SOCK_STREAM, 0); 7815 if (sock < 0) 7816 continue; 7817 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) != -1) 7818 break; 7819 close(sock); 7820 } 7821 } 7822 freeaddrinfo(result); 7823 if (!res) 7824 return (FILE *) NULL; 7825 #else 7826 inaddr = inet_addr(host); 7827 if (inaddr != (unsigned long) -1) 7828 memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr)); 7829 else { 7830 hp = gethostbyname(host); 7831 if (hp == NULL) 7832 return (FILE *) NULL; 7833 memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); 7834 } 7835 ad.sin_port = htons(clientPort); 7836 sock = socket(AF_INET, SOCK_STREAM, 0); 7837 if (sock < 0) 7838 return (FILE *) NULL; 7839 if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0) { 7840 close(sock); 7841 return (FILE *) NULL; 7842 } 7843 #endif /* INET6 */ 7844 7845 fp = fdopen(sock, "r+"); 7846 setvbuf(fp, NULL, _IOLBF, 2048); 7847 return (fp); 7848 } 7849 7850 int SockPrintf(FILE *sockfp, char *format,...) 7851 { 7852 va_list ap; 7853 char buf[16384]; 7854 7855 va_start(ap, format); 7856 vsnprintf(buf, sizeof(buf), format, ap); 7857 buf[sizeof(buf) - 1] = '\0'; 7858 va_end(ap); 7859 return SockWrite(buf, 1, strlen(buf), sockfp); 7860 } 7861 7862 int SockWrite(char *buf, int size, int len, FILE *sockfp) 7863 { 7864 return (fwrite(buf, size, len, sockfp)); 7865 } 7866 7867 char *SockGets(FILE *sockfp, char *buf, int len) 7868 { 7869 return (fgets(buf, len, sockfp)); 7870 } 7871 7872 int SockPuts(FILE *sockfp, char *buf) 7873 { 7874 int rc; 7875 7876 if ((rc = SockWrite(buf, 1, strlen(buf), sockfp))) 7877 return rc; 7878 return SockWrite("\r\n", 1, 2, sockfp); 7879 } 7880 7881 int Reply(FILE *sockfp) 7882 { 7883 char *reply, *rec, *separator; 7884 int ret = 0; 7885 7886 if ((reply = (char *) malloc(BUFSIZ)) == NULL) 7887 return ret; 7888 memset(reply, 0, 1024); 7889 do { 7890 rec = SockGets(sockfp, reply, BUFSIZ); 7891 if (rec != NULL) { 7892 ret = strtol(reply, &separator, 10); 7893 } 7894 else 7895 ret = 250; 7896 } while ((rec != NULL) && (separator[0] != ' ')); 7897 free(reply); 7898 fflush(sockfp); /* Solaris bug: need to clear buf before fwrite() */ 7899 return ret; 7900 } 7901 7902 int Send(FILE *sockfp, char *format,...) 7903 { 7904 va_list ap; 7905 char buf[16384]; 7906 7907 va_start(ap, format); 7908 vsnprintf(buf, sizeof(buf), format, ap); 7909 buf[sizeof(buf) - 1] = '\0'; 7910 va_end(ap); 7911 SockWrite(buf, 1, strlen(buf), sockfp); 7912 return Reply(sockfp); 7913 } 7914 #endif /* MAIL_ADMIN */ 7915 7916 7917 /* 7918 * fixpath 7919 * 7920 * In principal, this is similar to realpath() or the mapping chdir function. 7921 * It removes unnecessary path components. We do this to put a stop to 7922 * attempts to cause a memory starvation DoS. 7923 * 7924 */ 7925 7926 void fixpath(char *path) 7927 { 7928 int abs = 0; 7929 char *in; 7930 char *out; 7931 7932 if (*path == '/') { 7933 abs = 1; 7934 path++; 7935 } 7936 else if (*path == '~') { 7937 do 7938 path++; 7939 while ((*path != '\0') && (*path != '/')); 7940 if (*path == '/') 7941 path++; 7942 } 7943 in = path; 7944 out = path; 7945 while (*in != '\0') { 7946 if (*in == '/') 7947 in++; 7948 else if ((in[0] == '.') && ((in[1] == '/') || (in[1] == '\0'))) { 7949 in++; 7950 if (*in == '/') 7951 in++; 7952 } 7953 else if ((in[0] == '.') && (in[1] == '.') && ((in[2] == '/') || (in[2] == '\0'))) { 7954 if (out == path) { 7955 if (abs) { 7956 in++; 7957 in++; 7958 if (*in == '/') 7959 in++; 7960 } 7961 else { 7962 *out++ = *in++; 7963 *out++ = *in++; 7964 if (*in == '/') 7965 *out++ = *in++; 7966 path = out; 7967 } 7968 } 7969 else { 7970 out--; 7971 while ((out != path) && (*--out != '/')); 7972 in++; 7973 in++; 7974 if (*in == '/') 7975 in++; 7976 } 7977 } 7978 else { 7979 do 7980 *out++ = *in++; 7981 while ((*in != '\0') && (*in != '/')); 7982 if (*in == '/') 7983 *out++ = *in++; 7984 } 7985 } 7986 *out = '\0'; 7987 } 7988 7989 #if defined(SOLARIS_2) 7990 7991 /* Callback function to cleanup_nscd()'s fdwalk(). 7992 * If "fd" has the same inode, device as nscd door 7993 * it returns 1 otherwise it returns 0. 7994 */ 7995 int close_nsdoor(void *cb_data, int fd) 7996 { 7997 struct stat fd_buf; 7998 struct stat *nsdoor_buf = (struct stat *) cb_data; 7999 8000 if (fstat(fd, &fd_buf) != 0) { 8001 return (0); 8002 } 8003 8004 if ((nsdoor_buf->st_dev == fd_buf.st_dev) && 8005 (nsdoor_buf->st_ino == fd_buf.st_ino)) { 8006 close(fd); 8007 return (1); 8008 } 8009 8010 return (0); 8011 } 8012 8013 /* Walk through the list of open file descriptors 8014 * of the ftp dameon and find the nscd door fd and 8015 * close it. 8016 */ 8017 void cleanup_nscd() 8018 { 8019 struct stat nsdoor_buf; 8020 8021 if (stat(NAME_SERVICE_DOOR, &nsdoor_buf) == 0) { 8022 fdwalk(close_nsdoor, &nsdoor_buf); 8023 } 8024 } 8025 8026 #endif