2 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "ftpd_locl.h"
41 __RCSID("$Heimdal: ftpd.c 21222 2007-06-20 10:11:14Z lha $"
44 static char version
[] = "Version 6.00";
46 extern off_t restart_point
;
49 struct sockaddr_storage ctrl_addr_ss
;
50 struct sockaddr
*ctrl_addr
= (struct sockaddr
*)&ctrl_addr_ss
;
52 struct sockaddr_storage data_source_ss
;
53 struct sockaddr
*data_source
= (struct sockaddr
*)&data_source_ss
;
55 struct sockaddr_storage data_dest_ss
;
56 struct sockaddr
*data_dest
= (struct sockaddr
*)&data_dest_ss
;
58 struct sockaddr_storage his_addr_ss
;
59 struct sockaddr
*his_addr
= (struct sockaddr
*)&his_addr_ss
;
61 struct sockaddr_storage pasv_addr_ss
;
62 struct sockaddr
*pasv_addr
= (struct sockaddr
*)&pasv_addr_ss
;
68 int ftpd_timeout
= 900; /* timeout after 15 minutes of inactivity */
69 int maxtimeout
= 7200;/* don't allow idle time to be set beyond 2 hours */
70 int restricted_data_ports
= 1;
76 int stru
; /* avoid C keyword */
78 int usedefault
= 1; /* for data transfers */
79 int pdata
= -1; /* for passive mode */
80 int allow_insecure_oob
= 1;
85 #if !defined(CMASK) || CMASK == 0
89 int defumask
= CMASK
; /* default umask value */
90 int guest_umask
= 0777; /* Paranoia for anonymous users */
92 char hostname
[MaxHostNameLen
];
93 char remotehost
[MaxHostNameLen
];
94 static char ttyline
[20];
96 #define AUTH_PLAIN (1 << 0) /* allow sending passwords */
97 #define AUTH_OTP (1 << 1) /* passwords are one-time */
98 #define AUTH_FTP (1 << 2) /* allow anonymous login */
100 static int auth_level
= 0; /* Only allow kerberos login by default */
103 * Timeout intervals for retrying connections
104 * to hosts that don't accept PORT cmds. This
105 * is a kludge, but given the problems with TCP...
107 #define SWAITMAX 90 /* wait at most 90 seconds */
108 #define SWAITINT 5 /* interval between retries */
110 int swaitmax
= SWAITMAX
;
111 int swaitint
= SWAITINT
;
113 #ifdef HAVE_SETPROCTITLE
114 char proctitle
[BUFSIZ
]; /* initial part of title */
115 #endif /* HAVE_SETPROCTITLE */
117 #define LOGCMD(cmd, file) \
119 syslog(LOG_INFO,"%s %s%s", cmd, \
120 *(file) == '/' ? "" : curdir(), file);
121 #define LOGCMD2(cmd, file1, file2) \
123 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
124 *(file1) == '/' ? "" : curdir(), file1, \
125 *(file2) == '/' ? "" : curdir(), file2);
126 #define LOGBYTES(cmd, file, cnt) \
128 if (cnt == (off_t)-1) \
129 syslog(LOG_INFO,"%s %s%s", cmd, \
130 *(file) == '/' ? "" : curdir(), file); \
132 syslog(LOG_INFO, "%s %s%s = %ld bytes", \
133 cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
136 static void ack (char *);
137 static void myoob (int);
138 static int handleoobcmd(void);
139 static int checkuser (char *, char *);
140 static int checkaccess (char *);
141 static FILE *dataconn (const char *, off_t
, const char *);
142 static void dolog (struct sockaddr
*, int);
143 static void end_login (void);
144 static FILE *getdatasock (const char *, int);
145 static char *gunique (char *);
146 static RETSIGTYPE
lostconn (int);
147 static int receive_data (FILE *, FILE *);
148 static void send_data (FILE *, FILE *);
149 static struct passwd
* sgetpwnam (char *);
154 static char path
[MaxPathLen
+1]; /* path + '/' + '\0' */
156 if (getcwd(path
, sizeof(path
)-1) == NULL
)
158 if (path
[1] != '\0') /* special case for root dir. */
159 strlcat(path
, "/", sizeof(path
));
160 /* For guest account, skip / since it's chrooted */
161 return (guest
? path
+1 : path
);
165 #define LINE_MAX 1024
169 parse_auth_level(char *str
)
175 for(p
= strtok_r(str
, ",", &foo
);
177 p
= strtok_r(NULL
, ",", &foo
)) {
178 if(strcmp(p
, "user") == 0)
181 else if(strcmp(p
, "otp") == 0)
182 ret
|= AUTH_PLAIN
|AUTH_OTP
;
184 else if(strcmp(p
, "ftp") == 0 ||
185 strcmp(p
, "safe") == 0)
187 else if(strcmp(p
, "plain") == 0)
189 else if(strcmp(p
, "none") == 0)
190 ret
|= AUTH_PLAIN
|AUTH_FTP
;
192 warnx("bad value for -a: `%s'", p
);
198 * Print usage and die.
201 static int interactive_flag
;
202 static char *guest_umask_string
;
203 static char *port_string
;
204 static char *umask_string
;
205 static char *auth_string
;
207 int use_builtin_ls
= -1;
209 static int help_flag
;
210 static int version_flag
;
212 static const char *good_chars
= "+-=_,.";
214 struct getargs args
[] = {
215 { NULL
, 'a', arg_string
, &auth_string
, "required authentication" },
216 { NULL
, 'i', arg_flag
, &interactive_flag
, "don't assume stdin is a socket" },
217 { NULL
, 'p', arg_string
, &port_string
, "what port to listen to" },
218 { NULL
, 'g', arg_string
, &guest_umask_string
, "umask for guest logins" },
219 { NULL
, 'l', arg_counter
, &logging
, "log more stuff", "" },
220 { NULL
, 't', arg_integer
, &ftpd_timeout
, "initial timeout" },
221 { NULL
, 'T', arg_integer
, &maxtimeout
, "max timeout" },
222 { NULL
, 'u', arg_string
, &umask_string
, "umask for user logins" },
223 { NULL
, 'U', arg_negative_flag
, &restricted_data_ports
, "don't use high data ports" },
224 { NULL
, 'd', arg_flag
, &debug
, "enable debugging" },
225 { NULL
, 'v', arg_flag
, &debug
, "enable debugging" },
226 { "builtin-ls", 'B', arg_flag
, &use_builtin_ls
, "use built-in ls to list files" },
227 { "good-chars", 0, arg_string
, &good_chars
, "allowed anonymous upload filename chars" },
228 { "insecure-oob", 'I', arg_negative_flag
, &allow_insecure_oob
, "don't allow insecure OOB ABOR/STAT" },
230 { "gss-bindings", 0, arg_flag
, &ftp_do_gss_bindings
, "Require GSS-API bindings", NULL
},
232 { "version", 0, arg_flag
, &version_flag
},
233 { "help", 'h', arg_flag
, &help_flag
}
236 static int num_args
= sizeof(args
) / sizeof(args
[0]);
241 arg_printusage(args
, num_args
, NULL
, "");
245 /* output contents of a file */
247 show_file(const char *file
, int code
)
252 f
= fopen(file
, "r");
255 while(fgets(buf
, sizeof(buf
), f
)){
256 buf
[strcspn(buf
, "\r\n")] = '\0';
257 lreply(code
, "%s", buf
);
264 main(int argc
, char **argv
)
266 socklen_t his_addr_len
, ctrl_addr_len
;
273 setprogname (argv
[0]);
275 /* detach from any tickets and tokens */
279 snprintf(tkfile
, sizeof(tkfile
),
280 "/tmp/ftp_%u", (unsigned)getpid());
281 krb_set_tkt_string(tkfile
);
285 if(getarg(args
, num_args
, argc
, argv
, &optind
))
297 auth_level
= parse_auth_level(auth_string
);
302 if(guest_umask_string
) {
303 val
= strtol(guest_umask_string
, &p
, 8);
304 if (*p
!= '\0' || val
< 0)
305 warnx("bad value for -g");
310 val
= strtol(umask_string
, &p
, 8);
311 if (*p
!= '\0' || val
< 0)
312 warnx("bad value for -u");
317 sp
= getservbyname("ftp", "tcp");
323 sp
= getservbyname(port_string
, "tcp");
327 if(isdigit((unsigned char)port_string
[0]))
328 port
= htons(atoi(port_string
));
330 warnx("bad value for -p");
333 if (maxtimeout
< ftpd_timeout
)
334 maxtimeout
= ftpd_timeout
;
337 if (ftpd_timeout
> maxtimeout
)
338 ftpd_timeout
= maxtimeout
;
345 * LOG_NDELAY sets up the logging connection immediately,
346 * necessary for anonymous ftp's that chroot and can't do it later.
348 openlog("ftpd", LOG_PID
| LOG_NDELAY
, LOG_FTP
);
349 his_addr_len
= sizeof(his_addr_ss
);
350 if (getpeername(STDIN_FILENO
, his_addr
, &his_addr_len
) < 0) {
351 syslog(LOG_ERR
, "getpeername (%s): %m",argv
[0]);
354 ctrl_addr_len
= sizeof(ctrl_addr_ss
);
355 if (getsockname(STDIN_FILENO
, ctrl_addr
, &ctrl_addr_len
) < 0) {
356 syslog(LOG_ERR
, "getsockname (%s): %m",argv
[0]);
359 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
361 int tos
= IPTOS_LOWDELAY
;
363 if (setsockopt(STDIN_FILENO
, IPPROTO_IP
, IP_TOS
,
364 (void *)&tos
, sizeof(int)) < 0)
365 syslog(LOG_WARNING
, "setsockopt (IP_TOS): %m");
368 data_source
->sa_family
= ctrl_addr
->sa_family
;
369 socket_set_port (data_source
,
370 htons(ntohs(socket_get_port(ctrl_addr
)) - 1));
372 /* set this here so it can be put in wtmp */
373 snprintf(ttyline
, sizeof(ttyline
), "ftp%u", (unsigned)getpid());
376 /* freopen(_PATH_DEVNULL, "w", stderr); */
377 signal(SIGPIPE
, lostconn
);
378 signal(SIGCHLD
, SIG_IGN
);
380 if (signal(SIGURG
, myoob
) == SIG_ERR
)
381 syslog(LOG_ERR
, "signal: %m");
384 /* Try to handle urgent data inline */
385 #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
386 if (setsockopt(0, SOL_SOCKET
, SO_OOBINLINE
, (void *)&on
,
388 syslog(LOG_ERR
, "setsockopt: %m");
392 if (fcntl(fileno(stdin
), F_SETOWN
, getpid()) == -1)
393 syslog(LOG_ERR
, "fcntl F_SETOWN: %m");
395 dolog(his_addr
, his_addr_len
);
397 * Set up default state
406 /* If logins are disabled, print out the message. */
407 if(show_file(_PATH_NOLOGIN
, 530) == 0) {
408 reply(530, "System not available.");
411 show_file(_PATH_FTPWELCOME
, 220);
412 /* reply(220,) must follow */
413 gethostname(hostname
, sizeof(hostname
));
415 reply(220, "%s FTP server (%s"
422 ") ready.", hostname
, version
441 syslog(LOG_DEBUG
, "lost connection");
446 * Helper function for sgetpwnam().
451 char *new = strdup(s
);
454 perror_reply(421, "Local resource failure: malloc");
462 * Save the result of a getpwnam. Used for USER command, since
463 * the data returned must not be clobbered by any other command
466 static struct passwd
*
467 sgetpwnam(char *name
)
469 static struct passwd save
;
472 if ((p
= k_getpwnam(name
)) == NULL
)
476 free(save
.pw_passwd
);
482 save
.pw_name
= sgetsave(p
->pw_name
);
483 save
.pw_passwd
= sgetsave(p
->pw_passwd
);
484 save
.pw_gecos
= sgetsave(p
->pw_gecos
);
485 save
.pw_dir
= sgetsave(p
->pw_dir
);
486 save
.pw_shell
= sgetsave(p
->pw_shell
);
490 static int login_attempts
; /* number of failed login attempts */
491 static int askpasswd
; /* had user command, ask for passwd */
492 static char curname
[10]; /* current USER name */
499 * Sets global passwd pointer pw if named account exists and is acceptable;
500 * sets askpasswd if a PASS command is expected. If logged in previously,
501 * need to reset state. If name is "ftp" or "anonymous", the name is not in
502 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
503 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
504 * requesting login privileges. Disallow anyone who does not have a standard
505 * shell as returned by getusershell(). Disallow anyone mentioned in the file
506 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
513 if(auth_level
== 0 && !sec_complete
){
514 reply(530, "No login allowed without authorization.");
520 reply(530, "Can't change user from guest login.");
522 } else if (dochroot
) {
523 reply(530, "Can't change user from chroot user.");
530 if (strcmp(name
, "ftp") == 0 || strcmp(name
, "anonymous") == 0) {
531 if ((auth_level
& AUTH_FTP
) == 0 ||
532 checkaccess("ftp") ||
533 checkaccess("anonymous"))
534 reply(530, "User %s access denied.", name
);
535 else if ((pw
= sgetpwnam("ftp")) != NULL
) {
537 defumask
= guest_umask
; /* paranoia for incoming */
539 reply(331, "Guest login ok, type your name as password.");
541 reply(530, "User %s unknown.", name
);
542 if (!askpasswd
&& logging
) {
545 if (inet_ntop (his_addr
->sa_family
,
546 socket_get_address(his_addr
),
547 data_addr
, sizeof(data_addr
)) == NULL
)
548 strlcpy (data_addr
, "unknown address",
552 "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
553 remotehost
, data_addr
);
557 if((auth_level
& AUTH_PLAIN
) == 0 && !sec_complete
){
558 reply(530, "Only authorized and anonymous login allowed.");
561 if ((pw
= sgetpwnam(name
))) {
562 if ((shell
= pw
->pw_shell
) == NULL
|| *shell
== 0)
563 shell
= _PATH_BSHELL
;
564 while ((cp
= getusershell()) != NULL
)
565 if (strcmp(cp
, shell
) == 0)
569 if (cp
== NULL
|| checkaccess(name
)) {
570 reply(530, "User %s access denied.", name
);
574 if (inet_ntop (his_addr
->sa_family
,
575 socket_get_address(his_addr
),
577 sizeof(data_addr
)) == NULL
)
583 "FTP LOGIN REFUSED FROM %s(%s), %s",
588 pw
= (struct passwd
*) NULL
;
593 strlcpy(curname
, name
, sizeof(curname
));
595 if(sec_userok(name
) == 0) {
599 reply(530, "User %s access denied.", name
);
604 if (otp_challenge(&otp_ctx
, name
, ss
, sizeof(ss
)) == 0) {
605 reply(331, "Password %s for %s required.",
610 if ((auth_level
& AUTH_OTP
) == 0) {
611 reply(331, "Password required for %s.", name
);
617 if ((s
= otp_error (&otp_ctx
)) != NULL
)
618 lreply(530, "OTP: %s", s
);
621 "Only authorized, anonymous"
630 * Delay before reading passwd after first failed
631 * attempt to slow down passwd-guessing programs.
634 sleep(login_attempts
);
638 * Check if a user is in the file "fname"
641 checkuser(char *fname
, char *name
)
645 char *p
, line
[BUFSIZ
];
647 if ((fd
= fopen(fname
, "r")) != NULL
) {
648 while (fgets(line
, sizeof(line
), fd
) != NULL
)
649 if ((p
= strchr(line
, '\n')) != NULL
) {
653 if (strcmp(line
, name
) == 0) {
665 * Determine whether a user has access, based on information in
666 * _PATH_FTPUSERS. The users are listed one per line, with `allow'
667 * or `deny' after the username. If anything other than `allow', or
668 * just nothing, is given after the username, `deny' is assumed.
670 * If the user is not found in the file, but the pseudo-user `*' is,
671 * the permission is taken from that line.
673 * This preserves the old semantics where if a user was listed in the
674 * file he was denied, otherwise he was allowed.
676 * Return 1 if the user is denied, or 0 if he is allowed. */
679 match(const char *pattern
, const char *string
)
681 return fnmatch(pattern
, string
, FNM_NOESCAPE
);
685 checkaccess(char *name
)
688 #define NOT_ALLOWED 1
690 int allowed
= ALLOWED
;
691 char *user
, *perm
, line
[BUFSIZ
];
694 fd
= fopen(_PATH_FTPUSERS
, "r");
699 while (fgets(line
, sizeof(line
), fd
) != NULL
) {
701 user
= strtok_r(line
, " \t\n", &foo
);
702 if (user
== NULL
|| user
[0] == '#')
704 perm
= strtok_r(NULL
, " \t\n", &foo
);
705 if (match(user
, name
) == 0){
706 if(perm
&& strcmp(perm
, "allow") == 0)
709 allowed
= NOT_ALLOWED
;
720 int do_login(int code
, char *passwd
)
722 login_attempts
= 0; /* this time successful */
723 if (setegid((gid_t
)pw
->pw_gid
) < 0) {
724 reply(550, "Can't set gid.");
727 initgroups(pw
->pw_name
, pw
->pw_gid
);
728 #if defined(KRB4) || defined(KRB5)
733 /* open wtmp before chroot */
734 ftpd_logwtmp(ttyline
, pw
->pw_name
, remotehost
);
737 dochroot
= checkuser(_PATH_FTPCHROOT
, pw
->pw_name
);
740 * We MUST do a chdir() after the chroot. Otherwise
741 * the old current directory will be accessible as "."
742 * outside the new root!
744 if (chroot(pw
->pw_dir
) < 0 || chdir("/") < 0) {
745 reply(550, "Can't set guest privileges.");
748 } else if (dochroot
) {
749 if (chroot(pw
->pw_dir
) < 0 || chdir("/") < 0) {
750 reply(550, "Can't change root.");
753 } else if (chdir(pw
->pw_dir
) < 0) {
754 if (chdir("/") < 0) {
755 reply(530, "User %s: can't change directory to %s.",
756 pw
->pw_name
, pw
->pw_dir
);
759 lreply(code
, "No directory! Logging in with home=/");
761 if (seteuid((uid_t
)pw
->pw_uid
) < 0) {
762 reply(550, "Can't set uid.");
766 if(use_builtin_ls
== -1) {
768 /* if /bin/ls exist and is a regular file, use it, otherwise
770 if(stat("/bin/ls", &st
) == 0 &&
778 * Display a login message, if it exists.
779 * N.B. reply(code,) must follow the message.
781 show_file(_PATH_FTPLOGINMESG
, code
);
782 if(show_file(_PATH_ISSUE_NET
, code
) != 0)
783 show_file(_PATH_ISSUE
, code
);
785 reply(code
, "Guest login ok, access restrictions apply.");
786 #ifdef HAVE_SETPROCTITLE
787 snprintf (proctitle
, sizeof(proctitle
),
791 setproctitle("%s", proctitle
);
792 #endif /* HAVE_SETPROCTITLE */
796 if (inet_ntop (his_addr
->sa_family
,
797 socket_get_address(his_addr
),
798 data_addr
, sizeof(data_addr
)) == NULL
)
799 strlcpy (data_addr
, "unknown address",
802 syslog(LOG_INFO
, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
808 reply(code
, "User %s logged in.", pw
->pw_name
);
809 #ifdef HAVE_SETPROCTITLE
810 snprintf(proctitle
, sizeof(proctitle
), "%s: %s", remotehost
, pw
->pw_name
);
811 setproctitle("%s", proctitle
);
812 #endif /* HAVE_SETPROCTITLE */
816 if (inet_ntop (his_addr
->sa_family
,
817 socket_get_address(his_addr
),
818 data_addr
, sizeof(data_addr
)) == NULL
)
819 strlcpy (data_addr
, "unknown address",
822 syslog(LOG_INFO
, "FTP LOGIN FROM %s(%s) as %s",
833 * Terminate login as previous user, if any, resetting state;
834 * used when USER command is given or login fails.
840 if (seteuid((uid_t
)0) < 0)
841 fatal("Failed to seteuid");
843 ftpd_logwtmp(ttyline
, "", "");
852 krb5_verify(struct passwd
*pwd
, char *passwd
)
854 krb5_context context
;
856 krb5_principal princ
;
859 ret
= krb5_init_context(&context
);
863 ret
= krb5_parse_name(context
, pwd
->pw_name
, &princ
);
865 krb5_free_context(context
);
868 ret
= krb5_cc_gen_new(context
, &krb5_mcc_ops
, &id
);
870 krb5_free_principal(context
, princ
);
871 krb5_free_context(context
);
874 ret
= krb5_verify_user(context
,
880 krb5_free_principal(context
, princ
);
882 krb5_afslog_uid_home(context
, id
,NULL
, NULL
,pwd
->pw_uid
, pwd
->pw_dir
);
884 krb5_cc_destroy(context
, id
);
885 krb5_free_context (context
);
897 /* some clients insists on sending a password */
898 if (logged_in
&& askpasswd
== 0){
899 reply(230, "Password not necessary");
903 if (logged_in
|| askpasswd
== 0) {
904 reply(503, "Login with USER first.");
909 if (!guest
) { /* "ftp" is only account allowed no password */
911 rval
= 1; /* failure below */
913 else if (otp_verify_user (&otp_ctx
, passwd
) == 0) {
917 else if((auth_level
& AUTH_OTP
) == 0) {
919 rval
= krb5_verify(pw
, passwd
);
923 char realm
[REALM_SZ
];
924 if((rval
= krb_get_lrealm(realm
, 1)) == KSUCCESS
)
925 rval
= krb_verify_user(pw
->pw_name
,
928 KRB_VERIFY_SECURE
, NULL
);
929 if (rval
== KSUCCESS
) {
930 chown (tkt_string(), pw
->pw_uid
, pw
->pw_gid
);
937 rval
= unix_verify_user(pw
->pw_name
, passwd
);
941 if ((s
= otp_error(&otp_ctx
)) != NULL
)
942 lreply(530, "OTP: %s", s
);
945 memset (passwd
, 0, strlen(passwd
));
948 * If rval == 1, the user failed the authentication
949 * check above. If rval == 0, either Kerberos or
950 * local authentication succeeded.
955 if (inet_ntop (his_addr
->sa_family
,
956 socket_get_address(his_addr
),
957 data_addr
, sizeof(data_addr
)) == NULL
)
958 strlcpy (data_addr
, "unknown address",
961 reply(530, "Login incorrect.");
964 "FTP LOGIN FAILED FROM %s(%s), %s",
969 if (login_attempts
++ >= 5) {
971 "repeated login failures from %s(%s)",
979 if(!do_login(230, passwd
))
982 /* Forget all about it... */
987 retrieve(const char *cmd
, char *name
)
989 FILE *fin
= NULL
, *dout
;
991 int (*closefunc
) (FILE *);
996 fin
= fopen(name
, "r");
1000 int save_errno
= errno
;
1004 const char *rev_cmd
;
1006 {".tar", "/bin/gtar cPf - %s", NULL
},
1007 {".tar.gz", "/bin/gtar zcPf - %s", NULL
},
1008 {".tar.Z", "/bin/gtar ZcPf - %s", NULL
},
1009 {".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
1010 {".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
1014 for(p
= cmds
; p
->ext
; p
++){
1015 char *tail
= name
+ strlen(name
) - strlen(p
->ext
);
1018 if(strcmp(tail
, p
->ext
) == 0 &&
1020 access(name
, R_OK
) == 0){
1021 snprintf (line
, sizeof(line
), p
->cmd
, name
);
1026 if (p
->rev_cmd
!= NULL
) {
1030 ret
= asprintf(&ext
, "%s%s", name
, p
->ext
);
1032 if (access(ext
, R_OK
) == 0) {
1033 snprintf (line
, sizeof(line
),
1044 fin
= ftpd_popen(line
, "r", 0, 0);
1045 closefunc
= ftpd_pclose
;
1052 snprintf(line
, sizeof(line
), cmd
, name
);
1054 fin
= ftpd_popen(line
, "r", 1, 0);
1055 closefunc
= ftpd_pclose
;
1060 perror_reply(550, name
);
1062 LOGCMD("get", name
);
1069 if(fstat(fileno(fin
), &st
) < 0 || !S_ISREG(st
.st_mode
)) {
1070 reply(550, "%s: not a plain file.", name
);
1074 if (restart_point
) {
1075 if (type
== TYPE_A
) {
1082 if ((c
=getc(fin
)) == EOF
) {
1083 perror_reply(550, name
);
1089 } else if (lseek(fileno(fin
), restart_point
, SEEK_SET
) < 0) {
1090 perror_reply(550, name
);
1094 dout
= dataconn(name
, st
.st_size
, "w");
1097 set_buffer_size(fileno(dout
), 0);
1098 send_data(fin
, dout
);
1104 LOGBYTES("get", name
, byte_count
);
1108 /* filename sanity check */
1111 filename_check(char *filename
)
1115 p
= strrchr(filename
, '/');
1121 if(isalnum((unsigned char)*p
)){
1123 while(*p
&& (isalnum((unsigned char)*p
) || strchr(good_chars
, (unsigned char)*p
)))
1128 lreply(553, "\"%s\" is not an acceptable filename.", filename
);
1129 lreply(553, "The filename must start with an alphanumeric "
1130 "character and must only");
1131 reply(553, "consist of alphanumeric characters or any of the following: %s",
1137 do_store(char *name
, char *mode
, int unique
)
1141 int (*closefunc
) (FILE *);
1143 if(guest
&& filename_check(name
))
1145 if (unique
&& stat(name
, &st
) == 0 &&
1146 (name
= gunique(name
)) == NULL
) {
1147 LOGCMD(*mode
== 'w' ? "put" : "append", name
);
1153 fout
= fopen(name
, mode
);
1156 perror_reply(553, name
);
1157 LOGCMD(*mode
== 'w' ? "put" : "append", name
);
1161 if (restart_point
) {
1162 if (type
== TYPE_A
) {
1169 if ((c
=getc(fout
)) == EOF
) {
1170 perror_reply(550, name
);
1177 * We must do this seek to "current" position
1178 * because we are changing from reading to
1181 if (fseek(fout
, 0L, SEEK_CUR
) < 0) {
1182 perror_reply(550, name
);
1185 } else if (lseek(fileno(fout
), restart_point
, SEEK_SET
) < 0) {
1186 perror_reply(550, name
);
1190 din
= dataconn(name
, (off_t
)-1, "r");
1193 set_buffer_size(fileno(din
), 1);
1194 if (receive_data(din
, fout
) == 0) {
1195 if((*closefunc
)(fout
) < 0)
1196 perror_reply(552, name
);
1199 reply(226, "Transfer complete (unique file name:%s).",
1202 reply(226, "Transfer complete.");
1210 LOGBYTES(*mode
== 'w' ? "put" : "append", name
, byte_count
);
1214 getdatasock(const char *mode
, int domain
)
1219 return (fdopen(data
, mode
));
1221 fatal("Failed to seteuid");
1222 s
= socket(domain
, SOCK_STREAM
, 0);
1225 socket_set_reuseaddr (s
, 1);
1226 /* anchor socket to avoid multi-homing problems */
1227 socket_set_address_and_port (data_source
,
1228 socket_get_address (ctrl_addr
),
1229 socket_get_port (data_source
));
1231 for (tries
= 1; ; tries
++) {
1232 if (bind(s
, data_source
,
1233 socket_sockaddr_size (data_source
)) >= 0)
1235 if (errno
!= EADDRINUSE
|| tries
> 10)
1239 if (seteuid(pw
->pw_uid
) < 0)
1240 fatal("Failed to seteuid");
1241 #ifdef IPTOS_THROUGHPUT
1242 socket_set_tos (s
, IPTOS_THROUGHPUT
);
1244 return (fdopen(s
, mode
));
1246 /* Return the real value of errno (close may change it) */
1248 if (seteuid((uid_t
)pw
->pw_uid
) < 0)
1249 fatal("Failed to seteuid");
1256 accept_with_timeout(int socket
,
1257 struct sockaddr
*address
,
1258 socklen_t
*address_len
,
1259 struct timeval
*timeout
)
1264 FD_SET(socket
, &rfd
);
1265 ret
= select(socket
+ 1, &rfd
, NULL
, NULL
, timeout
);
1272 return accept(socket
, address
, address_len
);
1276 dataconn(const char *name
, off_t size
, const char *mode
)
1280 int domain
, retry
= 0;
1285 snprintf(sizebuf
, sizeof(sizebuf
), " (%ld bytes)", (long)size
);
1289 struct sockaddr_storage from_ss
;
1290 struct sockaddr
*from
= (struct sockaddr
*)&from_ss
;
1291 struct timeval timeout
;
1293 socklen_t fromlen
= sizeof(from_ss
);
1295 timeout
.tv_sec
= 15;
1296 timeout
.tv_usec
= 0;
1297 s
= accept_with_timeout(pdata
, from
, &fromlen
, &timeout
);
1299 reply(425, "Can't open data connection.");
1306 #if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
1308 int tos
= IPTOS_THROUGHPUT
;
1310 setsockopt(s
, IPPROTO_IP
, IP_TOS
, (void *)&tos
,
1314 reply(150, "Opening %s mode data connection for '%s'%s.",
1315 type
== TYPE_A
? "ASCII" : "BINARY", name
, sizebuf
);
1316 return (fdopen(pdata
, mode
));
1319 reply(125, "Using existing data connection for '%s'%s.",
1322 return (fdopen(data
, mode
));
1325 data_dest
= his_addr
;
1328 * Default to using the same socket type as the ctrl address,
1329 * unless we know the type of the data address.
1331 domain
= data_dest
->sa_family
;
1332 if (domain
== PF_UNSPEC
)
1333 domain
= ctrl_addr
->sa_family
;
1335 file
= getdatasock(mode
, domain
);
1337 char data_addr
[256];
1339 if (inet_ntop (data_source
->sa_family
,
1340 socket_get_address(data_source
),
1341 data_addr
, sizeof(data_addr
)) == NULL
)
1342 strlcpy (data_addr
, "unknown address",
1345 reply(425, "Can't create data socket (%s,%d): %s.",
1347 socket_get_port (data_source
),
1351 data
= fileno(file
);
1352 while (connect(data
, data_dest
,
1353 socket_sockaddr_size(data_dest
)) < 0) {
1354 if (errno
== EADDRINUSE
&& retry
< swaitmax
) {
1359 perror_reply(425, "Can't build data connection");
1364 reply(150, "Opening %s mode data connection for '%s'%s.",
1365 type
== TYPE_A
? "ASCII" : "BINARY", name
, sizebuf
);
1370 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1371 * encapsulation of the data subject * to Mode, Structure, and Type.
1373 * NB: Form isn't handled.
1376 send_data(FILE *instr
, FILE *outstr
)
1378 int c
, cnt
, filefd
, netfd
;
1380 static size_t bufsize
;
1386 while ((c
= getc(instr
)) != EOF
) {
1387 if (urgflag
&& handleoobcmd())
1391 sec_putc('\r', outstr
);
1392 sec_putc(c
, outstr
);
1401 reply(226, "Transfer complete.");
1406 #if 0 /* XXX handle urg flag */
1407 #if defined(HAVE_MMAP) && !defined(NO_MMAP)
1409 #define MAP_FAILED (-1)
1414 int in
= fileno(instr
);
1415 if(fstat(in
, &st
) == 0 && S_ISREG(st
.st_mode
)
1416 && st
.st_size
> 0) {
1418 * mmap zero bytes has potential of loosing, don't do it.
1420 chunk
= mmap(0, st
.st_size
, PROT_READ
,
1422 if((void *)chunk
!= (void *)MAP_FAILED
) {
1423 cnt
= st
.st_size
- restart_point
;
1424 sec_write(fileno(outstr
), chunk
+ restart_point
, cnt
);
1425 if (munmap(chunk
, st
.st_size
) < 0)
1439 netfd
= fileno(outstr
);
1440 filefd
= fileno(instr
);
1441 buf
= alloc_buffer (buf
, &bufsize
,
1442 fstat(filefd
, &st
) >= 0 ? &st
: NULL
);
1446 perror_reply(451, "Local resource failure: malloc");
1449 while ((cnt
= read(filefd
, buf
, bufsize
)) > 0 &&
1450 sec_write(netfd
, buf
, cnt
) == cnt
) {
1452 if (urgflag
&& handleoobcmd())
1455 sec_fflush(outstr
); /* to end an encrypted stream */
1464 reply(226, "Transfer complete.");
1469 reply(550, "Unimplemented TYPE %d in send_data", type
);
1476 perror_reply(426, "Data connection");
1482 perror_reply(551, "Error on input file");
1486 * Transfer data from peer to "outstr" using the appropriate encapulation of
1487 * the data subject to Mode, Structure, and Type.
1489 * N.B.: Form isn't handled.
1492 receive_data(FILE *instr
, FILE *outstr
)
1494 int cnt
, bare_lfs
= 0;
1496 static size_t bufsize
;
1501 buf
= alloc_buffer (buf
, &bufsize
,
1502 fstat(fileno(outstr
), &st
) >= 0 ? &st
: NULL
);
1506 perror_reply(451, "Local resource failure: malloc");
1514 while ((cnt
= sec_read(fileno(instr
), buf
, bufsize
)) > 0) {
1515 if (write(fileno(outstr
), buf
, cnt
) != cnt
)
1518 if (urgflag
&& handleoobcmd())
1528 reply(553, "TYPE E not implemented.");
1537 while ((cnt
= sec_read(fileno(instr
),
1539 bufsize
- cr_flag
)) > 0){
1540 if (urgflag
&& handleoobcmd())
1545 for(p
= buf
, q
= buf
; p
< buf
+ cnt
;) {
1549 if(p
== buf
+ cnt
- 1){
1553 }else if(p
[1] == '\n'){
1561 fwrite(buf
, q
- buf
, 1, outstr
);
1575 lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1576 " File may not have transferred correctly.\r\n",
1582 reply(550, "Unimplemented TYPE %d in receive_data", type
);
1591 perror_reply(426, "Data Connection");
1597 perror_reply(452, "Error writing file");
1602 statfilecmd(char *filename
)
1606 char line
[LINE_MAX
];
1608 snprintf(line
, sizeof(line
), "/bin/ls -la -- %s", filename
);
1609 fin
= ftpd_popen(line
, "r", 1, 0);
1610 lreply(211, "status of %s:", filename
);
1611 while ((c
= getc(fin
)) != EOF
) {
1613 if (ferror(stdout
)){
1614 perror_reply(421, "control connection");
1620 perror_reply(551, filename
);
1629 reply(211, "End of Status");
1636 struct sockaddr_in
*sin
;
1639 lreply(211, "%s FTP server (%s) status:", hostname
, version
);
1640 printf(" %s\r\n", version
);
1641 printf(" Connected to %s", remotehost
);
1642 if (!isdigit((unsigned char)remotehost
[0]))
1643 printf(" (%s)", inet_ntoa(his_addr
.sin_addr
));
1647 printf(" Logged in anonymously\r\n");
1649 printf(" Logged in as %s\r\n", pw
->pw_name
);
1650 } else if (askpasswd
)
1651 printf(" Waiting for password\r\n");
1653 printf(" Waiting for user name\r\n");
1654 printf(" TYPE: %s", typenames
[type
]);
1655 if (type
== TYPE_A
|| type
== TYPE_E
)
1656 printf(", FORM: %s", formnames
[form
]);
1659 printf(" %d", NBBY
);
1661 printf(" %d", bytesize
); /* need definition! */
1663 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1664 strunames
[stru
], modenames
[mode
]);
1666 printf(" Data connection open\r\n");
1667 else if (pdata
!= -1) {
1668 printf(" in Passive mode");
1671 } else if (usedefault
== 0) {
1675 a
= (u_char
*) &sin
->sin_addr
;
1676 p
= (u_char
*) &sin
->sin_port
;
1677 #define UC(b) (((int) b) & 0xff)
1678 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a
[0]),
1679 UC(a
[1]), UC(a
[2]), UC(a
[3]), UC(p
[0]), UC(p
[1]));
1682 printf(" No data connection\r\n");
1684 reply(211, "End of status");
1691 reply(451, "Error in server: %s\n", s
);
1692 reply(221, "Closing connection due to server error.");
1698 int_reply(int, char *, const char *, va_list)
1700 __attribute__ ((format (printf
, 3, 0)))
1705 int_reply(int n
, char *c
, const char *fmt
, va_list ap
)
1711 snprintf(p
, sizeof(buf
), "%d%s", n
, c
);
1714 vsnprintf(p
, sizeof(buf
) - strlen(p
), fmt
, ap
);
1716 snprintf(p
, sizeof(buf
) - strlen(p
), "\r\n");
1718 sec_fprintf(stdout
, "%s", buf
);
1721 syslog(LOG_DEBUG
, "<--- %s- ", buf
);
1725 reply(int n
, const char *fmt
, ...)
1729 int_reply(n
, " ", fmt
, ap
);
1730 delete_ftp_command();
1735 lreply(int n
, const char *fmt
, ...)
1739 int_reply(n
, "-", fmt
, ap
);
1744 nreply(const char *fmt
, ...)
1748 int_reply(0, NULL
, fmt
, ap
);
1756 reply(250, "%s command successful.", s
);
1763 reply(502, "%s command not implemented.", s
);
1767 do_delete(char *name
)
1771 LOGCMD("delete", name
);
1772 if (stat(name
, &st
) < 0) {
1773 perror_reply(550, name
);
1776 if ((st
.st_mode
&S_IFMT
) == S_IFDIR
) {
1777 if (rmdir(name
) < 0) {
1778 perror_reply(550, name
);
1783 if (unlink(name
) < 0) {
1784 perror_reply(550, name
);
1795 if (chdir(path
) < 0)
1796 perror_reply(550, path
);
1805 LOGCMD("mkdir", name
);
1806 if(guest
&& filename_check(name
))
1808 if (mkdir(name
, 0777) < 0)
1809 perror_reply(550, name
);
1812 chmod(name
, 0700); /* guest has umask 777 */
1813 reply(257, "MKD command successful.");
1818 removedir(char *name
)
1821 LOGCMD("rmdir", name
);
1822 if (rmdir(name
) < 0)
1823 perror_reply(550, name
);
1831 char path
[MaxPathLen
];
1834 /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1835 * failes miserably when running chroot
1837 ret
= getcwd(path
, sizeof(path
));
1839 reply(550, "%s.", strerror(errno
));
1841 reply(257, "\"%s\" is current directory.", path
);
1845 renamefrom(char *name
)
1849 if (stat(name
, &st
) < 0) {
1850 perror_reply(550, name
);
1853 reply(350, "File exists, ready for destination name");
1858 renamecmd(char *from
, char *to
)
1861 LOGCMD2("rename", from
, to
);
1862 if(guest
&& filename_check(to
))
1864 if (rename(from
, to
) < 0)
1865 perror_reply(550, "rename");
1871 dolog(struct sockaddr
*sa
, int len
)
1873 getnameinfo_verified (sa
, len
, remotehost
, sizeof(remotehost
),
1875 #ifdef HAVE_SETPROCTITLE
1876 snprintf(proctitle
, sizeof(proctitle
), "%s: connected", remotehost
);
1877 setproctitle("%s", proctitle
);
1878 #endif /* HAVE_SETPROCTITLE */
1881 char data_addr
[256];
1883 if (inet_ntop (his_addr
->sa_family
,
1884 socket_get_address(his_addr
),
1885 data_addr
, sizeof(data_addr
)) == NULL
)
1886 strlcpy (data_addr
, "unknown address",
1890 syslog(LOG_INFO
, "connection from %s(%s)",
1897 * Record logout in wtmp file
1898 * and exit with supplied status.
1901 dologout(int status
)
1909 seteuid((uid_t
)0); /* No need to check, we call exit() below */
1910 ftpd_logwtmp(ttyline
, "", "");
1912 /* beware of flushing buffers after a SIGPIPE */
1924 reply(426, "Transfer aborted. Data connection closed.");
1925 reply(226, "Abort successful");
1938 while(isspace(*(unsigned char *)p
))
1948 /* only process if transfer occurring */
1955 if (ftpd_getline(cp
, sizeof(tmpline
)) == NULL
) {
1956 reply(221, "You could at least say goodbye.");
1960 if (strncasecmp("MIC", cp
, 3) == 0) {
1961 mec(mec_space(cp
+ 3), prot_safe
);
1962 } else if (strncasecmp("CONF", cp
, 4) == 0) {
1963 mec(mec_space(cp
+ 4), prot_confidential
);
1964 } else if (strncasecmp("ENC", cp
, 3) == 0) {
1965 mec(mec_space(cp
+ 3), prot_private
);
1966 } else if (!allow_insecure_oob
) {
1967 reply(533, "Command protection level denied "
1968 "for paranoid reasons.");
1972 if (secure_command())
1975 if (strcasecmp(cp
, "ABOR\r\n") == 0) {
1977 } else if (strcasecmp(cp
, "STAT\r\n") == 0) {
1978 if (file_size
!= (off_t
) -1)
1979 reply(213, "Status: %ld of %ld bytes transferred",
1983 reply(213, "Status: %ld bytes transferred",
1987 return (transflag
== 0);
1991 * Note: a response of 425 is not mentioned as a possible response to
1992 * the PASV command in RFC959. However, it has been blessed as
1993 * a legitimate response by Jon Postel in a telephone conversation
1994 * with Rick Adams on 25 Jan 89.
2001 struct sockaddr_in
*sin
;
2003 if (ctrl_addr
->sa_family
!= AF_INET
) {
2005 "You cannot do PASV with something that's not IPv4");
2012 pdata
= socket(ctrl_addr
->sa_family
, SOCK_STREAM
, 0);
2014 perror_reply(425, "Can't open passive connection");
2017 pasv_addr
->sa_family
= ctrl_addr
->sa_family
;
2018 socket_set_address_and_port (pasv_addr
,
2019 socket_get_address (ctrl_addr
),
2021 socket_set_portrange(pdata
, restricted_data_ports
,
2022 pasv_addr
->sa_family
);
2024 fatal("Failed to seteuid");
2025 if (bind(pdata
, pasv_addr
, socket_sockaddr_size (pasv_addr
)) < 0) {
2026 if (seteuid(pw
->pw_uid
) < 0)
2027 fatal("Failed to seteuid");
2030 if (seteuid(pw
->pw_uid
) < 0)
2031 fatal("Failed to seteuid");
2032 len
= sizeof(pasv_addr_ss
);
2033 if (getsockname(pdata
, pasv_addr
, &len
) < 0)
2035 if (listen(pdata
, 1) < 0)
2037 sin
= (struct sockaddr_in
*)pasv_addr
;
2038 a
= (char *) &sin
->sin_addr
;
2039 p
= (char *) &sin
->sin_port
;
2041 #define UC(b) (((int) b) & 0xff)
2043 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a
[0]),
2044 UC(a
[1]), UC(a
[2]), UC(a
[3]), UC(p
[0]), UC(p
[1]));
2050 perror_reply(425, "Can't open passive connection");
2059 pdata
= socket(ctrl_addr
->sa_family
, SOCK_STREAM
, 0);
2061 perror_reply(425, "Can't open passive connection");
2064 pasv_addr
->sa_family
= ctrl_addr
->sa_family
;
2065 socket_set_address_and_port (pasv_addr
,
2066 socket_get_address (ctrl_addr
),
2068 socket_set_portrange(pdata
, restricted_data_ports
,
2069 pasv_addr
->sa_family
);
2071 fatal("Failed to seteuid");
2072 if (bind(pdata
, pasv_addr
, socket_sockaddr_size (pasv_addr
)) < 0) {
2073 if (seteuid(pw
->pw_uid
))
2074 fatal("Failed to seteuid");
2077 if (seteuid(pw
->pw_uid
) < 0)
2078 fatal("Failed to seteuid");
2079 len
= sizeof(pasv_addr_ss
);
2080 if (getsockname(pdata
, pasv_addr
, &len
) < 0)
2082 if (listen(pdata
, 1) < 0)
2085 reply(229, "Entering Extended Passive Mode (|||%d|)",
2086 ntohs(socket_get_port (pasv_addr
)));
2092 perror_reply(425, "Can't open passive connection");
2113 reply(500, "Bad syntax in EPRT");
2116 af
= strtol (str
, &end
, 0);
2117 if (af
== 0 || *end
!= sep
) {
2118 reply(500, "Bad syntax in EPRT");
2125 data_dest
->sa_family
= AF_INET6
;
2129 data_dest
->sa_family
= AF_INET
;
2132 reply(522, "Network protocol %d not supported, use (1"
2139 end
= strchr (str
, sep
);
2141 reply(500, "Bad syntax in EPRT");
2145 ret
= inet_pton (data_dest
->sa_family
, str
,
2146 socket_get_address (data_dest
));
2149 reply(500, "Bad address syntax in EPRT");
2153 port
= strtol (str
, &end
, 0);
2154 if (port
== 0 || *end
!= sep
) {
2155 reply(500, "Bad port syntax in EPRT");
2158 socket_set_port (data_dest
, htons(port
));
2159 reply(200, "EPRT command successful.");
2163 * Generate unique name for file with basename "local".
2164 * The file named "local" is already known to exist.
2165 * Generates failure reply on error.
2168 gunique(char *local
)
2170 static char new[MaxPathLen
];
2175 cp
= strrchr(local
, '/');
2178 if (stat(cp
? local
: ".", &st
) < 0) {
2179 perror_reply(553, cp
? local
: ".");
2184 for (count
= 1; count
< 100; count
++) {
2185 snprintf (new, sizeof(new), "%s.%d", local
, count
);
2186 if (stat(new, &st
) < 0)
2189 reply(452, "Unique file name cannot be created.");
2194 * Format and send reply containing system error number.
2197 perror_reply(int code
, const char *string
)
2199 reply(code
, "%s: %s.", string
, strerror(errno
));
2202 static char *onefile
[] = {
2208 list_file(char *file
)
2210 if(use_builtin_ls
) {
2212 dout
= dataconn(file
, -1, "w");
2215 set_buffer_size(fileno(dout
), 0);
2216 if(builtin_ls(dout
, file
) == 0)
2217 reply(226, "Transfer complete.");
2219 reply(451, "Requested action aborted. Local error in processing.");
2225 const char *cmd
= "/bin/ls -lA %s";
2227 const char *cmd
= "/bin/ls -la %s";
2229 retrieve(cmd
, file
);
2234 send_file_list(char *whichf
)
2240 char **dirlist
, *dirname
;
2244 char buf
[MaxPathLen
];
2246 if (strpbrk(whichf
, "~{[*?") != NULL
) {
2247 int flags
= GLOB_BRACE
|GLOB_NOCHECK
|GLOB_QUOTE
|GLOB_TILDE
|
2255 memset(&gl
, 0, sizeof(gl
));
2257 if (glob(whichf
, flags
, 0, &gl
)) {
2258 reply(550, "not found");
2260 } else if (gl
.gl_pathc
== 0) {
2262 perror_reply(550, whichf
);
2265 dirlist
= gl
.gl_pathv
;
2267 onefile
[0] = whichf
;
2272 while ((dirname
= *dirlist
++)) {
2274 if (urgflag
&& handleoobcmd())
2277 if (stat(dirname
, &st
) < 0) {
2279 * If user typed "ls -l", etc, and the client
2280 * used NLST, do what the user meant.
2282 if (dirname
[0] == '-' && *dirlist
== NULL
&&
2287 perror_reply(550, whichf
);
2291 if (S_ISREG(st
.st_mode
)) {
2293 dout
= dataconn("file list", (off_t
)-1, "w");
2298 snprintf(buf
, sizeof(buf
), "%s%s\n", dirname
,
2299 type
== TYPE_A
? "\r" : "");
2300 sec_write(fileno(dout
), buf
, strlen(buf
));
2301 byte_count
+= strlen(dirname
) + 1;
2303 } else if (!S_ISDIR(st
.st_mode
))
2306 if ((dirp
= opendir(dirname
)) == NULL
)
2309 while ((dir
= readdir(dirp
)) != NULL
) {
2310 char nbuf
[MaxPathLen
];
2312 if (urgflag
&& handleoobcmd())
2315 if (!strcmp(dir
->d_name
, "."))
2317 if (!strcmp(dir
->d_name
, ".."))
2320 snprintf(nbuf
, sizeof(nbuf
), "%s/%s", dirname
, dir
->d_name
);
2323 * We have to do a stat to insure it's
2324 * not a directory or special file.
2326 if (simple
|| (stat(nbuf
, &st
) == 0 &&
2327 S_ISREG(st
.st_mode
))) {
2329 dout
= dataconn("file list", (off_t
)-1, "w");
2334 if(strncmp(nbuf
, "./", 2) == 0)
2335 snprintf(buf
, sizeof(buf
), "%s%s\n", nbuf
+2,
2336 type
== TYPE_A
? "\r" : "");
2338 snprintf(buf
, sizeof(buf
), "%s%s\n", nbuf
,
2339 type
== TYPE_A
? "\r" : "");
2340 sec_write(fileno(dout
), buf
, strlen(buf
));
2341 byte_count
+= strlen(nbuf
) + 1;
2347 reply(550, "No files found.");
2348 else if (ferror(dout
) != 0)
2349 perror_reply(550, "Data connection");
2351 reply(226, "Transfer complete.");
2356 sec_write(fileno(dout
), buf
, 0); /* XXX flush */
2375 snprintf(line
, sizeof(line
),
2376 "/bin/locate -d %s -- %s",
2377 ftp_rooted("/etc/locatedb"),
2379 f
= ftpd_popen(line
, "r", 1, 1);
2381 perror_reply(550, "/bin/locate");
2384 lreply(200, "Output from find.");
2385 while(fgets(line
, sizeof(line
), f
)){
2386 if(line
[strlen(line
)-1] == '\n')
2387 line
[strlen(line
)-1] = 0;