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