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