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