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