ftpd.c revision 1.44 1 /* $NetBSD: ftpd.c,v 1.44 1997/12/28 04:28:17 lukem Exp $ */
2
3 /*
4 * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT(
39 "@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
40 The Regents of the University of California. All rights reserved.\n");
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95";
46 #else
47 __RCSID("$NetBSD: ftpd.c,v 1.44 1997/12/28 04:28:17 lukem Exp $");
48 #endif
49 #endif /* not lint */
50
51 /*
52 * FTP server.
53 */
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <sys/ioctl.h>
57 #include <sys/socket.h>
58 #include <sys/wait.h>
59
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63
64 #define FTP_NAMES
65 #include <arpa/ftp.h>
66 #include <arpa/inet.h>
67 #include <arpa/telnet.h>
68
69 #include <ctype.h>
70 #include <dirent.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <fcntl.h>
74 #include <fnmatch.h>
75 #include <glob.h>
76 #include <limits.h>
77 #include <netdb.h>
78 #include <pwd.h>
79 #include <setjmp.h>
80 #include <signal.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <syslog.h>
85 #include <time.h>
86 #include <unistd.h>
87 #ifdef SKEY
88 #include <skey.h>
89 #endif
90 #ifdef KERBEROS5
91 #include <krb5.h>
92 #endif
93
94 #include "extern.h"
95 #include "pathnames.h"
96
97 #if __STDC__
98 #include <stdarg.h>
99 #else
100 #include <varargs.h>
101 #endif
102
103 static char version[] = "Version 7.02";
104
105 extern off_t restart_point;
106 extern char cbuf[];
107 extern int yyparse __P((void));
108
109 struct sockaddr_in ctrl_addr;
110 struct sockaddr_in data_source;
111 struct sockaddr_in data_dest;
112 struct sockaddr_in his_addr;
113 struct sockaddr_in pasv_addr;
114
115 int data;
116 jmp_buf errcatch, urgcatch;
117 int logged_in;
118 struct passwd *pw;
119 int debug;
120 int logging;
121 int guest;
122 int dochroot;
123 int type;
124 int form;
125 int stru; /* avoid C keyword */
126 int mode;
127 int usedefault = 1; /* for data transfers */
128 int pdata = -1; /* for passive mode */
129 sig_atomic_t transflag;
130 off_t file_size;
131 off_t byte_count;
132 char tmpline[7];
133 char hostname[MAXHOSTNAMELEN];
134 char remotehost[MAXHOSTNAMELEN];
135 static char ttyline[20];
136 char *tty = ttyline; /* for klogin */
137 static char *anondir = NULL;
138 static char confdir[MAXPATHLEN];
139
140 extern struct ftpclass curclass;
141
142 #if defined(KERBEROS) || defined(KERBEROS5)
143 int notickets = 1;
144 char *krbtkfile_env = NULL;
145 #endif
146 #ifdef KERBEROS5
147 extern krb5_context kcontext;
148 #endif
149
150 /*
151 * Timeout intervals for retrying connections
152 * to hosts that don't accept PORT cmds. This
153 * is a kludge, but given the problems with TCP...
154 */
155 #define SWAITMAX 90 /* wait at most 90 seconds */
156 #define SWAITINT 5 /* interval between retries */
157
158 int swaitmax = SWAITMAX;
159 int swaitint = SWAITINT;
160
161 #ifdef HASSETPROCTITLE
162 char proctitle[BUFSIZ]; /* initial part of title */
163 #endif /* HASSETPROCTITLE */
164
165 #define LOGCMD(cmd, file) \
166 if (logging > 1) \
167 syslog(LOG_INFO,"%s %s%s", cmd, \
168 *(file) == '/' ? "" : curdir(), file);
169 #define LOGCMD2(cmd, file1, file2) \
170 if (logging > 1) \
171 syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
172 *(file1) == '/' ? "" : curdir(), file1, \
173 *(file2) == '/' ? "" : curdir(), file2);
174 #define LOGBYTES(cmd, file, cnt) \
175 if (logging > 1) { \
176 if (cnt == (off_t)-1) \
177 syslog(LOG_INFO,"%s %s%s", cmd, \
178 *(file) == '/' ? "" : curdir(), file); \
179 else \
180 syslog(LOG_INFO, "%s %s%s = %qd bytes", \
181 cmd, (*(file) == '/') ? "" : curdir(), file, \
182 (long long)cnt); \
183 }
184
185 static void ack __P((char *));
186 static void myoob __P((int));
187 static int checkuser __P((char *, char *));
188 static int checkaccess __P((char *));
189 static FILE *dataconn __P((char *, off_t, char *));
190 static void dolog __P((struct sockaddr_in *));
191 static char *curdir __P((void));
192 static void end_login __P((void));
193 static FILE *getdatasock __P((char *));
194 static char *gunique __P((char *));
195 static void lostconn __P((int));
196 static int receive_data __P((FILE *, FILE *));
197 static void replydirname __P((const char *, const char *));
198 static void send_data __P((FILE *, FILE *, off_t));
199 static struct passwd *
200 sgetpwnam __P((char *));
201 static char *sgetsave __P((char *));
202
203 int main __P((int, char *[]));
204
205 #if defined(KERBEROS) || defined(KERBEROS5)
206 int klogin __P((struct passwd *, char *, char *, char *));
207 void kdestroy __P((void));
208 #endif
209
210 static char *
211 curdir()
212 {
213 static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */
214
215 if (getcwd(path, sizeof(path)-2) == NULL)
216 return ("");
217 if (path[1] != '\0') /* special case for root dir. */
218 strcat(path, "/");
219 /* For guest account, skip / since it's chrooted */
220 return (guest ? path+1 : path);
221 }
222
223 int
224 main(argc, argv)
225 int argc;
226 char *argv[];
227 {
228 int addrlen, ch, on = 1, tos;
229 char *cp, line[LINE_MAX];
230 FILE *fd;
231 #ifdef KERBEROS5
232 krb5_error_code kerror;
233 #endif
234
235 debug = 0;
236 logging = 0;
237 (void)strcpy(confdir, _DEFAULT_CONFDIR);
238
239 while ((ch = getopt(argc, argv, "a:c:C:dlt:T:u:v")) != -1) {
240 switch (ch) {
241 case 'a':
242 anondir = optarg;
243 break;
244
245 case 'c':
246 (void)strncpy(confdir, optarg, sizeof(confdir));
247 confdir[sizeof(confdir)-1] = '\0';
248 break;
249
250 case 'C':
251 exit(checkaccess(optarg));
252 /* NOTREACHED */
253
254 case 'd':
255 case 'v': /* deprecated */
256 debug = 1;
257 break;
258
259 case 'l':
260 logging++; /* > 1 == extra logging */
261 break;
262
263 case 't':
264 case 'T':
265 case 'u':
266 warnx("-%c has been deprecated in favour of ftpd.conf",
267 ch);
268 break;
269
270 default:
271 if (optopt == 'a' || optopt == 'C')
272 exit(1);
273 warnx("unknown flag -%c ignored", optopt);
274 break;
275 }
276 }
277
278 /*
279 * LOG_NDELAY sets up the logging connection immediately,
280 * necessary for anonymous ftp's that chroot and can't do it later.
281 */
282 openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
283 addrlen = sizeof(his_addr);
284 if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
285 syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
286 exit(1);
287 }
288 addrlen = sizeof(ctrl_addr);
289 if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
290 syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
291 exit(1);
292 }
293 #ifdef IP_TOS
294 tos = IPTOS_LOWDELAY;
295 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
296 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
297 #endif
298 data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
299
300 /* set this here so klogin can use it... */
301 (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid());
302
303 (void) freopen(_PATH_DEVNULL, "w", stderr);
304 (void) signal(SIGPIPE, lostconn);
305 (void) signal(SIGCHLD, SIG_IGN);
306 if ((long)signal(SIGURG, myoob) < 0)
307 syslog(LOG_ERR, "signal: %m");
308
309 /* Try to handle urgent data inline */
310 #ifdef SO_OOBINLINE
311 if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0)
312 syslog(LOG_ERR, "setsockopt: %m");
313 #endif
314
315 #ifdef F_SETOWN
316 if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
317 syslog(LOG_ERR, "fcntl F_SETOWN: %m");
318 #endif
319 dolog(&his_addr);
320 /*
321 * Set up default state
322 */
323 data = -1;
324 type = TYPE_A;
325 form = FORM_N;
326 stru = STRU_F;
327 mode = MODE_S;
328 tmpline[0] = '\0';
329
330 #ifdef KERBEROS5
331 kerror = krb5_init_context(&kcontext);
332 if (kerror) {
333 syslog(LOG_NOTICE, "%s when initializing Kerberos context",
334 error_message(kerror));
335 exit(0);
336 }
337 #endif KERBEROS5
338
339 /* If logins are disabled, print out the message. */
340 if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
341 while (fgets(line, sizeof(line), fd) != NULL) {
342 if ((cp = strchr(line, '\n')) != NULL)
343 *cp = '\0';
344 lreply(530, "%s", line);
345 }
346 (void) fflush(stdout);
347 (void) fclose(fd);
348 reply(530, "System not available.");
349 exit(0);
350 }
351 if ((fd = fopen(conffilename(_PATH_FTPWELCOME), "r")) != NULL) {
352 while (fgets(line, sizeof(line), fd) != NULL) {
353 if ((cp = strchr(line, '\n')) != NULL)
354 *cp = '\0';
355 lreply(220, "%s", line);
356 }
357 (void) fflush(stdout);
358 (void) fclose(fd);
359 /* reply(220,) must follow */
360 }
361 (void) gethostname(hostname, sizeof(hostname));
362 reply(220, "%s FTP server (%s) ready.", hostname, version);
363 (void) setjmp(errcatch);
364 curclass.timeout = 300; /* 5 minutes, as per login(1) */
365 for (;;)
366 (void) yyparse();
367 /* NOTREACHED */
368 }
369
370 static void
371 lostconn(signo)
372 int signo;
373 {
374
375 if (debug)
376 syslog(LOG_DEBUG, "lost connection");
377 dologout(1);
378 }
379
380 /*
381 * Helper function for sgetpwnam().
382 */
383 static char *
384 sgetsave(s)
385 char *s;
386 {
387 char *new = malloc((unsigned) strlen(s) + 1);
388
389 if (new == NULL) {
390 perror_reply(421, "Local resource failure: malloc");
391 dologout(1);
392 /* NOTREACHED */
393 }
394 (void) strcpy(new, s);
395 return (new);
396 }
397
398 /*
399 * Save the result of a getpwnam. Used for USER command, since
400 * the data returned must not be clobbered by any other command
401 * (e.g., globbing).
402 */
403 static struct passwd *
404 sgetpwnam(name)
405 char *name;
406 {
407 static struct passwd save;
408 struct passwd *p;
409
410 if ((p = getpwnam(name)) == NULL)
411 return (p);
412 if (save.pw_name) {
413 free(save.pw_name);
414 free(save.pw_passwd);
415 free(save.pw_gecos);
416 free(save.pw_dir);
417 free(save.pw_shell);
418 }
419 save = *p;
420 save.pw_name = sgetsave(p->pw_name);
421 save.pw_passwd = sgetsave(p->pw_passwd);
422 save.pw_gecos = sgetsave(p->pw_gecos);
423 save.pw_dir = sgetsave(p->pw_dir);
424 save.pw_shell = sgetsave(p->pw_shell);
425 return (&save);
426 }
427
428 static int login_attempts; /* number of failed login attempts */
429 static int askpasswd; /* had user command, ask for passwd */
430 static char curname[10]; /* current USER name */
431
432 /*
433 * USER command.
434 * Sets global passwd pointer pw if named account exists and is acceptable;
435 * sets askpasswd if a PASS command is expected. If logged in previously,
436 * need to reset state. If name is "ftp" or "anonymous", the name is not in
437 * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
438 * If account doesn't exist, ask for passwd anyway. Otherwise, check user
439 * requesting login privileges. Disallow anyone who does not have a standard
440 * shell as returned by getusershell(). Disallow anyone mentioned in the file
441 * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
442 */
443 void
444 user(name)
445 char *name;
446 {
447 if (logged_in) {
448 if (guest) {
449 reply(530, "Can't change user from guest login.");
450 return;
451 } else if (dochroot) {
452 reply(530, "Can't change user from chroot user.");
453 return;
454 }
455 end_login();
456 }
457
458 #if defined(KERBEROS) || defined(KERBEROS5)
459 kdestroy();
460 #endif
461
462 guest = 0;
463 if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
464 if (checkaccess("ftp") || checkaccess("anonymous"))
465 reply(530, "User %s access denied.", name);
466 else if ((pw = sgetpwnam("ftp")) != NULL) {
467 guest = 1;
468 askpasswd = 1;
469 reply(331,
470 "Guest login ok, type your name as password.");
471 } else
472 reply(530, "User %s unknown.", name);
473 if (!askpasswd && logging)
474 syslog(LOG_NOTICE,
475 "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
476 return;
477 }
478
479 pw = sgetpwnam(name);
480 if (logging)
481 strncpy(curname, name, sizeof(curname)-1);
482
483 #ifdef SKEY
484 if (skey_haskey(name) == 0) {
485 char *myskey;
486
487 myskey = skey_keyinfo(name);
488 reply(331, "Password [%s] required for %s.",
489 myskey ? myskey : "error getting challenge", name);
490 } else
491 #endif
492 reply(331, "Password required for %s.", name);
493
494 askpasswd = 1;
495 /*
496 * Delay before reading passwd after first failed
497 * attempt to slow down passwd-guessing programs.
498 */
499 if (login_attempts)
500 sleep((unsigned) login_attempts);
501 }
502
503 /*
504 * Check if a user is in the file "fname"
505 */
506 static int
507 checkuser(fname, name)
508 char *fname;
509 char *name;
510 {
511 FILE *fd;
512 int found = 0;
513 char *p, line[BUFSIZ];
514
515 if ((fd = fopen(fname, "r")) != NULL) {
516 while (fgets(line, sizeof(line), fd) != NULL)
517 if ((p = strchr(line, '\n')) != NULL) {
518 *p = '\0';
519 if (line[0] == '#')
520 continue;
521 if (strcmp(line, name) == 0) {
522 found = 1;
523 break;
524 }
525 }
526 (void) fclose(fd);
527 }
528 return (found);
529 }
530
531 /*
532 * Determine whether a user has access, based on information in
533 * _PATH_FTPUSERS. Each line is a shell-style glob followed by
534 * `allow' or `deny' (with deny being the default if anything but
535 * `allow', or nothing at all, is specified).
536 *
537 * Each glob is matched against the username in turn, and the first
538 * match found is used. If no match is found, access is allowed.
539 *
540 * Any line starting with `#' is considered a comment and ignored.
541 *
542 * This is probably not the best way to do this, but it preserves
543 * the old semantics where if a user was listed in the file he was
544 * denied, otherwise he was allowed.
545 *
546 * There is one change in the semantics, however; ftpd will now `fail
547 * safe' and deny all access if there's no /etc/ftpusers file.
548 *
549 * Return 1 if the user is denied, or 0 if he is allowed.
550 */
551 static int
552 checkaccess(name)
553 char *name;
554 {
555 #define ALLOWED 0
556 #define NOT_ALLOWED 1
557 FILE *fd;
558 int retval = ALLOWED;
559 char *glob, *perm, line[BUFSIZ];
560
561 if ((fd = fopen(conffilename(_PATH_FTPUSERS), "r")) == NULL)
562 return NOT_ALLOWED;
563
564 while (fgets(line, sizeof(line), fd) != NULL) {
565 glob = strtok(line, " \t\n");
566 if (glob[0] == '#')
567 continue;
568 perm = strtok(NULL, " \t\n");
569 if (fnmatch(glob, name, 0) == 0) {
570 if (perm != NULL && strcmp(perm, "allow") == 0)
571 retval = ALLOWED;
572 else
573 retval = NOT_ALLOWED;
574 break;
575 }
576 }
577 (void) fclose(fd);
578 return (retval);
579 }
580 #undef ALLOWED
581 #undef NOT_ALLOWED
582
583 /*
584 * Terminate login as previous user, if any, resetting state;
585 * used when USER command is given or login fails.
586 */
587 static void
588 end_login()
589 {
590
591 (void) seteuid((uid_t)0);
592 if (logged_in)
593 logwtmp(ttyline, "", "");
594 pw = NULL;
595 logged_in = 0;
596 guest = 0;
597 dochroot = 0;
598 }
599
600 void
601 pass(passwd)
602 char *passwd;
603 {
604 int rval;
605 FILE *fd;
606 char *cp, *shell, *home;
607
608 if (logged_in || askpasswd == 0) {
609 reply(503, "Login with USER first.");
610 return;
611 }
612 askpasswd = 0;
613 if (!guest) { /* "ftp" is only account allowed no password */
614 if (pw == NULL) {
615 rval = 1; /* failure below */
616 goto skip;
617 }
618 #ifdef KERBEROS
619 if (klogin(pw, "", hostname, passwd) == 0) {
620 rval = 0;
621 goto skip;
622 }
623 #endif
624 #ifdef KERBEROS5
625 if (klogin(pw, "", hostname, passwd) == 0) {
626 rval = 0;
627 goto skip;
628 }
629 #endif
630 #ifdef SKEY
631 if (skey_haskey(pw->pw_name) == 0 &&
632 skey_passcheck(pw->pw_name, passwd) != -1) {
633 rval = 0;
634 goto skip;
635 }
636 #endif
637 if (*pw->pw_passwd != '\0' &&
638 !strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd)) {
639 rval = 0;
640 goto skip;
641 }
642 rval = 1;
643
644 skip:
645 /*
646 * If rval == 1, the user failed the authentication check
647 * above. If rval == 0, either Kerberos or local authentication
648 * succeeded.
649 */
650 if (rval) {
651 reply(530, "Login incorrect.");
652 if (logging) {
653 syslog(LOG_NOTICE,
654 "FTP LOGIN FAILED FROM %s", remotehost);
655 syslog(LOG_AUTHPRIV | LOG_NOTICE,
656 "FTP LOGIN FAILED FROM %s, %s",
657 remotehost, curname);
658 }
659 pw = NULL;
660 if (login_attempts++ >= 5) {
661 syslog(LOG_NOTICE,
662 "repeated login failures from %s",
663 remotehost);
664 exit(0);
665 }
666 return;
667 }
668 }
669
670 /* password was ok; see if anything else prevents login */
671 if (checkaccess(pw->pw_name)) {
672 reply(530, "User %s may not use FTP.", pw->pw_name);
673 if (logging)
674 syslog(LOG_NOTICE, "FTP LOGIN REFUSED FROM %s, %s",
675 remotehost, pw->pw_name);
676 pw = (struct passwd *) NULL;
677 return;
678 }
679 /* check for valid shell, if not guest user */
680 if ((shell = pw->pw_shell) == NULL || *shell == 0)
681 shell = _PATH_BSHELL;
682 while ((cp = getusershell()) != NULL)
683 if (strcmp(cp, shell) == 0)
684 break;
685 endusershell();
686 if (cp == NULL && guest == 0) {
687 reply(530, "User %s may not use FTP.", pw->pw_name);
688 if (logging)
689 syslog(LOG_NOTICE,
690 "FTP LOGIN REFUSED FROM %s, %s",
691 remotehost, pw->pw_name);
692 pw = (struct passwd *) NULL;
693 return;
694 }
695
696 login_attempts = 0; /* this time successful */
697 if (setegid((gid_t)pw->pw_gid) < 0) {
698 reply(550, "Can't set gid.");
699 return;
700 }
701 (void) initgroups(pw->pw_name, pw->pw_gid);
702
703 /* open wtmp before chroot */
704 logwtmp(ttyline, pw->pw_name, remotehost);
705 logged_in = 1;
706
707 dochroot = checkuser(conffilename(_PATH_FTPCHROOT), pw->pw_name);
708
709 /* parse ftpd.conf, setting up various parameters */
710 if (guest)
711 parse_conf(CLASS_GUEST);
712 else if (dochroot)
713 parse_conf(CLASS_CHROOT);
714 else
715 parse_conf(CLASS_REAL);
716
717 home = "/";
718 if (guest) {
719 /*
720 * We MUST do a chdir() after the chroot. Otherwise
721 * the old current directory will be accessible as "."
722 * outside the new root!
723 */
724 if (chroot(anondir ? anondir : pw->pw_dir) < 0 ||
725 chdir("/") < 0) {
726 reply(550, "Can't set guest privileges.");
727 goto bad;
728 }
729 } else if (dochroot) {
730 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
731 reply(550, "Can't change root.");
732 goto bad;
733 }
734 } else if (chdir(pw->pw_dir) < 0) {
735 if (chdir("/") < 0) {
736 reply(530, "User %s: can't change directory to %s.",
737 pw->pw_name, pw->pw_dir);
738 goto bad;
739 } else
740 lreply(230, "No directory! Logging in with home=/");
741 } else
742 home = pw->pw_dir;
743 if (seteuid((uid_t)pw->pw_uid) < 0) {
744 reply(550, "Can't set uid.");
745 goto bad;
746 }
747 setenv("HOME", home, 1);
748
749
750 /*
751 * Display a login message, if it exists.
752 * N.B. reply(230,) must follow the message.
753 */
754 if ((fd = fopen(conffilename(_PATH_FTPLOGINMESG), "r")) != NULL) {
755 char *cp, line[LINE_MAX];
756
757 while (fgets(line, sizeof(line), fd) != NULL) {
758 if ((cp = strchr(line, '\n')) != NULL)
759 *cp = '\0';
760 lreply(230, "%s", line);
761 }
762 (void) fflush(stdout);
763 (void) fclose(fd);
764 }
765 show_chdir_messages(230);
766 if (guest) {
767 reply(230, "Guest login ok, access restrictions apply.");
768 #ifdef HASSETPROCTITLE
769 snprintf(proctitle, sizeof(proctitle),
770 "%s: anonymous/%.*s", remotehost,
771 (int) (sizeof(proctitle) - sizeof(remotehost) -
772 sizeof(": anonymous/")), passwd);
773 setproctitle(proctitle);
774 #endif /* HASSETPROCTITLE */
775 if (logging)
776 syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s",
777 remotehost, passwd);
778 } else {
779 reply(230, "User %s logged in.", pw->pw_name);
780 #ifdef HASSETPROCTITLE
781 snprintf(proctitle, sizeof(proctitle),
782 "%s: %s", remotehost, pw->pw_name);
783 setproctitle(proctitle);
784 #endif /* HASSETPROCTITLE */
785 if (logging)
786 syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
787 remotehost, pw->pw_name);
788 }
789 (void) umask(curclass.umask);
790 return;
791 bad:
792 /* Forget all about it... */
793 end_login();
794 }
795
796 void
797 retrieve(cmd, name)
798 char *cmd, *name;
799 {
800 FILE *fin = NULL, *dout;
801 struct stat st;
802 int (*closefunc) __P((FILE *)) = NULL;
803 int log;
804
805 log = (cmd == 0);
806 if (cmd == 0) {
807 fin = fopen(name, "r"), closefunc = fclose;
808 if (fin == NULL)
809 cmd = do_conversion(name);
810 }
811 if (cmd) {
812 char line[BUFSIZ];
813
814 (void)snprintf(line, sizeof(line), cmd, name), name = line;
815 fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
816 st.st_size = -1;
817 st.st_blksize = BUFSIZ;
818 }
819 if (fin == NULL) {
820 if (errno != 0) {
821 perror_reply(550, name);
822 if (log) {
823 LOGCMD("get", name);
824 }
825 }
826 return;
827 }
828 byte_count = -1;
829 if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
830 reply(550, "%s: not a plain file.", name);
831 goto done;
832 }
833 if (restart_point) {
834 if (type == TYPE_A) {
835 off_t i, n;
836 int c;
837
838 n = restart_point;
839 i = 0;
840 while (i++ < n) {
841 if ((c=getc(fin)) == EOF) {
842 perror_reply(550, name);
843 goto done;
844 }
845 if (c == '\n')
846 i++;
847 }
848 } else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
849 perror_reply(550, name);
850 goto done;
851 }
852 }
853 dout = dataconn(name, st.st_size, "w");
854 if (dout == NULL)
855 goto done;
856 send_data(fin, dout, st.st_blksize);
857 (void) fclose(dout);
858 data = -1;
859 pdata = -1;
860 done:
861 if (log)
862 LOGBYTES("get", name, byte_count);
863 (*closefunc)(fin);
864 }
865
866 void
867 store(name, mode, unique)
868 char *name, *mode;
869 int unique;
870 {
871 FILE *fout, *din;
872 struct stat st;
873 int (*closefunc) __P((FILE *));
874
875 if (unique && stat(name, &st) == 0 &&
876 (name = gunique(name)) == NULL) {
877 LOGCMD(*mode == 'w' ? "put" : "append", name);
878 return;
879 }
880
881 if (restart_point)
882 mode = "r+";
883 fout = fopen(name, mode);
884 closefunc = fclose;
885 if (fout == NULL) {
886 perror_reply(553, name);
887 LOGCMD(*mode == 'w' ? "put" : "append", name);
888 return;
889 }
890 byte_count = -1;
891 if (restart_point) {
892 if (type == TYPE_A) {
893 off_t i, n;
894 int c;
895
896 n = restart_point;
897 i = 0;
898 while (i++ < n) {
899 if ((c=getc(fout)) == EOF) {
900 perror_reply(550, name);
901 goto done;
902 }
903 if (c == '\n')
904 i++;
905 }
906 /*
907 * We must do this seek to "current" position
908 * because we are changing from reading to
909 * writing.
910 */
911 if (fseek(fout, 0L, SEEK_CUR) < 0) {
912 perror_reply(550, name);
913 goto done;
914 }
915 } else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
916 perror_reply(550, name);
917 goto done;
918 }
919 }
920 din = dataconn(name, (off_t)-1, "r");
921 if (din == NULL)
922 goto done;
923 if (receive_data(din, fout) == 0) {
924 if (unique)
925 reply(226, "Transfer complete (unique file name:%s).",
926 name);
927 else
928 reply(226, "Transfer complete.");
929 }
930 (void) fclose(din);
931 data = -1;
932 pdata = -1;
933 done:
934 LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
935 (*closefunc)(fout);
936 }
937
938 static FILE *
939 getdatasock(mode)
940 char *mode;
941 {
942 int on = 1, s, t, tries;
943
944 if (data >= 0)
945 return (fdopen(data, mode));
946 (void) seteuid((uid_t)0);
947 s = socket(AF_INET, SOCK_STREAM, 0);
948 if (s < 0)
949 goto bad;
950 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
951 (char *) &on, sizeof(on)) < 0)
952 goto bad;
953 /* anchor socket to avoid multi-homing problems */
954 data_source.sin_len = sizeof(struct sockaddr_in);
955 data_source.sin_family = AF_INET;
956 data_source.sin_addr = ctrl_addr.sin_addr;
957 for (tries = 1; ; tries++) {
958 if (bind(s, (struct sockaddr *)&data_source,
959 sizeof(data_source)) >= 0)
960 break;
961 if (errno != EADDRINUSE || tries > 10)
962 goto bad;
963 sleep(tries);
964 }
965 (void) seteuid((uid_t)pw->pw_uid);
966 #ifdef IP_TOS
967 on = IPTOS_THROUGHPUT;
968 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
969 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
970 #endif
971 return (fdopen(s, mode));
972 bad:
973 /* Return the real value of errno (close may change it) */
974 t = errno;
975 (void) seteuid((uid_t)pw->pw_uid);
976 (void) close(s);
977 errno = t;
978 return (NULL);
979 }
980
981 static FILE *
982 dataconn(name, size, mode)
983 char *name;
984 off_t size;
985 char *mode;
986 {
987 char sizebuf[32];
988 FILE *file;
989 int retry = 0, tos;
990
991 file_size = size;
992 byte_count = 0;
993 if (size != (off_t) -1)
994 (void)snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)",
995 (long long)size);
996 else
997 sizebuf[0] = '\0';
998 if (pdata >= 0) {
999 struct sockaddr_in from;
1000 int s, fromlen = sizeof(from);
1001
1002 (void) alarm(curclass.timeout);
1003 s = accept(pdata, (struct sockaddr *)&from, &fromlen);
1004 (void) alarm(0);
1005 if (s < 0) {
1006 reply(425, "Can't open data connection.");
1007 (void) close(pdata);
1008 pdata = -1;
1009 return (NULL);
1010 }
1011 (void) close(pdata);
1012 pdata = s;
1013 #ifdef IP_TOS
1014 tos = IPTOS_THROUGHPUT;
1015 (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1016 sizeof(int));
1017 #endif
1018 reply(150, "Opening %s mode data connection for '%s'%s.",
1019 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1020 return (fdopen(pdata, mode));
1021 }
1022 if (data >= 0) {
1023 reply(125, "Using existing data connection for '%s'%s.",
1024 name, sizebuf);
1025 usedefault = 1;
1026 return (fdopen(data, mode));
1027 }
1028 if (usedefault)
1029 data_dest = his_addr;
1030 usedefault = 1;
1031 file = getdatasock(mode);
1032 if (file == NULL) {
1033 reply(425, "Can't create data socket (%s,%d): %s.",
1034 inet_ntoa(data_source.sin_addr),
1035 ntohs(data_source.sin_port), strerror(errno));
1036 return (NULL);
1037 }
1038 data = fileno(file);
1039 while (connect(data, (struct sockaddr *)&data_dest,
1040 sizeof(data_dest)) < 0) {
1041 if (errno == EADDRINUSE && retry < swaitmax) {
1042 sleep((unsigned) swaitint);
1043 retry += swaitint;
1044 continue;
1045 }
1046 perror_reply(425, "Can't build data connection");
1047 (void) fclose(file);
1048 data = -1;
1049 return (NULL);
1050 }
1051 reply(150, "Opening %s mode data connection for '%s'%s.",
1052 type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1053 return (file);
1054 }
1055
1056 /*
1057 * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1058 * encapsulation of the data subject * to Mode, Structure, and Type.
1059 *
1060 * NB: Form isn't handled.
1061 */
1062 static void
1063 send_data(instr, outstr, blksize)
1064 FILE *instr, *outstr;
1065 off_t blksize;
1066 {
1067 int c, cnt, filefd, netfd;
1068 char *buf;
1069
1070 transflag++;
1071 if (setjmp(urgcatch)) {
1072 transflag = 0;
1073 return;
1074 }
1075
1076 switch (type) {
1077
1078 case TYPE_A:
1079 while ((c = getc(instr)) != EOF) {
1080 byte_count++;
1081 if (c == '\n') {
1082 if (ferror(outstr))
1083 goto data_err;
1084 (void) putc('\r', outstr);
1085 }
1086 (void) putc(c, outstr);
1087 }
1088 fflush(outstr);
1089 transflag = 0;
1090 if (ferror(instr))
1091 goto file_err;
1092 if (ferror(outstr))
1093 goto data_err;
1094 reply(226, "Transfer complete.");
1095 return;
1096
1097 case TYPE_I:
1098 case TYPE_L:
1099 if ((buf = malloc((u_int)blksize)) == NULL) {
1100 transflag = 0;
1101 perror_reply(451, "Local resource failure: malloc");
1102 return;
1103 }
1104 netfd = fileno(outstr);
1105 filefd = fileno(instr);
1106 while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 &&
1107 write(netfd, buf, cnt) == cnt)
1108 byte_count += cnt;
1109 transflag = 0;
1110 (void)free(buf);
1111 if (cnt != 0) {
1112 if (cnt < 0)
1113 goto file_err;
1114 goto data_err;
1115 }
1116 reply(226, "Transfer complete.");
1117 return;
1118 default:
1119 transflag = 0;
1120 reply(550, "Unimplemented TYPE %d in send_data", type);
1121 return;
1122 }
1123
1124 data_err:
1125 transflag = 0;
1126 perror_reply(426, "Data connection");
1127 return;
1128
1129 file_err:
1130 transflag = 0;
1131 perror_reply(551, "Error on input file");
1132 }
1133
1134 /*
1135 * Transfer data from peer to "outstr" using the appropriate encapulation of
1136 * the data subject to Mode, Structure, and Type.
1137 *
1138 * N.B.: Form isn't handled.
1139 */
1140 static int
1141 receive_data(instr, outstr)
1142 FILE *instr, *outstr;
1143 {
1144 int c, cnt, bare_lfs;
1145 char buf[BUFSIZ];
1146 #ifdef __GNUC__
1147 (void) &bare_lfs;
1148 #endif
1149
1150 bare_lfs = 0;
1151 transflag++;
1152 if (setjmp(urgcatch)) {
1153 transflag = 0;
1154 return (-1);
1155 }
1156
1157 switch (type) {
1158
1159 case TYPE_I:
1160 case TYPE_L:
1161 while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
1162 if (write(fileno(outstr), buf, cnt) != cnt)
1163 goto file_err;
1164 byte_count += cnt;
1165 }
1166 if (cnt < 0)
1167 goto data_err;
1168 transflag = 0;
1169 return (0);
1170
1171 case TYPE_E:
1172 reply(553, "TYPE E not implemented.");
1173 transflag = 0;
1174 return (-1);
1175
1176 case TYPE_A:
1177 while ((c = getc(instr)) != EOF) {
1178 byte_count++;
1179 if (c == '\n')
1180 bare_lfs++;
1181 while (c == '\r') {
1182 if (ferror(outstr))
1183 goto data_err;
1184 if ((c = getc(instr)) != '\n') {
1185 (void) putc ('\r', outstr);
1186 if (c == '\0' || c == EOF)
1187 goto contin2;
1188 }
1189 }
1190 (void) putc(c, outstr);
1191 contin2: ;
1192 }
1193 fflush(outstr);
1194 if (ferror(instr))
1195 goto data_err;
1196 if (ferror(outstr))
1197 goto file_err;
1198 transflag = 0;
1199 if (bare_lfs) {
1200 lreply(226,
1201 "WARNING! %d bare linefeeds received in ASCII mode",
1202 bare_lfs);
1203 (void)printf(" File may not have transferred correctly.\r\n");
1204 }
1205 return (0);
1206 default:
1207 reply(550, "Unimplemented TYPE %d in receive_data", type);
1208 transflag = 0;
1209 return (-1);
1210 }
1211
1212 data_err:
1213 transflag = 0;
1214 perror_reply(426, "Data Connection");
1215 return (-1);
1216
1217 file_err:
1218 transflag = 0;
1219 perror_reply(452, "Error writing file");
1220 return (-1);
1221 }
1222
1223 void
1224 statfilecmd(filename)
1225 char *filename;
1226 {
1227 FILE *fin;
1228 int c;
1229 char line[LINE_MAX];
1230
1231 (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
1232 fin = ftpd_popen(line, "r", 0);
1233 lreply(211, "status of %s:", filename);
1234 while ((c = getc(fin)) != EOF) {
1235 if (c == '\n') {
1236 if (ferror(stdout)){
1237 perror_reply(421, "control connection");
1238 (void) ftpd_pclose(fin);
1239 dologout(1);
1240 /* NOTREACHED */
1241 }
1242 if (ferror(fin)) {
1243 perror_reply(551, filename);
1244 (void) ftpd_pclose(fin);
1245 return;
1246 }
1247 (void) putc('\r', stdout);
1248 }
1249 (void) putc(c, stdout);
1250 }
1251 (void) ftpd_pclose(fin);
1252 reply(211, "End of Status");
1253 }
1254
1255 void
1256 statcmd()
1257 {
1258 struct sockaddr_in *sin;
1259 u_char *a, *p;
1260
1261 lreply(211, "%s FTP server status:", hostname);
1262 lreply(211, "%s", version);
1263 if (isdigit(remotehost[0]))
1264 lreply(211, "Connected to %s", remotehost);
1265 else
1266 lreply(211, "Connected to %s (%s)", remotehost,
1267 inet_ntoa(his_addr.sin_addr));
1268 if (logged_in) {
1269 if (guest)
1270 lreply(211, "Logged in anonymously");
1271 else
1272 lreply(211, "Logged in as %s", pw->pw_name);
1273 } else if (askpasswd)
1274 lreply(211, "Waiting for password");
1275 else
1276 lreply(211, "Waiting for user name");
1277 printf("211- TYPE: %s", typenames[type]);
1278 if (type == TYPE_A || type == TYPE_E)
1279 printf(", FORM: %s", formnames[form]);
1280 if (type == TYPE_L)
1281 #if NBBY == 8
1282 printf(" %d", NBBY);
1283 #else
1284 printf(" %d", bytesize); /* need definition! */
1285 #endif
1286 printf("; STRUcture: %s; transfer MODE: %s\r\n",
1287 strunames[stru], modenames[mode]);
1288 if (data != -1)
1289 lreply(211, "Data connection open");
1290 else if (pdata != -1) {
1291 printf("211- in Passive mode");
1292 sin = &pasv_addr;
1293 goto printaddr;
1294 } else if (usedefault == 0) {
1295 printf("211- PORT");
1296 sin = &data_dest;
1297 printaddr:
1298 a = (u_char *) &sin->sin_addr;
1299 p = (u_char *) &sin->sin_port;
1300 #define UC(b) (((int) b) & 0xff)
1301 printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1302 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1303 #undef UC
1304 } else
1305 lreply(211, "No data connection");
1306
1307 if (logged_in) {
1308 struct ftpconv *cp;
1309
1310 lreply(211, "");
1311 lreply(211, "Class: %s", curclass.classname);
1312 lreply(211, "Check PORT commands: %sabled",
1313 curclass.checkportcmd ? "en" : "dis");
1314 if (curclass.display)
1315 lreply(211, "Display file: %s", curclass.display);
1316 if (curclass.notify)
1317 lreply(211, "Notify fileglob: %s", curclass.notify);
1318 lreply(211, "Idle timeout: %d, maximum timeout: %d",
1319 curclass.timeout, curclass.maxtimeout);
1320 lreply(211, "DELE, MKD, RMD, UMASK, CHMOD commands: %sabled",
1321 curclass.modify ? "en" : "dis");
1322 lreply(211, "Umask: %.04o", curclass.umask);
1323 for (cp = curclass.conversions; cp != NULL; cp=cp->next) {
1324 if (cp->suffix == NULL || cp->types == NULL ||
1325 cp->command == NULL)
1326 continue;
1327 lreply(211,
1328 "Conversion: %s [%s] disable: %s, command: %s",
1329 cp->suffix, cp->types, cp->disable, cp->command);
1330 }
1331 }
1332
1333 reply(211, "End of status");
1334 }
1335
1336 void
1337 fatal(s)
1338 char *s;
1339 {
1340
1341 reply(451, "Error in server: %s\n", s);
1342 reply(221, "Closing connection due to server error.");
1343 dologout(0);
1344 /* NOTREACHED */
1345 }
1346
1347 void
1348 #if __STDC__
1349 reply(int n, const char *fmt, ...)
1350 #else
1351 reply(n, fmt, va_alist)
1352 int n;
1353 char *fmt;
1354 va_dcl
1355 #endif
1356 {
1357 va_list ap;
1358 #if __STDC__
1359 va_start(ap, fmt);
1360 #else
1361 va_start(ap);
1362 #endif
1363 (void)printf("%d ", n);
1364 (void)vprintf(fmt, ap);
1365 (void)printf("\r\n");
1366 (void)fflush(stdout);
1367 if (debug) {
1368 syslog(LOG_DEBUG, "<--- %d ", n);
1369 vsyslog(LOG_DEBUG, fmt, ap);
1370 }
1371 }
1372
1373 void
1374 #if __STDC__
1375 lreply(int n, const char *fmt, ...)
1376 #else
1377 lreply(n, fmt, va_alist)
1378 int n;
1379 char *fmt;
1380 va_dcl
1381 #endif
1382 {
1383 va_list ap;
1384 #if __STDC__
1385 va_start(ap, fmt);
1386 #else
1387 va_start(ap);
1388 #endif
1389 (void)printf("%d- ", n);
1390 (void)vprintf(fmt, ap);
1391 (void)printf("\r\n");
1392 (void)fflush(stdout);
1393 if (debug) {
1394 syslog(LOG_DEBUG, "<--- %d- ", n);
1395 vsyslog(LOG_DEBUG, fmt, ap);
1396 }
1397 }
1398
1399 static void
1400 ack(s)
1401 char *s;
1402 {
1403
1404 reply(250, "%s command successful.", s);
1405 }
1406
1407 void
1408 nack(s)
1409 char *s;
1410 {
1411
1412 reply(502, "%s command not implemented.", s);
1413 }
1414
1415 /* ARGSUSED */
1416 void
1417 yyerror(s)
1418 char *s;
1419 {
1420 char *cp;
1421
1422 if ((cp = strchr(cbuf,'\n')) != NULL)
1423 *cp = '\0';
1424 reply(500, "'%s': command not understood.", cbuf);
1425 }
1426
1427 void
1428 delete(name)
1429 char *name;
1430 {
1431
1432 LOGCMD("delete", name);
1433 if (remove(name) < 0)
1434 perror_reply(550, name);
1435 else
1436 ack("DELE");
1437 }
1438
1439 void
1440 cwd(path)
1441 char *path;
1442 {
1443
1444 if (chdir(path) < 0)
1445 perror_reply(550, path);
1446 else {
1447 show_chdir_messages(250);
1448 ack("CWD");
1449 }
1450 }
1451
1452 static void
1453 replydirname(name, message)
1454 const char *name, *message;
1455 {
1456 char npath[MAXPATHLEN + 1];
1457 int i;
1458
1459 for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) {
1460 npath[i] = *name;
1461 if (*name == '"')
1462 npath[++i] = '"';
1463 }
1464 npath[i] = '\0';
1465 reply(257, "\"%s\" %s", npath, message);
1466 }
1467
1468 void
1469 makedir(name)
1470 char *name;
1471 {
1472
1473 LOGCMD("mkdir", name);
1474 if (mkdir(name, 0777) < 0)
1475 perror_reply(550, name);
1476 else
1477 replydirname(name, "directory created.");
1478 }
1479
1480 void
1481 removedir(name)
1482 char *name;
1483 {
1484
1485 LOGCMD("rmdir", name);
1486 if (rmdir(name) < 0)
1487 perror_reply(550, name);
1488 else
1489 ack("RMD");
1490 }
1491
1492 void
1493 pwd()
1494 {
1495 char path[MAXPATHLEN + 1];
1496
1497 if (getcwd(path, sizeof(path) - 1) == NULL)
1498 reply(550, "%s.", path);
1499 else
1500 replydirname(path, "is the current directory.");
1501 }
1502
1503 char *
1504 renamefrom(name)
1505 char *name;
1506 {
1507 struct stat st;
1508
1509 if (stat(name, &st) < 0) {
1510 perror_reply(550, name);
1511 return ((char *)0);
1512 }
1513 reply(350, "File exists, ready for destination name");
1514 return (name);
1515 }
1516
1517 void
1518 renamecmd(from, to)
1519 char *from, *to;
1520 {
1521
1522 LOGCMD2("rename", from, to);
1523 if (rename(from, to) < 0)
1524 perror_reply(550, "rename");
1525 else
1526 ack("RNTO");
1527 }
1528
1529 static void
1530 dolog(sin)
1531 struct sockaddr_in *sin;
1532 {
1533 struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
1534 sizeof(struct in_addr), AF_INET);
1535
1536 if (hp)
1537 (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
1538 else
1539 (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
1540 sizeof(remotehost));
1541 #ifdef HASSETPROCTITLE
1542 snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1543 setproctitle(proctitle);
1544 #endif /* HASSETPROCTITLE */
1545
1546 if (logging)
1547 syslog(LOG_INFO, "connection from %s", remotehost);
1548 }
1549
1550 /*
1551 * Record logout in wtmp file
1552 * and exit with supplied status.
1553 */
1554 void
1555 dologout(status)
1556 int status;
1557 {
1558 /*
1559 * Prevent reception of SIGURG from resulting in a resumption
1560 * back to the main program loop.
1561 */
1562 transflag = 0;
1563
1564 if (logged_in) {
1565 (void) seteuid((uid_t)0);
1566 logwtmp(ttyline, "", "");
1567 #ifdef KERBEROS
1568 if (!notickets && krbtkfile_env)
1569 unlink(krbtkfile_env);
1570 #endif
1571 }
1572 /* beware of flushing buffers after a SIGPIPE */
1573 _exit(status);
1574 }
1575
1576 static void
1577 myoob(signo)
1578 int signo;
1579 {
1580 char *cp;
1581
1582 /* only process if transfer occurring */
1583 if (!transflag)
1584 return;
1585 cp = tmpline;
1586 if (getline(cp, 7, stdin) == NULL) {
1587 reply(221, "You could at least say goodbye.");
1588 dologout(0);
1589 }
1590 upper(cp);
1591 if (strcmp(cp, "ABOR\r\n") == 0) {
1592 tmpline[0] = '\0';
1593 reply(426, "Transfer aborted. Data connection closed.");
1594 reply(226, "Abort successful");
1595 longjmp(urgcatch, 1);
1596 }
1597 if (strcmp(cp, "STAT\r\n") == 0) {
1598 if (file_size != (off_t) -1)
1599 reply(213, "Status: %qd of %qd bytes transferred",
1600 byte_count, file_size);
1601 else
1602 reply(213, "Status: %qd bytes transferred", byte_count);
1603 }
1604 }
1605
1606 /*
1607 * Note: a response of 425 is not mentioned as a possible response to
1608 * the PASV command in RFC959. However, it has been blessed as
1609 * a legitimate response by Jon Postel in a telephone conversation
1610 * with Rick Adams on 25 Jan 89.
1611 */
1612 void
1613 passive()
1614 {
1615 int len;
1616 char *p, *a;
1617
1618 pdata = socket(AF_INET, SOCK_STREAM, 0);
1619 if (pdata < 0 || !logged_in) {
1620 perror_reply(425, "Can't open passive connection");
1621 return;
1622 }
1623 pasv_addr = ctrl_addr;
1624 pasv_addr.sin_port = 0;
1625 (void) seteuid((uid_t)0);
1626 if (bind(pdata, (struct sockaddr *)&pasv_addr, sizeof(pasv_addr)) < 0) {
1627 (void) seteuid((uid_t)pw->pw_uid);
1628 goto pasv_error;
1629 }
1630 (void) seteuid((uid_t)pw->pw_uid);
1631 len = sizeof(pasv_addr);
1632 if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
1633 goto pasv_error;
1634 if (listen(pdata, 1) < 0)
1635 goto pasv_error;
1636 a = (char *) &pasv_addr.sin_addr;
1637 p = (char *) &pasv_addr.sin_port;
1638
1639 #define UC(b) (((int) b) & 0xff)
1640
1641 reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
1642 UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1643 return;
1644
1645 pasv_error:
1646 (void) close(pdata);
1647 pdata = -1;
1648 perror_reply(425, "Can't open passive connection");
1649 return;
1650 }
1651
1652 /*
1653 * Generate unique name for file with basename "local".
1654 * The file named "local" is already known to exist.
1655 * Generates failure reply on error.
1656 *
1657 * XXX this function should under go changes similar to
1658 * the mktemp(3)/mkstemp(3) changes.
1659 */
1660 static char *
1661 gunique(local)
1662 char *local;
1663 {
1664 static char new[MAXPATHLEN];
1665 struct stat st;
1666 int count, len;
1667 char *cp;
1668
1669 cp = strrchr(local, '/');
1670 if (cp)
1671 *cp = '\0';
1672 if (stat(cp ? local : ".", &st) < 0) {
1673 perror_reply(553, cp ? local : ".");
1674 return ((char *) 0);
1675 }
1676 if (cp)
1677 *cp = '/';
1678 (void) strcpy(new, local);
1679 len = strlen(new);
1680 cp = new + len;
1681 *cp++ = '.';
1682 for (count = 1; count < 100; count++) {
1683 (void)snprintf(cp, sizeof(new) - len - 2, "%d", count);
1684 if (stat(new, &st) < 0)
1685 return (new);
1686 }
1687 reply(452, "Unique file name cannot be created.");
1688 return (NULL);
1689 }
1690
1691 /*
1692 * Format and send reply containing system error number.
1693 */
1694 void
1695 perror_reply(code, string)
1696 int code;
1697 char *string;
1698 {
1699
1700 reply(code, "%s: %s.", string, strerror(errno));
1701 }
1702
1703 static char *onefile[] = {
1704 "",
1705 0
1706 };
1707
1708 void
1709 send_file_list(whichf)
1710 char *whichf;
1711 {
1712 struct stat st;
1713 DIR *dirp = NULL;
1714 struct dirent *dir;
1715 FILE *dout = NULL;
1716 char **dirlist, *dirname;
1717 int simple = 0;
1718 int freeglob = 0;
1719 glob_t gl;
1720 #ifdef __GNUC__
1721 (void) &dout;
1722 (void) &dirlist;
1723 (void) &simple;
1724 (void) &freeglob;
1725 #endif
1726
1727 if (strpbrk(whichf, "~{[*?") != NULL) {
1728 int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
1729
1730 memset(&gl, 0, sizeof(gl));
1731 freeglob = 1;
1732 if (glob(whichf, flags, 0, &gl)) {
1733 reply(550, "not found");
1734 goto out;
1735 } else if (gl.gl_pathc == 0) {
1736 errno = ENOENT;
1737 perror_reply(550, whichf);
1738 goto out;
1739 }
1740 dirlist = gl.gl_pathv;
1741 } else {
1742 onefile[0] = whichf;
1743 dirlist = onefile;
1744 simple = 1;
1745 }
1746
1747 if (setjmp(urgcatch)) {
1748 transflag = 0;
1749 goto out;
1750 }
1751 while ((dirname = *dirlist++) != NULL) {
1752 int trailingslash = 0;
1753
1754 if (stat(dirname, &st) < 0) {
1755 /*
1756 * If user typed "ls -l", etc, and the client
1757 * used NLST, do what the user meant.
1758 */
1759 if (dirname[0] == '-' && *dirlist == NULL &&
1760 transflag == 0) {
1761 retrieve("/bin/ls %s", dirname);
1762 goto out;
1763 }
1764 perror_reply(550, whichf);
1765 if (dout != NULL) {
1766 (void) fclose(dout);
1767 transflag = 0;
1768 data = -1;
1769 pdata = -1;
1770 }
1771 goto out;
1772 }
1773
1774 if (S_ISREG(st.st_mode)) {
1775 if (dout == NULL) {
1776 dout = dataconn("file list", (off_t)-1, "w");
1777 if (dout == NULL)
1778 goto out;
1779 transflag++;
1780 }
1781 fprintf(dout, "%s%s\n", dirname,
1782 type == TYPE_A ? "\r" : "");
1783 byte_count += strlen(dirname) + 1;
1784 continue;
1785 } else if (!S_ISDIR(st.st_mode))
1786 continue;
1787
1788 if (dirname[strlen(dirname) - 1] == '/')
1789 trailingslash++;
1790
1791 if ((dirp = opendir(dirname)) == NULL)
1792 continue;
1793
1794 while ((dir = readdir(dirp)) != NULL) {
1795 char nbuf[MAXPATHLEN];
1796
1797 if (dir->d_name[0] == '.' && dir->d_namlen == 1)
1798 continue;
1799 if (dir->d_name[0] == '.' && dir->d_name[1] == '.' &&
1800 dir->d_namlen == 2)
1801 continue;
1802
1803 (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname,
1804 trailingslash ? "" : "/", dir->d_name);
1805
1806 /*
1807 * We have to do a stat to ensure it's
1808 * not a directory or special file.
1809 */
1810 if (simple || (stat(nbuf, &st) == 0 &&
1811 S_ISREG(st.st_mode))) {
1812 if (dout == NULL) {
1813 dout = dataconn("file list", (off_t)-1,
1814 "w");
1815 if (dout == NULL)
1816 goto out;
1817 transflag++;
1818 }
1819 if (nbuf[0] == '.' && nbuf[1] == '/')
1820 fprintf(dout, "%s%s\n", &nbuf[2],
1821 type == TYPE_A ? "\r" : "");
1822 else
1823 fprintf(dout, "%s%s\n", nbuf,
1824 type == TYPE_A ? "\r" : "");
1825 byte_count += strlen(nbuf) + 1;
1826 }
1827 }
1828 (void) closedir(dirp);
1829 }
1830
1831 if (dout == NULL)
1832 reply(550, "No files found.");
1833 else if (ferror(dout) != 0)
1834 perror_reply(550, "Data connection");
1835 else
1836 reply(226, "Transfer complete.");
1837
1838 transflag = 0;
1839 if (dout != NULL)
1840 (void) fclose(dout);
1841 data = -1;
1842 pdata = -1;
1843 out:
1844 if (freeglob) {
1845 freeglob = 0;
1846 globfree(&gl);
1847 }
1848 }
1849
1850 char *
1851 conffilename(s)
1852 const char *s;
1853 {
1854 static char filename[MAXPATHLEN];
1855
1856 (void)snprintf(filename, sizeof(filename), "%s/%s", confdir ,s);
1857 return filename;
1858 }
1859