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