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