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