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