ftpd.c revision 1.73 1 /* $NetBSD: ftpd.c,v 1.73 1999/12/12 14:05:54 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1997-1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
41 * The Regents of the University of California. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the University of
54 * California, Berkeley and its contributors.
55 * 4. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71
72 /*
73 * Copyright (C) 1997 and 1998 WIDE Project.
74 * All rights reserved.
75 *
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions
78 * are met:
79 * 1. Redistributions of source code must retain the above copyright
80 * notice, this list of conditions and the following disclaimer.
81 * 2. Redistributions in binary form must reproduce the above copyright
82 * notice, this list of conditions and the following disclaimer in the
83 * documentation and/or other materials provided with the distribution.
84 * 3. Neither the name of the project nor the names of its contributors
85 * may be used to endorse or promote products derived from this software
86 * without specific prior written permission.
87 *
88 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 * SUCH DAMAGE.
99 */
100
101 #include <sys/cdefs.h>
102 #ifndef lint
103 __COPYRIGHT(
104 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
105 The Regents of the University of California. All rights reserved.\n");
106 #endif /* not lint */
107
108 #ifndef lint
109 #if 0
110 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
111 #else
112 __RCSID("$NetBSD: ftpd.c,v 1.73 1999/12/12 14:05:54 lukem Exp $");
113 #endif
114 #endif /* not lint */
115
116 /*
117 * FTP server.
118 */
119 #include <sys/param.h>
120 #include <sys/stat.h>
121 #include <sys/ioctl.h>
122 #include <sys/socket.h>
123 #include <sys/wait.h>
124
125 #include <netinet/in.h>
126 #include <netinet/in_systm.h>
127 #include <netinet/ip.h>
128
129 #define FTP_NAMES
130 #include <arpa/ftp.h>
131 #include <arpa/inet.h>
132 #include <arpa/telnet.h>
133
134 #include <ctype.h>
135 #include <dirent.h>
136 #include <err.h>
137 #include <errno.h>
138 #include <fcntl.h>
139 #include <fnmatch.h>
140 #include <glob.h>
141 #include <limits.h>
142 #include <netdb.h>
143 #include <pwd.h>
144 #include <setjmp.h>
145 #include <signal.h>
146 #include <stdio.h>
147 #include <stdlib.h>
148 #include <string.h>
149 #include <syslog.h>
150 #include <time.h>
151 #include <unistd.h>
152 #include <util.h>
153 #ifdef SKEY
154 #include <skey.h>
155 #endif
156 #ifdef KERBEROS5
157 #include <kerberosIV/com_err.h>
158 #include <krb5/krb5.h>
159 #endif
160
161 #include "extern.h"
162 #include "pathnames.h"
163
164 #if __STDC__
165 #include <stdarg.h>
166 #else
167 #include <varargs.h>
168 #endif
169
170 const char version[] = "NetBSD-ftpd 19991213";
171
172 union sockunion ctrl_addr;
173 union sockunion data_source;
174 union sockunion data_dest;
175 union sockunion his_addr;
176 union sockunion pasv_addr;
177
178 int data;
179 jmp_buf errcatch, urgcatch;
180 int logged_in;
181 struct passwd *pw;
182 int debug;
183 int sflag;
184 int logging;
185 int type;
186 int form;
187 int stru; /* avoid C keyword */
188 int mode;
189 int usedefault = 1; /* for data transfers */
190 int pdata = -1; /* for passive mode */
191 int family = AF_INET;
192 sig_atomic_t transflag;
193 off_t file_size;
194 off_t byte_count;
195 char tmpline[7];
196 char hostname[MAXHOSTNAMELEN+1];
197 char remotehost[MAXHOSTNAMELEN+1];
198 static char ttyline[20];
199 char *tty = ttyline; /* for klogin */
200
201 off_t total_data_in; /* total file data bytes received */
202 off_t total_data_out; /* total file data bytes sent data */
203 off_t total_data; /* total file data bytes transferred data */
204 off_t total_files_in; /* total number of data files received */
205 off_t total_files_out; /* total number of data files sent */
206 off_t total_files; /* total number of data files transferred */
207 off_t total_bytes_in; /* total bytes received */
208 off_t total_bytes_out; /* total bytes sent */
209 off_t total_bytes; /* total bytes transferred */
210 off_t total_xfers_in; /* total number of xfers incoming */
211 off_t total_xfers_out; /* total number of xfers outgoing */
212 off_t total_xfers; /* total number of xfers */
213
214 static char *anondir = NULL;
215 static char confdir[MAXPATHLEN];
216
217 #if defined(KERBEROS) || defined(KERBEROS5)
218 int notickets = 1;
219 char *krbtkfile_env = NULL;
220 #endif
221
222 int epsvall = 0;
223
224 /*
225 * Timeout intervals for retrying connections
226 * to hosts that don't accept PORT cmds. This
227 * is a kludge, but given the problems with TCP...
228 */
229 #define SWAITMAX 90 /* wait at most 90 seconds */
230 #define SWAITINT 5 /* interval between retries */
231
232 int swaitmax = SWAITMAX;
233 int swaitint = SWAITINT;
234
235 #ifdef HASSETPROCTITLE
236 char proctitle[BUFSIZ]; /* initial part of title */
237 #endif /* HASSETPROCTITLE */
238
239 static void ack __P((const char *));
240 static void myoob __P((int));
241 static int checkuser __P((const char *, const char *, int, int, char **));
242 static int checkaccess __P((const char *));
243 static FILE *dataconn __P((const char *, off_t, const char *));
244 static void dolog __P((struct sockaddr *));
245 static void end_login __P((void));
246 static FILE *getdatasock __P((const char *));
247 static char *gunique __P((const char *));
248 static void lostconn __P((int));
249 static int receive_data __P((FILE *, FILE *));
250 static void replydirname __P((const char *, const char *));
251 static int send_data __P((FILE *, FILE *, off_t, int));
252 static struct passwd *
253 sgetpwnam __P((const char *));
254
255 int main __P((int, char *[]));
256
257 #if defined(KERBEROS) || defined(KERBEROS5)
258 int klogin __P((struct passwd *, char *, char *, char *));
259 void kdestroy __P((void));
260 #endif
261
262 int
263 main(argc, argv)
264 int argc;
265 char *argv[];
266 {
267 int addrlen, ch, on = 1, tos, keepalive;
268 #ifdef KERBEROS5
269 krb5_error_code kerror;
270 #endif
271
272 debug = 0;
273 logging = 0;
274 sflag = 0;
275 (void)strcpy(confdir, _DEFAULT_CONFDIR);
276
277 while ((ch = getopt(argc, argv, "a:c:C:dlst:T:u:v46")) != -1) {
278 switch (ch) {
279 case 'a':
280 anondir = optarg;
281 break;
282
283 case 'c':
284 (void)strlcpy(confdir, optarg, sizeof(confdir));
285 break;
286
287 case 'C':
288 exit(checkaccess(optarg) ? 0 : 1);
289 /* NOTREACHED */
290
291 case 'd':
292 case 'v': /* deprecated */
293 debug = 1;
294 break;
295
296 case 'l':
297 logging++; /* > 1 == extra logging */
298 break;
299
300 case 's':
301 sflag = 1;
302 break;
303
304 case 't':
305 case 'T':
306 case 'u':
307 warnx("-%c has been deprecated in favour of ftpd.conf",
308 ch);
309 break;
310
311 case '4':
312 family = AF_INET;
313 break;
314
315 case '6':
316 family = AF_INET6;
317 break;
318
319 default:
320 if (optopt == 'a' || optopt == 'C')
321 exit(1);
322 warnx("unknown flag -%c ignored", optopt);
323 break;
324 }
325 }
326
327 /*
328 * LOG_NDELAY sets up the logging connection immediately,
329 * necessary for anonymous ftp's that chroot and can't do it later.
330 */
331 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
332 addrlen = sizeof(his_addr); /* xxx */
333 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
334 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
335 exit(1);
336 }
337 addrlen = sizeof(ctrl_addr);
338 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
339 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
340 exit(1);
341 }
342 if (his_addr.su_family == AF_INET6
343 && IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) {
344 #if 1
345 /*
346 * IPv4 control connection arrived to AF_INET6 socket.
347 * I hate to do this, but this is the easiest solution.
348 */
349 union sockunion tmp_addr;
350
351 tmp_addr = his_addr;
352 memset(&his_addr, 0, sizeof(his_addr));
353 his_addr.su_sin.sin_family = AF_INET;
354 his_addr.su_sin.sin_len = sizeof(his_addr.su_sin);
355 memcpy(&his_addr.su_sin.sin_addr,
356 &tmp_addr.su_sin6.sin6_addr.s6_addr32[3],
357 sizeof(his_addr.su_sin.sin_addr));
358 his_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
359
360 tmp_addr = ctrl_addr;
361 memset(&ctrl_addr, 0, sizeof(ctrl_addr));
362 ctrl_addr.su_sin.sin_family = AF_INET;
363 ctrl_addr.su_sin.sin_len = sizeof(ctrl_addr.su_sin);
364 memcpy(&ctrl_addr.su_sin.sin_addr,
365 &tmp_addr.su_sin6.sin6_addr.s6_addr32[3],
366 sizeof(ctrl_addr.su_sin.sin_addr));
367 ctrl_addr.su_sin.sin_port = tmp_addr.su_sin6.sin6_port;
368 #else
369 while (fgets(line, sizeof(line), fd) != NULL) {
370 if ((cp = strchr(line, '\n')) != NULL)
371 *cp = '\0';
372 lreply(530, "%s", line);
373 }
374 (void) fflush(stdout);
375 (void) fclose(fd);
376 reply(530,
377 "Connection from IPv4 mapped address is not supported.");
378 exit(0);
379 #endif
380 }
381 #ifdef IP_TOS
382 if (family == AF_INET) {
383 tos = IPTOS_LOWDELAY;
384 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos,
385 sizeof(int)) < 0)
386 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
387 }
388 #endif
389 data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1);
390
391 /* set this here so klogin can use it... */
392 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
393
394 (void) freopen(_PATH_DEVNULL, "w", stderr);
395 (void) signal(SIGPIPE, lostconn);
396 (void) signal(SIGCHLD, SIG_IGN);
397 if ((long)signal(SIGURG, myoob) < 0)
398 syslog(LOG_ERR, "signal: %m");
399
400 /* Try to handle urgent data inline */
401 #ifdef SO_OOBINLINE
402 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
403 syslog(LOG_ERR, "setsockopt: %m");
404 #endif
405 /* Set keepalives on the socket to detect dropped connections. */
406 #ifdef SO_KEEPALIVE
407 keepalive = 1;
408 if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive,
409 sizeof(int)) < 0)
410 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
411 #endif
412
413 #ifdef F_SETOWN
414 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
415 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
416 #endif
417 dolog((struct sockaddr *)&his_addr);
418 /*
419 * Set up default state
420 */
421 data = -1;
422 type = TYPE_A;
423 form = FORM_N;
424 stru = STRU_F;
425 mode = MODE_S;
426 tmpline[0] = '\0';
427 hasyyerrored = 0;
428
429 #ifdef KERBEROS5
430 kerror = krb5_init_context(&kcontext);
431 if (kerror) {
432 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
433 error_message(kerror));
434 exit(0);
435 }
436 #endif /* KERBEROS5 */
437
438 /* If logins are disabled, print out the message. */
439 if (format_file(_PATH_NOLOGIN, 530)) {
440 reply(530, "System not available.");
441 exit(0);
442 }
443 (void)format_file(conffilename(_PATH_FTPWELCOME), 220);
444 /* reply(220,) must follow */
445 (void)gethostname(hostname, sizeof(hostname));
446 hostname[sizeof(hostname) - 1] = '\0';
447 reply(220, "%s FTP server (%s) ready.", hostname, version);
448
449 curclass.timeout = 300; /* 5 minutes, as per login(1) */
450 curclass.type = CLASS_REAL;
451
452 (void) setjmp(errcatch);
453 for (;;)
454 (void) yyparse();
455 /* NOTREACHED */
456 }
457
458 static void
459 lostconn(signo)
460 int signo;
461 {
462
463 if (debug)
464 syslog(LOG_DEBUG, "lost connection");
465 dologout(1);
466 }
467
468 /*
469 * Save the result of a getpwnam. Used for USER command, since
470 * the data returned must not be clobbered by any other command
471 * (e.g., globbing).
472 */
473 static struct passwd *
474 sgetpwnam(name)
475 const char *name;
476 {
477 static struct passwd save;
478 struct passwd *p;
479
480 if ((p = getpwnam(name)) == NULL)
481 return (p);
482 if (save.pw_name) {
483 free((char *)save.pw_name);
484 free((char *)save.pw_passwd);
485 free((char *)save.pw_gecos);
486 free((char *)save.pw_dir);
487 free((char *)save.pw_shell);
488 }
489 save = *p;
490 save.pw_name = xstrdup(p->pw_name);
491 save.pw_passwd = xstrdup(p->pw_passwd);
492 save.pw_gecos = xstrdup(p->pw_gecos);
493 save.pw_dir = xstrdup(p->pw_dir);
494 save.pw_shell = xstrdup(p->pw_shell);
495 return (&save);
496 }
497
498 static int login_attempts; /* number of failed login attempts */
499 static int askpasswd; /* had user command, ask for passwd */
500 static char curname[10]; /* current USER name */
501
502 /*
503 * USER command.
504 * Sets global passwd pointer pw if named account exists and is acceptable;
505 * sets askpasswd if a PASS command is expected. If logged in previously,
506 * need to reset state. If name is "ftp" or "anonymous", the name is not in
507 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
508 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
509 * requesting login privileges. Disallow anyone who does not have a standard
510 * shell as returned by getusershell(). Disallow anyone mentioned in the file
511 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
512 */
513 void
514 user(name)
515 const char *name;
516 {
517 if (logged_in) {
518 switch (curclass.type) {
519 case CLASS_GUEST:
520 reply(530, "Can't change user from guest login.");
521 return;
522 case CLASS_CHROOT:
523 reply(530, "Can't change user from chroot user.");
524 return;
525 case CLASS_REAL:
526 end_login();
527 break;
528 default:
529 abort();
530 }
531 }
532
533 #if defined(KERBEROS) || defined(KERBEROS5)
534 kdestroy();
535 #endif
536
537 curclass.type = CLASS_REAL;
538 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
539 if (! checkaccess("ftp") && ! checkaccess("anonymous"))
540 reply(530, "User %s access denied.", name);
541 else if ((pw = sgetpwnam("ftp")) != NULL) {
542 curclass.type = CLASS_GUEST;
543 askpasswd = 1;
544 reply(331,
545 "Guest login ok, type your name as password.");
546 } else
547 reply(530, "User %s unknown.", name);
548 if (!askpasswd && logging)
549 syslog(LOG_NOTICE,
550 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
551 return;
552 }
553
554 pw = sgetpwnam(name);
555 if (logging)
556 strlcpy(curname, name, sizeof(curname));
557
558 #ifdef SKEY
559 if (skey_haskey(name) == 0) {
560 char *myskey;
561
562 myskey = skey_keyinfo(name);
563 reply(331, "Password [%s] required for %s.",
564 myskey ? myskey : "error getting challenge", name);
565 } else
566 #endif
567 reply(331, "Password required for %s.", name);
568
569 askpasswd = 1;
570 /*
571 * Delay before reading passwd after first failed
572 * attempt to slow down passwd-guessing programs.
573 */
574 if (login_attempts)
575 sleep((unsigned) login_attempts);
576 }
577
578 /*
579 * Determine whether something is to happen (allow access, chroot)
580 * for a user. Each line is a shell-style glob followed by
581 * `yes' or `no'.
582 *
583 * For backward compatability, `allow' and `deny' are synonymns
584 * for `yes' and `no', respectively.
585 *
586 * Each glob is matched against the username in turn, and the first
587 * match found is used. If no match is found, the result is the
588 * argument `def'. If a match is found but without and explicit
589 * `yes'/`no', the result is the opposite of def.
590 *
591 * If the file doesn't exist at all, the result is the argument
592 * `nofile'
593 *
594 * Any line starting with `#' is considered a comment and ignored.
595 *
596 * Returns 0 if the user is denied, or 1 if they are allowed.
597 */
598 int
599 checkuser(fname, name, def, nofile, retclass)
600 const char *fname, *name;
601 int def, nofile;
602 char **retclass;
603 {
604 FILE *fd;
605 int retval;
606 char *glob, *perm, *class, *buf, *p;
607 size_t len;
608
609 retval = def;
610 if (retclass != NULL)
611 *retclass = NULL;
612 if ((fd = fopen(conffilename(fname), "r")) == NULL)
613 return nofile;
614
615 for (;
616 (buf = fparseln(fd, &len, NULL, NULL, FPARSELN_UNESCCOMM |
617 FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL;
618 free(buf), buf = NULL) {
619 glob = perm = class = NULL;
620 p = buf;
621 if (len < 1)
622 continue;
623 if (p[len - 1] == '\n')
624 p[--len] = '\0';
625 if (EMPTYSTR(p))
626 continue;
627
628 NEXTWORD(p, glob);
629 NEXTWORD(p, perm);
630 NEXTWORD(p, class);
631 if (EMPTYSTR(glob))
632 continue;
633
634 /* have a host specifier */
635 if ((p = strchr(glob, '@')) != NULL) {
636 u_int32_t net, mask, addr;
637 int bits;
638
639 *p++ = '\0';
640 /* check against network or CIDR */
641 if (isdigit(*p) &&
642 (bits = inet_net_pton(AF_INET, p,
643 &net, sizeof(net))) != -1) {
644 net = ntohl(net);
645 mask = 0xffffffffU << (32 - bits);
646 addr = ntohl(his_addr.su_sin.sin_addr.s_addr);
647 if ((addr & mask) != net)
648 continue;
649
650 /* check against hostname glob */
651 } else if (fnmatch(p, remotehost, 0) != 0)
652 continue;
653 }
654
655 /* check against username glob */
656 if (fnmatch(glob, name, 0) != 0)
657 continue;
658
659 if (perm != NULL &&
660 ((strcasecmp(perm, "allow") == 0) ||
661 (strcasecmp(perm, "yes") == 0)))
662 retval = 1;
663 else if (perm != NULL &&
664 ((strcasecmp(perm, "deny") == 0) ||
665 (strcasecmp(perm, "no") == 0)))
666 retval = 0;
667 else
668 retval = !def;
669 if (!EMPTYSTR(class) && retclass != NULL)
670 *retclass = xstrdup(class);
671 free(buf);
672 break;
673 }
674 (void) fclose(fd);
675 return (retval);
676 }
677
678 /*
679 * Check if user is allowed by /etc/ftpusers
680 * returns 1 for yes, 0 for no
681 */
682 int
683 checkaccess(name)
684 const char *name;
685 {
686
687 return (checkuser(_PATH_FTPUSERS, name, 1, 0, NULL));
688 }
689
690 /*
691 * Terminate login as previous user, if any, resetting state;
692 * used when USER command is given or login fails.
693 */
694 static void
695 end_login()
696 {
697
698 (void) seteuid((uid_t)0);
699 if (logged_in)
700 logwtmp(ttyline, "", "");
701 pw = NULL;
702 logged_in = 0;
703 curclass.type = CLASS_REAL;
704 }
705
706 void
707 pass(passwd)
708 const char *passwd;
709 {
710 int rval;
711 const char *cp, *shell, *home;
712 char *class;
713
714 class = NULL;
715 if (logged_in || askpasswd == 0) {
716 reply(503, "Login with USER first.");
717 return;
718 }
719 askpasswd = 0;
720 if (curclass.type != CLASS_GUEST) {
721 /* "ftp" is only account allowed no password */
722 if (pw == NULL) {
723 rval = 1; /* failure below */
724 goto skip;
725 }
726 #if defined(KERBEROS) || defined(KERBEROS5)
727 if (klogin(pw, "", hostname, (char *)passwd) == 0) {
728 rval = 0;
729 goto skip;
730 }
731 #endif
732 #ifdef SKEY
733 if (skey_haskey(pw->pw_name) == 0) {
734 char *p;
735 int r;
736
737 p = xstrdup(passwd);
738 r = skey_passcheck(pw->pw_name, p);
739 free(p);
740 if (r != -1) {
741 rval = 0;
742 goto skip;
743 }
744 }
745 #endif
746 if (!sflag && *pw->pw_passwd != '\0' &&
747 !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
748 rval = 0;
749 goto skip;
750 }
751 rval = 1;
752
753 skip:
754 if (pw != NULL && pw->pw_expire && time(NULL) >= pw->pw_expire)
755 rval = 2;
756 /*
757 * If rval > 0, the user failed the authentication check
758 * above. If rval == 0, either Kerberos or local authentication
759 * succeeded.
760 */
761 if (rval) {
762 reply(530, rval == 2 ? "Password expired." :
763 "Login incorrect.");
764 if (logging) {
765 syslog(LOG_NOTICE,
766 "FTP LOGIN FAILED FROM %s", remotehost);
767 syslog(LOG_AUTHPRIV | LOG_NOTICE,
768 "FTP LOGIN FAILED FROM %s, %s",
769 remotehost, curname);
770 }
771 pw = NULL;
772 if (login_attempts++ >= 5) {
773 syslog(LOG_NOTICE,
774 "repeated login failures from %s",
775 remotehost);
776 exit(0);
777 }
778 return;
779 }
780 }
781
782 /* password was ok; see if anything else prevents login */
783 if (! checkuser(_PATH_FTPUSERS, pw->pw_name, 1, 0, &class)) {
784 reply(530, "User %s may not use FTP.", pw->pw_name);
785 if (logging)
786 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
787 remotehost, pw->pw_name);
788 pw = (struct passwd *) NULL;
789 goto cleanuppass;
790 }
791 /* check for valid shell, if not guest user */
792 if ((shell = pw->pw_shell) == NULL || *shell == 0)
793 shell = _PATH_BSHELL;
794 while ((cp = getusershell()) != NULL)
795 if (strcmp(cp, shell) == 0)
796 break;
797 endusershell();
798 if (cp == NULL && curclass.type != CLASS_GUEST) {
799 reply(530, "User %s may not use FTP.", pw->pw_name);
800 if (logging)
801 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
802 remotehost, pw->pw_name);
803 pw = (struct passwd *) NULL;
804 goto cleanuppass;
805 }
806
807 login_attempts = 0; /* this time successful */
808 if (setegid((gid_t)pw->pw_gid) < 0) {
809 reply(550, "Can't set gid.");
810 goto cleanuppass;
811 }
812 (void) initgroups(pw->pw_name, pw->pw_gid);
813
814 /* open wtmp before chroot */
815 logwtmp(ttyline, pw->pw_name, remotehost);
816 logged_in = 1;
817
818 /* check user in /etc/ftpchroot */
819 if (checkuser(_PATH_FTPCHROOT, pw->pw_name, 0, 0, NULL)) {
820 if (curclass.type == CLASS_GUEST) {
821 syslog(LOG_NOTICE,
822 "Can't change guest user to chroot class; remove entry in %s",
823 _PATH_FTPCHROOT);
824 exit(1);
825 }
826 curclass.type = CLASS_CHROOT;
827 }
828 if (class == NULL) {
829 switch (curclass.type) {
830 case CLASS_GUEST:
831 class = xstrdup("guest");
832 break;
833 case CLASS_CHROOT:
834 class = xstrdup("chroot");
835 break;
836 case CLASS_REAL:
837 class = xstrdup("real");
838 break;
839 default:
840 abort();
841 }
842 }
843
844 /* parse ftpd.conf, setting up various parameters */
845 parse_conf(class);
846
847 home = "/";
848 switch (curclass.type) {
849 case CLASS_GUEST:
850 /*
851 * We MUST do a chdir() after the chroot. Otherwise
852 * the old current directory will be accessible as "."
853 * outside the new root!
854 */
855 if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
856 chdir("/") < 0) {
857 reply(550, "Can't set guest privileges.");
858 goto bad;
859 }
860 break;
861 case CLASS_CHROOT:
862 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
863 reply(550, "Can't change root.");
864 goto bad;
865 }
866 break;
867 case CLASS_REAL:
868 if (chdir(pw->pw_dir) < 0) {
869 if (chdir("/") < 0) {
870 reply(530,
871 "User %s: can't change directory to %s.",
872 pw->pw_name, pw->pw_dir);
873 goto bad;
874 } else
875 lreply(230,
876 "No directory! Logging in with home=/");
877 } else
878 home = pw->pw_dir;
879 break;
880 }
881 if (seteuid((uid_t)pw->pw_uid) < 0) {
882 reply(550, "Can't set uid.");
883 goto bad;
884 }
885 setenv("HOME", home, 1);
886
887 /*
888 * Display a login message, if it exists.
889 * N.B. reply(230,) must follow the message.
890 */
891 (void)format_file(conffilename(curclass.motd), 230);
892 show_chdir_messages(230);
893 if (curclass.type == CLASS_GUEST) {
894 reply(230, "Guest login ok, access restrictions apply.");
895 #ifdef HASSETPROCTITLE
896 snprintf(proctitle, sizeof(proctitle),
897 "%s: anonymous/%.*s", remotehost,
898 (int) (sizeof(proctitle) - sizeof(remotehost) -
899 sizeof(": anonymous/")), passwd);
900 setproctitle(proctitle);
901 #endif /* HASSETPROCTITLE */
902 if (logging)
903 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
904 remotehost, passwd);
905 } else {
906 reply(230, "User %s logged in.", pw->pw_name);
907 #ifdef HASSETPROCTITLE
908 snprintf(proctitle, sizeof(proctitle),
909 "%s: %s", remotehost, pw->pw_name);
910 setproctitle(proctitle);
911 #endif /* HASSETPROCTITLE */
912 if (logging)
913 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
914 remotehost, pw->pw_name);
915 }
916 (void) umask(curclass.umask);
917 goto cleanuppass;
918 bad:
919 /* Forget all about it... */
920 end_login();
921 cleanuppass:
922 if (class)
923 free(class);
924 }
925
926 void
927 retrieve(argv, name)
928 char *argv[];
929 const char *name;
930 {
931 FILE *fin = NULL, *dout;
932 struct stat st;
933 int (*closefunc) __P((FILE *)) = NULL;
934 int log, sendrv, closerv, stderrfd, isconversion, isdata, isls;
935 struct timeval start, finish, td, *tdp;
936 const char *dispname;
937
938 sendrv = closerv = stderrfd = -1;
939 isconversion = isdata = isls = log = 0;
940 tdp = NULL;
941 dispname = name;
942 if (argv == NULL) {
943 log = 1;
944 isdata = 1;
945 fin = fopen(name, "r");
946 closefunc = fclose;
947 if (fin == NULL)
948 argv = do_conversion(name);
949 if (argv != NULL) {
950 isconversion++;
951 syslog(LOG_INFO, "get command: '%s' on '%s'",
952 argv[0], name);
953 }
954 }
955 if (argv != NULL) {
956 char temp[MAXPATHLEN + 1];
957
958 if (strcmp(argv[0], INTERNAL_LS) == 0) {
959 isls = 1;
960 stderrfd = -1;
961 } else {
962 (void)snprintf(temp, sizeof(temp), "%s", TMPFILE);
963 stderrfd = mkstemp(temp);
964 if (stderrfd != -1)
965 (void)unlink(temp);
966 }
967 dispname = argv[0];
968 fin = ftpd_popen(argv, "r", stderrfd);
969 closefunc = ftpd_pclose;
970 st.st_size = -1;
971 st.st_blksize = BUFSIZ;
972 }
973 if (fin == NULL) {
974 if (errno != 0) {
975 perror_reply(550, dispname);
976 if (log)
977 logcmd("get", -1, name, NULL, NULL,
978 strerror(errno));
979 }
980 goto cleanupretrieve;
981 }
982 byte_count = -1;
983 if (argv == NULL
984 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
985 reply(550, "%s: not a plain file.", dispname);
986 goto done;
987 }
988 if (restart_point) {
989 if (type == TYPE_A) {
990 off_t i;
991 int c;
992
993 for (i = 0; i < restart_point; i++) {
994 if ((c=getc(fin)) == EOF) {
995 perror_reply(550, dispname);
996 goto done;
997 }
998 if (c == '\n')
999 i++;
1000 }
1001 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1002 perror_reply(550, dispname);
1003 goto done;
1004 }
1005 }
1006 dout = dataconn(dispname, st.st_size, "w");
1007 if (dout == NULL)
1008 goto done;
1009
1010 (void)gettimeofday(&start, NULL);
1011 sendrv = send_data(fin, dout, st.st_blksize, isdata);
1012 (void)gettimeofday(&finish, NULL);
1013 (void) fclose(dout);
1014 timersub(&finish, &start, &td);
1015 tdp = &td;
1016 data = -1;
1017 pdata = -1;
1018 done:
1019 if (log)
1020 logcmd("get", byte_count, name, NULL, tdp, NULL);
1021 closerv = (*closefunc)(fin);
1022 if (sendrv == 0) {
1023 FILE *err;
1024 struct stat sb;
1025
1026 if (!isls && argv != NULL && closerv != 0) {
1027 lreply(226,
1028 "Command returned an exit status of %d",
1029 closerv);
1030 if (isconversion)
1031 syslog(LOG_INFO,
1032 "retrieve command: '%s' returned %d",
1033 argv[0], closerv);
1034 }
1035 if (!isls && argv != NULL && stderrfd != -1 &&
1036 (fstat(stderrfd, &sb) == 0) && sb.st_size > 0 &&
1037 ((err = fdopen(stderrfd, "r")) != NULL)) {
1038 char *cp, line[LINE_MAX];
1039
1040 lreply(226, "Command error messages:");
1041 rewind(err);
1042 while (fgets(line, sizeof(line), err) != NULL) {
1043 if ((cp = strchr(line, '\n')) != NULL)
1044 *cp = '\0';
1045 lreply(0, " %s", line);
1046 }
1047 (void) fflush(stdout);
1048 (void) fclose(err);
1049 /* a reply(226,) must follow */
1050 }
1051 reply(226, "Transfer complete.");
1052 }
1053 cleanupretrieve:
1054 if (stderrfd != -1)
1055 (void)close(stderrfd);
1056 if (isconversion)
1057 free(argv);
1058 }
1059
1060 void
1061 store(name, mode, unique)
1062 const char *name, *mode;
1063 int unique;
1064 {
1065 FILE *fout, *din;
1066 struct stat st;
1067 int (*closefunc) __P((FILE *));
1068 struct timeval start, finish, td, *tdp;
1069 char *desc;
1070
1071 desc = (*mode == 'w') ? "put" : "append";
1072 if (unique && stat(name, &st) == 0 &&
1073 (name = gunique(name)) == NULL) {
1074 logcmd(desc, -1, name, NULL, NULL, "cannot create unique file");
1075 return;
1076 }
1077
1078 if (restart_point)
1079 mode = "r+";
1080 fout = fopen(name, mode);
1081 closefunc = fclose;
1082 tdp = NULL;
1083 if (fout == NULL) {
1084 perror_reply(553, name);
1085 logcmd(desc, -1, name, NULL, NULL, strerror(errno));
1086 return;
1087 }
1088 byte_count = -1;
1089 if (restart_point) {
1090 if (type == TYPE_A) {
1091 off_t i;
1092 int c;
1093
1094 for (i = 0; i < restart_point; i++) {
1095 if ((c=getc(fout)) == EOF) {
1096 perror_reply(550, name);
1097 goto done;
1098 }
1099 if (c == '\n')
1100 i++;
1101 }
1102 /*
1103 * We must do this seek to "current" position
1104 * because we are changing from reading to
1105 * writing.
1106 */
1107 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1108 perror_reply(550, name);
1109 goto done;
1110 }
1111 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1112 perror_reply(550, name);
1113 goto done;
1114 }
1115 }
1116 din = dataconn(name, (off_t)-1, "r");
1117 if (din == NULL)
1118 goto done;
1119 (void)gettimeofday(&start, NULL);
1120 if (receive_data(din, fout) == 0) {
1121 if (unique)
1122 reply(226, "Transfer complete (unique file name:%s).",
1123 name);
1124 else
1125 reply(226, "Transfer complete.");
1126 }
1127 (void)gettimeofday(&finish, NULL);
1128 (void) fclose(din);
1129 timersub(&finish, &start, &td);
1130 tdp = &td;
1131 data = -1;
1132 pdata = -1;
1133 done:
1134 logcmd(desc, byte_count, name, NULL, tdp, NULL);
1135 (*closefunc)(fout);
1136 }
1137
1138 static FILE *
1139 getdatasock(mode)
1140 const char *mode;
1141 {
1142 int on = 1, s, t, tries;
1143
1144 if (data >= 0)
1145 return (fdopen(data, mode));
1146 (void) seteuid((uid_t)0);
1147 s = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
1148 if (s < 0)
1149 goto bad;
1150 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1151 (char *) &on, sizeof(on)) < 0)
1152 goto bad;
1153 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1154 (char *) &on, sizeof(on)) < 0)
1155 goto bad;
1156 /* anchor socket to avoid multi-homing problems */
1157 data_source = ctrl_addr;
1158 data_source.su_port = htons(20); /* ftp-data port */
1159 for (tries = 1; ; tries++) {
1160 if (bind(s, (struct sockaddr *)&data_source,
1161 data_source.su_len) >= 0)
1162 break;
1163 if (errno != EADDRINUSE || tries > 10)
1164 goto bad;
1165 sleep(tries);
1166 }
1167 (void) seteuid((uid_t)pw->pw_uid);
1168 #ifdef IP_TOS
1169 if (ctrl_addr.su_family == AF_INET) {
1170 on = IPTOS_THROUGHPUT;
1171 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on,
1172 sizeof(int)) < 0)
1173 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
1174 }
1175 #endif
1176 return (fdopen(s, mode));
1177 bad:
1178 /* Return the real value of errno (close may change it) */
1179 t = errno;
1180 (void) seteuid((uid_t)pw->pw_uid);
1181 (void) close(s);
1182 errno = t;
1183 return (NULL);
1184 }
1185
1186 static FILE *
1187 dataconn(name, size, mode)
1188 const char *name;
1189 off_t size;
1190 const char *mode;
1191 {
1192 char sizebuf[32];
1193 FILE *file;
1194 int retry = 0, tos, keepalive;
1195
1196 file_size = size;
1197 byte_count = 0;
1198 if (size != (off_t) -1)
1199 (void)snprintf(sizebuf, sizeof(sizebuf), " (%qd byte%s)",
1200 (qdfmt_t)size, PLURAL(size));
1201 else
1202 sizebuf[0] = '\0';
1203 if (pdata >= 0) {
1204 union sockunion from;
1205 int s, fromlen = sizeof(from);
1206
1207 (void) alarm(curclass.timeout);
1208 s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1209 (void) alarm(0);
1210 if (s < 0) {
1211 reply(425, "Can't open data connection.");
1212 (void) close(pdata);
1213 pdata = -1;
1214 return (NULL);
1215 }
1216 (void) close(pdata);
1217 pdata = s;
1218 switch (from.su_family) {
1219 case AF_INET:
1220 #ifdef IP_TOS
1221 tos = IPTOS_THROUGHPUT;
1222 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1223 sizeof(int));
1224 break;
1225 #endif
1226 }
1227 /* Set keepalives on the socket to detect dropped conns. */
1228 #ifdef SO_KEEPALIVE
1229 keepalive = 1;
1230 (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
1231 (char *)&keepalive, sizeof(int));
1232 #endif
1233 reply(150, "Opening %s mode data connection for '%s'%s.",
1234 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1235 return (fdopen(pdata, mode));
1236 }
1237 if (data >= 0) {
1238 reply(125, "Using existing data connection for '%s'%s.",
1239 name, sizebuf);
1240 usedefault = 1;
1241 return (fdopen(data, mode));
1242 }
1243 if (usedefault)
1244 data_dest = his_addr;
1245 usedefault = 1;
1246 file = getdatasock(mode);
1247 if (file == NULL) {
1248 char hbuf[INET6_ADDRSTRLEN];
1249 char pbuf[10];
1250 getnameinfo((struct sockaddr *)&data_source, data_source.su_len,
1251 hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
1252 NI_NUMERICHOST | NI_NUMERICSERV);
1253 reply(425, "Can't create data socket (%s,%s): %s.",
1254 hbuf, pbuf, strerror(errno));
1255 return (NULL);
1256 }
1257 data = fileno(file);
1258 while (connect(data, (struct sockaddr *)&data_dest,
1259 data_dest.su_len) < 0) {
1260 if (errno == EADDRINUSE && retry < swaitmax) {
1261 sleep((unsigned) swaitint);
1262 retry += swaitint;
1263 continue;
1264 }
1265 perror_reply(425, "Can't build data connection");
1266 (void) fclose(file);
1267 data = -1;
1268 return (NULL);
1269 }
1270 reply(150, "Opening %s mode data connection for '%s'%s.",
1271 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1272 return (file);
1273 }
1274
1275 /*
1276 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1277 * encapsulation of the data subject * to Mode, Structure, and Type.
1278 *
1279 * NB: Form isn't handled.
1280 */
1281 static int
1282 send_data(instr, outstr, blksize, isdata)
1283 FILE *instr, *outstr;
1284 off_t blksize;
1285 int isdata;
1286 {
1287 int c, filefd, netfd, rval;
1288 char *buf;
1289
1290 transflag = 1;
1291 rval = -1;
1292 buf = NULL;
1293 if (setjmp(urgcatch))
1294 goto cleanup_send_data;
1295
1296 switch (type) {
1297
1298 case TYPE_A:
1299 /* XXXX: rate limit ascii send (get) */
1300 (void) alarm(curclass.timeout);
1301 while ((c = getc(instr)) != EOF) {
1302 byte_count++;
1303 if (c == '\n') {
1304 if (ferror(outstr))
1305 goto data_err;
1306 (void) putc('\r', outstr);
1307 if (isdata) {
1308 total_data_out++;
1309 total_data++;
1310 }
1311 total_bytes_out++;
1312 total_bytes++;
1313 }
1314 (void) putc(c, outstr);
1315 if (isdata) {
1316 total_data_out++;
1317 total_data++;
1318 }
1319 total_bytes_out++;
1320 total_bytes++;
1321 if ((byte_count % 4096) == 0)
1322 (void) alarm(curclass.timeout);
1323 }
1324 (void) alarm(0);
1325 fflush(outstr);
1326 if (ferror(instr))
1327 goto file_err;
1328 if (ferror(outstr))
1329 goto data_err;
1330 rval = 0;
1331 goto cleanup_send_data;
1332
1333 case TYPE_I:
1334 case TYPE_L:
1335 if ((buf = malloc((size_t)blksize)) == NULL) {
1336 perror_reply(451, "Local resource failure: malloc");
1337 goto cleanup_send_data;
1338 }
1339 filefd = fileno(instr);
1340 netfd = fileno(outstr);
1341 (void) alarm(curclass.timeout);
1342 if (curclass.rateget) {
1343 while (1) {
1344 int d;
1345 struct timeval then, now, td;
1346 off_t bufrem;
1347 char *bufp;
1348
1349 (void)gettimeofday(&then, NULL);
1350 errno = c = d = 0;
1351 bufrem = curclass.rateget;
1352 while (bufrem > 0) {
1353 if ((c = read(filefd, buf,
1354 MIN(blksize, bufrem))) <= 0)
1355 goto senddone;
1356 (void) alarm(curclass.timeout);
1357 bufrem -= c;
1358 byte_count += c;
1359 if (isdata) {
1360 total_data_out += c;
1361 total_data += c;
1362 }
1363 total_bytes_out += c;
1364 total_bytes += c;
1365 for (bufp = buf; c > 0;
1366 c -= d, bufp += d)
1367 if ((d =
1368 write(netfd, bufp, c)) <= 0)
1369 break;
1370 if (d < 0)
1371 goto data_err;
1372 }
1373 (void)gettimeofday(&now, NULL);
1374 timersub(&now, &then, &td);
1375 if (td.tv_sec > 0)
1376 break;
1377 usleep(1000000 - td.tv_usec);
1378 }
1379 } else {
1380 while ((c = read(filefd, buf, (size_t)blksize)) > 0) {
1381 if (write(netfd, buf, c) != c)
1382 goto data_err;
1383 (void) alarm(curclass.timeout);
1384 byte_count += c;
1385 if (isdata) {
1386 total_data_out += c;
1387 total_data += c;
1388 }
1389 total_bytes_out += c;
1390 total_bytes += c;
1391 }
1392 }
1393 senddone:
1394 if (c < 0)
1395 goto file_err;
1396 rval = 0;
1397 goto cleanup_send_data;
1398
1399 default:
1400 reply(550, "Unimplemented TYPE %d in send_data", type);
1401 goto cleanup_send_data;
1402 }
1403
1404 data_err:
1405 (void) alarm(0);
1406 perror_reply(426, "Data connection");
1407 goto cleanup_send_data;
1408
1409 file_err:
1410 (void) alarm(0);
1411 perror_reply(551, "Error on input file");
1412 /* FALLTHROUGH */
1413
1414 cleanup_send_data:
1415 (void) alarm(0);
1416 transflag = 0;
1417 if (buf)
1418 free(buf);
1419 if (isdata) {
1420 total_files_out++;
1421 total_files++;
1422 }
1423 total_xfers_out++;
1424 total_xfers++;
1425 return (rval);
1426 }
1427
1428 /*
1429 * Transfer data from peer to "outstr" using the appropriate encapulation of
1430 * the data subject to Mode, Structure, and Type.
1431 *
1432 * N.B.: Form isn't handled.
1433 */
1434 static int
1435 receive_data(instr, outstr)
1436 FILE *instr, *outstr;
1437 {
1438 int c, bare_lfs, netfd, filefd, rval;
1439 char buf[BUFSIZ];
1440 #ifdef __GNUC__
1441 (void) &bare_lfs;
1442 #endif
1443
1444 bare_lfs = 0;
1445 transflag = 1;
1446 rval = -1;
1447 if (setjmp(urgcatch))
1448 goto cleanup_recv_data;
1449
1450 switch (type) {
1451
1452 case TYPE_I:
1453 case TYPE_L:
1454 netfd = fileno(instr);
1455 filefd = fileno(outstr);
1456 (void) alarm(curclass.timeout);
1457 if (curclass.rateput) {
1458 while (1) {
1459 int d;
1460 struct timeval then, now, td;
1461 off_t bufrem;
1462
1463 (void)gettimeofday(&then, NULL);
1464 errno = c = d = 0;
1465 for (bufrem = curclass.rateput; bufrem > 0; ) {
1466 if ((c = read(netfd, buf,
1467 MIN(sizeof(buf), bufrem))) <= 0)
1468 goto recvdone;
1469 if ((d = write(filefd, buf, c)) != c)
1470 goto recvdone;
1471 (void) alarm(curclass.timeout);
1472 bufrem -= c;
1473 byte_count += c;
1474 total_data_in += c;
1475 total_data += c;
1476 total_bytes_in += c;
1477 total_bytes += c;
1478 }
1479 (void)gettimeofday(&now, NULL);
1480 timersub(&now, &then, &td);
1481 if (td.tv_sec > 0)
1482 break;
1483 usleep(1000000 - td.tv_usec);
1484 }
1485 } else {
1486 while ((c = read(netfd, buf, sizeof(buf))) > 0) {
1487 if (write(filefd, buf, c) != c)
1488 goto file_err;
1489 (void) alarm(curclass.timeout);
1490 byte_count += c;
1491 total_data_in += c;
1492 total_data += c;
1493 total_bytes_in += c;
1494 total_bytes += c;
1495 }
1496 }
1497 recvdone:
1498 if (c < 0)
1499 goto data_err;
1500 rval = 0;
1501 goto cleanup_recv_data;
1502
1503 case TYPE_E:
1504 reply(553, "TYPE E not implemented.");
1505 goto cleanup_recv_data;
1506
1507 case TYPE_A:
1508 (void) alarm(curclass.timeout);
1509 /* XXXX: rate limit ascii receive (put) */
1510 while ((c = getc(instr)) != EOF) {
1511 byte_count++;
1512 total_data_in++;
1513 total_data++;
1514 total_bytes_in++;
1515 total_bytes++;
1516 if ((byte_count % 4096) == 0)
1517 (void) alarm(curclass.timeout);
1518 if (c == '\n')
1519 bare_lfs++;
1520 while (c == '\r') {
1521 if (ferror(outstr))
1522 goto data_err;
1523 if ((c = getc(instr)) != '\n') {
1524 byte_count++;
1525 total_data_in++;
1526 total_data++;
1527 total_bytes_in++;
1528 total_bytes++;
1529 if ((byte_count % 4096) == 0)
1530 (void) alarm(curclass.timeout);
1531 (void) putc ('\r', outstr);
1532 if (c == '\0' || c == EOF)
1533 goto contin2;
1534 }
1535 }
1536 (void) putc(c, outstr);
1537 contin2: ;
1538 }
1539 (void) alarm(0);
1540 fflush(outstr);
1541 if (ferror(instr))
1542 goto data_err;
1543 if (ferror(outstr))
1544 goto file_err;
1545 if (bare_lfs) {
1546 lreply(226,
1547 "WARNING! %d bare linefeeds received in ASCII mode",
1548 bare_lfs);
1549 lreply(0, "File may not have transferred correctly.");
1550 }
1551 rval = 0;
1552 goto cleanup_recv_data;
1553
1554 default:
1555 reply(550, "Unimplemented TYPE %d in receive_data", type);
1556 goto cleanup_recv_data;
1557 }
1558
1559 data_err:
1560 (void) alarm(0);
1561 perror_reply(426, "Data Connection");
1562 goto cleanup_recv_data;
1563
1564 file_err:
1565 (void) alarm(0);
1566 perror_reply(452, "Error writing file");
1567 goto cleanup_recv_data;
1568
1569 cleanup_recv_data:
1570 (void) alarm(0);
1571 transflag = 0;
1572 total_files_in++;
1573 total_files++;
1574 total_xfers_in++;
1575 total_xfers++;
1576 return (rval);
1577 }
1578
1579 void
1580 statfilecmd(filename)
1581 const char *filename;
1582 {
1583 FILE *fin;
1584 int c;
1585 char *argv[] = { INTERNAL_LS, "-lgA", "", NULL };
1586
1587 argv[2] = (char *)filename;
1588 fin = ftpd_popen(argv, "r", STDOUT_FILENO);
1589 lreply(211, "status of %s:", filename);
1590 while ((c = getc(fin)) != EOF) {
1591 if (c == '\n') {
1592 if (ferror(stdout)){
1593 perror_reply(421, "control connection");
1594 (void) ftpd_pclose(fin);
1595 dologout(1);
1596 /* NOTREACHED */
1597 }
1598 if (ferror(fin)) {
1599 perror_reply(551, filename);
1600 (void) ftpd_pclose(fin);
1601 return;
1602 }
1603 (void) putchar('\r');
1604 total_bytes++;
1605 total_bytes_out++;
1606 }
1607 (void) putchar(c);
1608 total_bytes++;
1609 total_bytes_out++;
1610 }
1611 (void) ftpd_pclose(fin);
1612 reply(211, "End of Status");
1613 }
1614
1615 void
1616 statcmd()
1617 {
1618 union sockunion *su = NULL;
1619 static char ntop_buf[INET6_ADDRSTRLEN];
1620 u_char *a, *p;
1621 int ispassive;
1622 off_t b, otbi, otbo, otb;
1623
1624 a = p = (u_char *)NULL;
1625
1626 lreply(211, "%s FTP server status:", hostname);
1627 lreply(0, "%s", version);
1628 ntop_buf[0] = '\0';
1629 if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len,
1630 ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST)
1631 && strcmp(remotehost, ntop_buf) != 0) {
1632 lreply(0, "Connected to %s (%s)", remotehost, ntop_buf);
1633 } else
1634 lreply(0, "Connected to %s", remotehost);
1635 if (logged_in) {
1636 if (curclass.type == CLASS_GUEST)
1637 lreply(0, "Logged in anonymously");
1638 else
1639 lreply(0, "Logged in as %s%s", pw->pw_name,
1640 curclass.type == CLASS_CHROOT ? " (chroot)" : "");
1641 } else if (askpasswd)
1642 lreply(0, "Waiting for password");
1643 else
1644 lreply(0, "Waiting for user name");
1645 b = printf(" TYPE: %s", typenames[type]);
1646 total_bytes += b;
1647 total_bytes_out += b;
1648 if (type == TYPE_A || type == TYPE_E) {
1649 b = printf(", FORM: %s", formnames[form]);
1650 total_bytes += b;
1651 total_bytes_out += b;
1652 }
1653 if (type == TYPE_L) {
1654 #if NBBY == 8
1655 b = printf(" %d", NBBY);
1656 #else
1657 /* XXX: `bytesize' needs to be defined in this case */
1658 b = printf(" %d", bytesize);
1659 #endif
1660 total_bytes += b;
1661 total_bytes_out += b;
1662 }
1663 b = printf("; STRUcture: %s; transfer MODE: %s\r\n",
1664 strunames[stru], modenames[mode]);
1665 total_bytes += b;
1666 total_bytes_out += b;
1667 ispassive = 0;
1668 if (data != -1) {
1669 lreply(0, "Data connection open");
1670 su = NULL;
1671 } else if (pdata != -1) {
1672 b = printf(" in Passive mode");
1673 total_bytes += b;
1674 total_bytes_out += b;
1675 su = (union sockunion *)&pasv_addr;
1676 ispassive = 1;
1677 goto printaddr;
1678 } else if (usedefault == 0) {
1679 if (epsvall) {
1680 b = printf("211- EPSV only mode (EPSV ALL )\r\n");
1681 total_bytes += b;
1682 total_bytes_out += b;
1683 goto epsvonly;
1684 }
1685 b = printf("211- %s",
1686 (data_dest.su_family == AF_INET) ? "PORT" : "LPRT");
1687 total_bytes += b;
1688 total_bytes_out += b;
1689 su = (union sockunion *)&data_dest;
1690 printaddr:
1691 /* PASV/PORT */
1692 if (su->su_family == AF_INET) {
1693 if (ispassive)
1694 b = printf("211- PASV ");
1695 else
1696 b = printf("211- PORT ");
1697 a = (u_char *) &su->su_sin.sin_addr;
1698 p = (u_char *) &su->su_sin.sin_port;
1699 #define UC(b) (((int) b) & 0xff)
1700 b += printf("(%d,%d,%d,%d,%d,%d)\r\n",
1701 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1702 UC(p[0]), UC(p[1]));
1703 total_bytes += b;
1704 total_bytes_out += b;
1705 }
1706
1707 /* LPSV/LPRT */
1708 {
1709 int alen, af, i;
1710
1711 alen = 0;
1712 switch (su->su_family) {
1713 case AF_INET:
1714 a = (u_char *) &su->su_sin.sin_addr;
1715 p = (u_char *) &su->su_sin.sin_port;
1716 alen = sizeof(su->su_sin.sin_addr);
1717 af = 4;
1718 break;
1719 case AF_INET6:
1720 a = (u_char *) &su->su_sin6.sin6_addr;
1721 p = (u_char *) &su->su_sin6.sin6_port;
1722 alen = sizeof(su->su_sin6.sin6_addr);
1723 af = 6;
1724 break;
1725 default:
1726 af = 0;
1727 break;
1728 }
1729 if (af) {
1730 if (ispassive)
1731 b = printf("211- LPSV ");
1732 else
1733 b = printf("211- LPRT ");
1734 printf("(%d,%d", af, alen);
1735 for (i = 0; i < alen; i++)
1736 b += printf("%d,", UC(a[alen]));
1737 b += printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1]));
1738 total_bytes += b;
1739 total_bytes_out += b;
1740 #undef UC
1741 }
1742 }
1743
1744 /* EPRT/EPSV */
1745 epsvonly:;
1746 {
1747 int af;
1748
1749 switch (su->su_family) {
1750 case AF_INET:
1751 af = 1;
1752 break;
1753 case AF_INET6:
1754 af = 2;
1755 break;
1756 default:
1757 af = 0;
1758 break;
1759 }
1760 if (af) {
1761 if (getnameinfo((struct sockaddr *)su, su->su_len,
1762 ntop_buf, sizeof(ntop_buf), NULL, 0,
1763 NI_NUMERICHOST) == 0) {
1764 if (ispassive)
1765 b = printf("211 - EPSV ");
1766 else
1767 b = printf("211 - EPRT ");
1768 b += printf("(|%d|%s|%d|)\r\n",
1769 af, ntop_buf, ntohs(su->su_port));
1770 total_bytes += b;
1771 total_bytes_out += b;
1772 }
1773 }
1774 }
1775 } else
1776 lreply(0, "No data connection");
1777
1778 if (logged_in) {
1779 lreply(0, "Data sent: %qd byte%s in %qd file%s",
1780 (qdfmt_t)total_data_out, PLURAL(total_data_out),
1781 (qdfmt_t)total_files_out, PLURAL(total_files_out));
1782 lreply(0, "Data received: %qd byte%s in %qd file%s",
1783 (qdfmt_t)total_data_in, PLURAL(total_data_in),
1784 (qdfmt_t)total_files_in, PLURAL(total_files_in));
1785 lreply(0, "Total data: %qd byte%s in %qd file%s",
1786 (qdfmt_t)total_data, PLURAL(total_data),
1787 (qdfmt_t)total_files, PLURAL(total_files));
1788 }
1789 otbi = total_bytes_in;
1790 otbo = total_bytes_out;
1791 otb = total_bytes;
1792 lreply(0, "Traffic sent: %qd byte%s in %qd transfer%s",
1793 (qdfmt_t)otbo, PLURAL(otbo),
1794 (qdfmt_t)total_xfers_out, PLURAL(total_xfers_out));
1795 lreply(0, "Traffic received: %qd byte%s in %qd transfer%s",
1796 (qdfmt_t)otbi, PLURAL(otbi),
1797 (qdfmt_t)total_xfers_in, PLURAL(total_xfers_in));
1798 lreply(0, "Total traffic: %qd byte%s in %qd transfer%s",
1799 (qdfmt_t)otb, PLURAL(otb),
1800 (qdfmt_t)total_xfers, PLURAL(total_xfers));
1801
1802 if (logged_in) {
1803 struct ftpconv *cp;
1804
1805 lreply(0, "");
1806 lreply(0, "Class: %s, class type: %s", curclass.classname,
1807 curclass.type == CLASS_GUEST ? "GUEST" :
1808 curclass.type == CLASS_CHROOT ? "CHROOT" :
1809 curclass.type == CLASS_REAL ? "REAL" : "<unknown>");
1810 lreply(0, "Check PORT/LPRT commands: %sabled",
1811 curclass.checkportcmd ? "en" : "dis");
1812 if (curclass.display != NULL)
1813 lreply(0, "Display file: %s", curclass.display);
1814 if (curclass.notify != NULL)
1815 lreply(0, "Notify fileglob: %s", curclass.notify);
1816 lreply(0, "Idle timeout: %d, maximum timeout: %d",
1817 curclass.timeout, curclass.maxtimeout);
1818 if (curclass.motd != NULL)
1819 lreply(0, "MotD file: %s", curclass.motd);
1820 lreply(0,
1821 "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled",
1822 curclass.modify ? "en" : "dis");
1823 lreply(0,
1824 "Upload commands (APPE, STOR, STOU): %sabled",
1825 curclass.upload ? "en" : "dis");
1826 if (curclass.rateget)
1827 lreply(0, "Rate get limit: %d bytes/sec",
1828 curclass.rateget);
1829 else
1830 lreply(0, "Rate get limit: disabled");
1831 if (curclass.rateput)
1832 lreply(0, "Rate put limit: %d bytes/sec",
1833 curclass.rateput);
1834 else
1835 lreply(0, "Rate put limit: disabled");
1836 lreply(0, "Umask: %.04o", curclass.umask);
1837 for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
1838 if (cp->suffix == NULL || cp->types == NULL ||
1839 cp->command == NULL)
1840 continue;
1841 lreply(0,
1842 "Conversion: %s [%s] disable: %s, command: %s",
1843 cp->suffix, cp->types, cp->disable, cp->command);
1844 }
1845 }
1846
1847 reply(211, "End of status");
1848 }
1849
1850 void
1851 fatal(s)
1852 const char *s;
1853 {
1854
1855 reply(451, "Error in server: %s\n", s);
1856 reply(221, "Closing connection due to server error.");
1857 dologout(0);
1858 /* NOTREACHED */
1859 }
1860
1861 void
1862 #ifdef __STDC__
1863 reply(int n, const char *fmt, ...)
1864 #else
1865 reply(n, fmt, va_alist)
1866 int n;
1867 char *fmt;
1868 va_dcl
1869 #endif
1870 {
1871 off_t b;
1872 va_list ap;
1873 #ifdef __STDC__
1874 va_start(ap, fmt);
1875 #else
1876 va_start(ap);
1877 #endif
1878 b = 0;
1879 b += printf("%d ", n);
1880 b += vprintf(fmt, ap);
1881 b += printf("\r\n");
1882 total_bytes += b;
1883 total_bytes_out += b;
1884 (void)fflush(stdout);
1885 if (debug) {
1886 syslog(LOG_DEBUG, "<--- %d ", n);
1887 vsyslog(LOG_DEBUG, fmt, ap);
1888 }
1889 }
1890
1891 void
1892 #ifdef __STDC__
1893 lreply(int n, const char *fmt, ...)
1894 #else
1895 lreply(n, fmt, va_alist)
1896 int n;
1897 char *fmt;
1898 va_dcl
1899 #endif
1900 {
1901 off_t b;
1902 va_list ap;
1903 #ifdef __STDC__
1904 va_start(ap, fmt);
1905 #else
1906 va_start(ap);
1907 #endif
1908 b = 0;
1909 switch (n) {
1910 case 0:
1911 b += printf(" ");
1912 case -1:
1913 break;
1914 default:
1915 b += printf("%d-", n);
1916 break;
1917 }
1918 b += vprintf(fmt, ap);
1919 b += printf("\r\n");
1920 total_bytes += b;
1921 total_bytes_out += b;
1922 (void)fflush(stdout);
1923 if (debug) {
1924 syslog(LOG_DEBUG, "<--- %d- ", n);
1925 vsyslog(LOG_DEBUG, fmt, ap);
1926 }
1927 }
1928
1929 static void
1930 ack(s)
1931 const char *s;
1932 {
1933
1934 reply(250, "%s command successful.", s);
1935 }
1936
1937 void
1938 delete(name)
1939 const char *name;
1940 {
1941 char *p = NULL;
1942
1943 if (remove(name) < 0) {
1944 p = strerror(errno);
1945 perror_reply(550, name);
1946 } else
1947 ack("DELE");
1948 logcmd("delete", -1, name, NULL, NULL, p);
1949 }
1950
1951 void
1952 cwd(path)
1953 const char *path;
1954 {
1955
1956 if (chdir(path) < 0)
1957 perror_reply(550, path);
1958 else {
1959 show_chdir_messages(250);
1960 ack("CWD");
1961 }
1962 }
1963
1964 static void
1965 replydirname(name, message)
1966 const char *name, *message;
1967 {
1968 char npath[MAXPATHLEN + 1];
1969 int i;
1970
1971 for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
1972 npath[i] = *name;
1973 if (*name == '"')
1974 npath[++i] = '"';
1975 }
1976 npath[i] = '\0';
1977 reply(257, "\"%s\" %s", npath, message);
1978 }
1979
1980 void
1981 makedir(name)
1982 const char *name;
1983 {
1984 char *p = NULL;
1985
1986 if (mkdir(name, 0777) < 0) {
1987 p = strerror(errno);
1988 perror_reply(550, name);
1989 } else
1990 replydirname(name, "directory created.");
1991 logcmd("mkdir", -1, name, NULL, NULL, p);
1992 }
1993
1994 void
1995 removedir(name)
1996 const char *name;
1997 {
1998 char *p = NULL;
1999
2000 if (rmdir(name) < 0) {
2001 p = strerror(errno);
2002 perror_reply(550, name);
2003 } else
2004 ack("RMD");
2005 logcmd("rmdir", -1, name, NULL, NULL, p);
2006 }
2007
2008 void
2009 pwd()
2010 {
2011 char path[MAXPATHLEN + 1];
2012
2013 if (getcwd(path, sizeof(path) - 1) == NULL)
2014 reply(550, "Can't get the current directory: %s.",
2015 strerror(errno));
2016 else
2017 replydirname(path, "is the current directory.");
2018 }
2019
2020 char *
2021 renamefrom(name)
2022 char *name;
2023 {
2024 struct stat st;
2025
2026 if (stat(name, &st) < 0) {
2027 perror_reply(550, name);
2028 return (NULL);
2029 }
2030 reply(350, "File exists, ready for destination name");
2031 return (name);
2032 }
2033
2034 void
2035 renamecmd(from, to)
2036 const char *from, *to;
2037 {
2038 char *p = NULL;
2039
2040 if (rename(from, to) < 0) {
2041 p = strerror(errno);
2042 perror_reply(550, "rename");
2043 } else
2044 ack("RNTO");
2045 logcmd("rename", -1, from, to, NULL, p);
2046 }
2047
2048 static void
2049 dolog(who)
2050 struct sockaddr *who;
2051 {
2052 int error;
2053 error = getnameinfo(who, who->sa_len, remotehost, sizeof(remotehost),
2054 NULL, 0, 0);
2055 #ifdef HASSETPROCTITLE
2056 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
2057 setproctitle(proctitle);
2058 #endif /* HASSETPROCTITLE */
2059
2060 if (logging)
2061 syslog(LOG_INFO, "connection from %s", remotehost);
2062 }
2063
2064 /*
2065 * Record logout in wtmp file
2066 * and exit with supplied status.
2067 */
2068 void
2069 dologout(status)
2070 int status;
2071 {
2072 /*
2073 * Prevent reception of SIGURG from resulting in a resumption
2074 * back to the main program loop.
2075 */
2076 transflag = 0;
2077
2078 if (logged_in) {
2079 (void) seteuid((uid_t)0);
2080 logwtmp(ttyline, "", "");
2081 #ifdef KERBEROS
2082 if (!notickets && krbtkfile_env)
2083 unlink(krbtkfile_env);
2084 #endif
2085 }
2086 /* beware of flushing buffers after a SIGPIPE */
2087 _exit(status);
2088 }
2089
2090 static void
2091 myoob(signo)
2092 int signo;
2093 {
2094 char *cp;
2095
2096 /* only process if transfer occurring */
2097 if (!transflag)
2098 return;
2099 cp = tmpline;
2100 if (getline(cp, 7, stdin) == NULL) {
2101 reply(221, "You could at least say goodbye.");
2102 dologout(0);
2103 }
2104 if (strcasecmp(cp, "ABOR\r\n") == 0) {
2105 tmpline[0] = '\0';
2106 reply(426, "Transfer aborted. Data connection closed.");
2107 reply(226, "Abort successful");
2108 longjmp(urgcatch, 1);
2109 }
2110 if (strcasecmp(cp, "STAT\r\n") == 0) {
2111 if (file_size != (off_t) -1)
2112 reply(213, "Status: %qd of %qd byte%s transferred",
2113 (qdfmt_t)byte_count, (qdfmt_t)file_size,
2114 PLURAL(byte_count));
2115 else
2116 reply(213, "Status: %qd byte%s transferred",
2117 (qdfmt_t)byte_count, PLURAL(byte_count));
2118 }
2119 }
2120
2121 /*
2122 * Note: a response of 425 is not mentioned as a possible response to
2123 * the PASV command in RFC959. However, it has been blessed as
2124 * a legitimate response by Jon Postel in a telephone conversation
2125 * with Rick Adams on 25 Jan 89.
2126 */
2127 void
2128 passive()
2129 {
2130 int len;
2131 char *p, *a;
2132
2133 if (pdata >= 0)
2134 close(pdata);
2135 pdata = socket(AF_INET, SOCK_STREAM, 0);
2136 if (pdata < 0 || !logged_in) {
2137 perror_reply(425, "Can't open passive connection");
2138 return;
2139 }
2140 pasv_addr = ctrl_addr;
2141 pasv_addr.su_port = 0;
2142 len = pasv_addr.su_len;
2143 if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0) {
2144 goto pasv_error;
2145 }
2146 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2147 goto pasv_error;
2148 if (listen(pdata, 1) < 0)
2149 goto pasv_error;
2150 a = (char *) &pasv_addr.su_sin.sin_addr;
2151 p = (char *) &pasv_addr.su_port;
2152
2153 #define UC(b) (((int) b) & 0xff)
2154
2155 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2156 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2157 return;
2158
2159 pasv_error:
2160 (void) close(pdata);
2161 pdata = -1;
2162 perror_reply(425, "Can't open passive connection");
2163 return;
2164 }
2165
2166 /*
2167 * 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
2168 * 229 Entering Extended Passive Mode (|||port|)
2169 */
2170 void
2171 long_passive(char *cmd, int pf)
2172 {
2173 int len;
2174 register char *p, *a;
2175
2176 if (!logged_in) {
2177 syslog(LOG_NOTICE, "long passive but not logged in");
2178 reply(503, "Login with USER first.");
2179 return;
2180 }
2181
2182 if (pf != PF_UNSPEC) {
2183 if (ctrl_addr.su_family != pf) {
2184 switch (ctrl_addr.su_family) {
2185 case AF_INET:
2186 pf = 1;
2187 break;
2188 case AF_INET6:
2189 pf = 2;
2190 break;
2191 default:
2192 pf = 0;
2193 break;
2194 }
2195 /*
2196 * XXX
2197 * only EPRT/EPSV ready clients will understand this
2198 */
2199 if (strcmp(cmd, "EPSV") == 0 && pf) {
2200 reply(522, "Network protocol mismatch, "
2201 "use (%d)", pf);
2202 } else
2203 reply(501, "Network protocol mismatch"); /*XXX*/
2204
2205 return;
2206 }
2207 }
2208
2209 if (pdata >= 0)
2210 close(pdata);
2211 pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0);
2212 if (pdata < 0) {
2213 perror_reply(425, "Can't open passive connection");
2214 return;
2215 }
2216 pasv_addr = ctrl_addr;
2217 pasv_addr.su_port = 0;
2218 if (bind(pdata, (struct sockaddr *) &pasv_addr, pasv_addr.su_len) < 0) {
2219 goto pasv_error;
2220 }
2221 len = pasv_addr.su_len;
2222 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
2223 goto pasv_error;
2224 if (listen(pdata, 1) < 0)
2225 goto pasv_error;
2226 p = (char *) &pasv_addr.su_port;
2227
2228 #define UC(b) (((int) b) & 0xff)
2229
2230 if (strcmp(cmd, "LPSV") == 0) {
2231 switch (pasv_addr.su_family) {
2232 case AF_INET:
2233 a = (char *) &pasv_addr.su_sin.sin_addr;
2234 reply(228, "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2235 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2236 2, UC(p[0]), UC(p[1]));
2237 return;
2238 case AF_INET6:
2239 a = (char *) &pasv_addr.su_sin6.sin6_addr;
2240 reply(228, "Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)",
2241 6, 16,
2242 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
2243 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]),
2244 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]),
2245 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]),
2246 2, UC(p[0]), UC(p[1]));
2247 return;
2248 }
2249 #undef UC
2250 } else if (strcmp(cmd, "EPSV") == 0) {
2251 switch (pasv_addr.su_family) {
2252 case AF_INET:
2253 case AF_INET6:
2254 reply(229, "Entering Extended Passive Mode (|||%d|)",
2255 ntohs(pasv_addr.su_port));
2256 return;
2257 }
2258 } else {
2259 /* more proper error code? */
2260 }
2261
2262 pasv_error:
2263 (void) close(pdata);
2264 pdata = -1;
2265 perror_reply(425, "Can't open passive connection");
2266 return;
2267 }
2268
2269 /*
2270 * Generate unique name for file with basename "local".
2271 * The file named "local" is already known to exist.
2272 * Generates failure reply on error.
2273 *
2274 * XXX this function should under go changes similar to
2275 * the mktemp(3)/mkstemp(3) changes.
2276 */
2277 static char *
2278 gunique(local)
2279 const char *local;
2280 {
2281 static char new[MAXPATHLEN + 1];
2282 struct stat st;
2283 char *cp;
2284 int count;
2285
2286 cp = strrchr(local, '/');
2287 if (cp)
2288 *cp = '\0';
2289 if (stat(cp ? local : ".", &st) < 0) {
2290 perror_reply(553, cp ? local : ".");
2291 return (NULL);
2292 }
2293 if (cp)
2294 *cp = '/';
2295 for (count = 1; count < 100; count++) {
2296 (void)snprintf(new, sizeof(new) - 1, "%s.%d", local, count);
2297 if (stat(new, &st) < 0)
2298 return (new);
2299 }
2300 reply(452, "Unique file name cannot be created.");
2301 return (NULL);
2302 }
2303
2304 /*
2305 * Format and send reply containing system error number.
2306 */
2307 void
2308 perror_reply(code, string)
2309 int code;
2310 const char *string;
2311 {
2312 int save_errno;
2313
2314 save_errno = errno;
2315 reply(code, "%s: %s.", string, strerror(errno));
2316 errno = save_errno;
2317 }
2318
2319 static char *onefile[] = {
2320 "",
2321 0
2322 };
2323
2324 void
2325 send_file_list(whichf)
2326 const char *whichf;
2327 {
2328 struct stat st;
2329 DIR *dirp = NULL;
2330 struct dirent *dir;
2331 FILE *dout = NULL;
2332 char **dirlist, *dirname, *p;
2333 int simple = 0;
2334 int freeglob = 0;
2335 glob_t gl;
2336 off_t b;
2337
2338 #ifdef __GNUC__
2339 (void) &dout;
2340 (void) &dirlist;
2341 (void) &simple;
2342 (void) &freeglob;
2343 #endif
2344
2345 p = NULL;
2346 if (strpbrk(whichf, "~{[*?") != NULL) {
2347 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
2348
2349 memset(&gl, 0, sizeof(gl));
2350 freeglob = 1;
2351 if (glob(whichf, flags, 0, &gl)) {
2352 reply(550, "not found");
2353 goto out;
2354 } else if (gl.gl_pathc == 0) {
2355 errno = ENOENT;
2356 perror_reply(550, whichf);
2357 goto out;
2358 }
2359 dirlist = gl.gl_pathv;
2360 } else {
2361 p = xstrdup(whichf);
2362 onefile[0] = p;
2363 dirlist = onefile;
2364 simple = 1;
2365 }
2366 /* XXX: } for vi sm */
2367
2368 if (setjmp(urgcatch)) {
2369 transflag = 0;
2370 goto out;
2371 }
2372 while ((dirname = *dirlist++) != NULL) {
2373 int trailingslash = 0;
2374
2375 if (stat(dirname, &st) < 0) {
2376 /*
2377 * If user typed "ls -l", etc, and the client
2378 * used NLST, do what the user meant.
2379 */
2380 /* XXX: nuke this support? */
2381 if (dirname[0] == '-' && *dirlist == NULL &&
2382 transflag == 0) {
2383 char *argv[] = { INTERNAL_LS, "", NULL };
2384
2385 argv[1] = dirname;
2386 retrieve(argv, dirname);
2387 goto out;
2388 }
2389 perror_reply(550, whichf);
2390 if (dout != NULL) {
2391 (void) fclose(dout);
2392 transflag = 0;
2393 data = -1;
2394 pdata = -1;
2395 }
2396 goto out;
2397 }
2398
2399 if (S_ISREG(st.st_mode)) {
2400 if (dout == NULL) {
2401 dout = dataconn("file list", (off_t)-1, "w");
2402 if (dout == NULL)
2403 goto out;
2404 transflag++;
2405 }
2406 b = fprintf(dout, "%s%s\n", dirname,
2407 type == TYPE_A ? "\r" : "");
2408 total_bytes += b;
2409 total_bytes_out += b;
2410 byte_count += strlen(dirname) + 1;
2411 continue;
2412 } else if (!S_ISDIR(st.st_mode))
2413 continue;
2414
2415 if (dirname[strlen(dirname) - 1] == '/')
2416 trailingslash++;
2417
2418 if ((dirp = opendir(dirname)) == NULL)
2419 continue;
2420
2421 while ((dir = readdir(dirp)) != NULL) {
2422 char nbuf[MAXPATHLEN + 1];
2423
2424 if (dir->d_name[0] == '.' && dir->d_namlen == 1)
2425 continue;
2426 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
2427 dir->d_namlen == 2)
2428 continue;
2429
2430 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
2431 trailingslash ? "" : "/", dir->d_name);
2432
2433 /*
2434 * We have to do a stat to ensure it's
2435 * not a directory or special file.
2436 */
2437 /* XXX: follow RFC959 and filter out non files ? */
2438 if (simple || (stat(nbuf, &st) == 0 &&
2439 S_ISREG(st.st_mode))) {
2440 char *p;
2441
2442 if (dout == NULL) {
2443 dout = dataconn("file list", (off_t)-1,
2444 "w");
2445 if (dout == NULL)
2446 goto out;
2447 transflag++;
2448 }
2449 p = nbuf;
2450 if (nbuf[0] == '.' && nbuf[1] == '/')
2451 p = &nbuf[2];
2452 b = fprintf(dout, "%s%s\n", p,
2453 type == TYPE_A ? "\r" : "");
2454 total_bytes += b;
2455 total_bytes_out += b;
2456 byte_count += strlen(nbuf) + 1;
2457 }
2458 }
2459 (void) closedir(dirp);
2460 }
2461
2462 if (dout == NULL)
2463 reply(550, "No files found.");
2464 else if (ferror(dout) != 0)
2465 perror_reply(550, "Data connection");
2466 else
2467 reply(226, "Transfer complete.");
2468
2469 transflag = 0;
2470 if (dout != NULL)
2471 (void) fclose(dout);
2472 data = -1;
2473 pdata = -1;
2474 out:
2475 total_xfers++;
2476 total_xfers_out++;
2477 if (p)
2478 free(p);
2479 if (freeglob)
2480 globfree(&gl);
2481 }
2482
2483 char *
2484 conffilename(s)
2485 const char *s;
2486 {
2487 static char filename[MAXPATHLEN + 1];
2488
2489 if (*s == '/')
2490 strlcpy(filename, s, sizeof(filename));
2491 else
2492 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
2493 return (filename);
2494 }
2495
2496 /*
2497 * logcmd --
2498 * based on the arguments, syslog a message:
2499 * if bytes != -1 "<command> <file1> = <bytes> bytes"
2500 * else if file2 != NULL "<command> <file1> <file2>"
2501 * else "<command> <file1>"
2502 * if elapsed != NULL, append "in xxx.yyy seconds"
2503 * if error != NULL, append ": " + error
2504 */
2505
2506 void
2507 logcmd(command, bytes, file1, file2, elapsed, error)
2508 const char *command;
2509 off_t bytes;
2510 const char *file1;
2511 const char *file2;
2512 const struct timeval *elapsed;
2513 const char *error;
2514 {
2515 char buf[MAXPATHLEN + 100], realfile[MAXPATHLEN + 1];
2516 const char *p;
2517 size_t len;
2518
2519 if (logging <=1)
2520 return;
2521
2522 if ((p = realpath(file1, realfile)) == NULL) {
2523 #if 0 /* XXX: too noisy */
2524 syslog(LOG_WARNING, "realpath `%s' failed: %s",
2525 realfile, strerror(errno));
2526 #endif
2527 p = file1;
2528 }
2529 len = snprintf(buf, sizeof(buf), "%s %s", command, p);
2530
2531 if (bytes != (off_t)-1) {
2532 len += snprintf(buf + len, sizeof(buf) - len,
2533 " = %qd byte%s", (qdfmt_t) bytes, PLURAL(bytes));
2534 } else if (file2 != NULL) {
2535 if ((p = realpath(file2, realfile)) == NULL) {
2536 #if 0 /* XXX: too noisy */
2537 syslog(LOG_WARNING, "realpath `%s' failed: %s",
2538 realfile, strerror(errno));
2539 #endif
2540 p = file2;
2541 }
2542 len += snprintf(buf + len, sizeof(buf) - len, " %s", p);
2543 }
2544
2545 if (elapsed != NULL) {
2546 len += snprintf(buf + len, sizeof(buf) - len,
2547 " in %ld.%.03d seconds", elapsed->tv_sec,
2548 (int)(elapsed->tv_usec / 1000));
2549 }
2550
2551 if (error != NULL)
2552 len += snprintf(buf + len, sizeof(buf) - len, ": %s", error);
2553
2554 syslog(LOG_INFO, "%s", buf);
2555 }
2556
2557 char *
2558 xstrdup(s)
2559 const char *s;
2560 {
2561 char *new = strdup(s);
2562
2563 if (new == NULL)
2564 fatal("Local resource failure: malloc");
2565 /* NOTREACHED */
2566 return (new);
2567 }
2568