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