xref: /freebsd/crypto/heimdal/appl/ftp/ftpd/ftpd.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
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  #define	FTP_NAMES
35  #include "ftpd_locl.h"
36  #ifdef KRB5
37  #include <krb5.h>
38  #endif
39  #include "getarg.h"
40  
41  RCSID("$Id$");
42  
43  static char version[] = "Version 6.00";
44  
45  extern	off_t restart_point;
46  extern	char cbuf[];
47  
48  struct  sockaddr_storage ctrl_addr_ss;
49  struct  sockaddr *ctrl_addr = (struct sockaddr *)&ctrl_addr_ss;
50  
51  struct  sockaddr_storage data_source_ss;
52  struct  sockaddr *data_source = (struct sockaddr *)&data_source_ss;
53  
54  struct  sockaddr_storage data_dest_ss;
55  struct  sockaddr *data_dest = (struct sockaddr *)&data_dest_ss;
56  
57  struct  sockaddr_storage his_addr_ss;
58  struct  sockaddr *his_addr = (struct sockaddr *)&his_addr_ss;
59  
60  struct  sockaddr_storage pasv_addr_ss;
61  struct  sockaddr *pasv_addr = (struct sockaddr *)&pasv_addr_ss;
62  
63  int	data;
64  int	logged_in;
65  struct	passwd *pw;
66  int	debug = 0;
67  int	ftpd_timeout = 900;    /* timeout after 15 minutes of inactivity */
68  int	maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */
69  int	restricted_data_ports = 1;
70  int	logging;
71  int	guest;
72  int	dochroot;
73  int	type;
74  int	form;
75  int	stru;			/* avoid C keyword */
76  int	mode;
77  int	usedefault = 1;		/* for data transfers */
78  int	pdata = -1;		/* for passive mode */
79  int	allow_insecure_oob = 1;
80  static int transflag;
81  static int urgflag;
82  off_t	file_size;
83  off_t	byte_count;
84  #if !defined(CMASK) || CMASK == 0
85  #undef CMASK
86  #define CMASK 027
87  #endif
88  int	defumask = CMASK;		/* default umask value */
89  int	guest_umask = 0777;	/* Paranoia for anonymous users */
90  char	tmpline[10240];
91  char	hostname[MaxHostNameLen];
92  char	remotehost[MaxHostNameLen];
93  static char ttyline[20];
94  int     paranoid = 1;
95  
96  #define AUTH_PLAIN	(1 << 0) /* allow sending passwords */
97  #define AUTH_OTP	(1 << 1) /* passwords are one-time */
98  #define AUTH_FTP	(1 << 2) /* allow anonymous login */
99  
100  static int auth_level = 0; /* Only allow kerberos login by default */
101  
102  /*
103   * Timeout intervals for retrying connections
104   * to hosts that don't accept PORT cmds.  This
105   * is a kludge, but given the problems with TCP...
106   */
107  #define	SWAITMAX	90	/* wait at most 90 seconds */
108  #define	SWAITINT	5	/* interval between retries */
109  
110  int	swaitmax = SWAITMAX;
111  int	swaitint = SWAITINT;
112  
113  #ifdef HAVE_SETPROCTITLE
114  char	proctitle[BUFSIZ];	/* initial part of title */
115  #endif /* HAVE_SETPROCTITLE */
116  
117  #define LOGCMD(cmd, file) \
118  	if (logging > 1) \
119  	    syslog(LOG_INFO,"%s %s%s", cmd, \
120  		*(file) == '/' ? "" : curdir(), file);
121  #define LOGCMD2(cmd, file1, file2) \
122  	 if (logging > 1) \
123  	    syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
124  		*(file1) == '/' ? "" : curdir(), file1, \
125  		*(file2) == '/' ? "" : curdir(), file2);
126  #define LOGBYTES(cmd, file, cnt) \
127  	if (logging > 1) { \
128  		if (cnt == (off_t)-1) \
129  		    syslog(LOG_INFO,"%s %s%s", cmd, \
130  			*(file) == '/' ? "" : curdir(), file); \
131  		else \
132  		    syslog(LOG_INFO, "%s %s%s = %ld bytes", \
133  			cmd, (*(file) == '/') ? "" : curdir(), file, (long)cnt); \
134  	}
135  
136  static void	 ack (char *);
137  static void	 myoob (int);
138  static int	 handleoobcmd(void);
139  static int	 checkuser (char *, char *);
140  static int	 checkaccess (char *);
141  static FILE	*dataconn (const char *, off_t, const char *);
142  static void	 dolog (struct sockaddr *, int);
143  static void	 end_login (void);
144  static FILE	*getdatasock (const char *, int);
145  static char	*gunique (char *);
146  static RETSIGTYPE	 lostconn (int);
147  static int	 receive_data (FILE *, FILE *);
148  static void	 send_data (FILE *, FILE *);
149  static struct passwd * sgetpwnam (char *);
150  
151  static char *
curdir(void)152  curdir(void)
153  {
154  	static char path[MaxPathLen+1];	/* path + '/' + '\0' */
155  
156  	if (getcwd(path, sizeof(path)-1) == NULL)
157  		return ("");
158  	if (path[1] != '\0')		/* special case for root dir. */
159  		strlcat(path, "/", sizeof(path));
160  	/* For guest account, skip / since it's chrooted */
161  	return (guest ? path+1 : path);
162  }
163  
164  #ifndef LINE_MAX
165  #define LINE_MAX 1024
166  #endif
167  
168  static int
parse_auth_level(char * str)169  parse_auth_level(char *str)
170  {
171      char *p;
172      int ret = 0;
173      char *foo = NULL;
174  
175      for(p = strtok_r(str, ",", &foo);
176  	p;
177  	p = strtok_r(NULL, ",", &foo)) {
178  	if(strcmp(p, "user") == 0)
179  	    ;
180  #ifdef OTP
181  	else if(strcmp(p, "otp") == 0)
182  	    ret |= AUTH_PLAIN|AUTH_OTP;
183  #endif
184  	else if(strcmp(p, "ftp") == 0 ||
185  		strcmp(p, "safe") == 0)
186  	    ret |= AUTH_FTP;
187  	else if(strcmp(p, "plain") == 0)
188  	    ret |= AUTH_PLAIN;
189  	else if(strcmp(p, "none") == 0)
190  	    ret |= AUTH_PLAIN|AUTH_FTP;
191  	else
192  	    warnx("bad value for -a: `%s'", p);
193      }
194      return ret;
195  }
196  
197  /*
198   * Print usage and die.
199   */
200  
201  static int interactive_flag;
202  static char *guest_umask_string;
203  static char *port_string;
204  static char *umask_string;
205  static char *auth_string;
206  
207  int use_builtin_ls = -1;
208  
209  static int help_flag;
210  static int version_flag;
211  
212  static const char *good_chars = "+-=_,.";
213  
214  struct getargs args[] = {
215      { NULL, 'a', arg_string, &auth_string, "required authentication" },
216      { NULL, 'i', arg_flag, &interactive_flag, "don't assume stdin is a socket" },
217      { NULL, 'p', arg_string, &port_string, "what port to listen to" },
218      { NULL, 'g', arg_string, &guest_umask_string, "umask for guest logins" },
219      { NULL, 'l', arg_counter, &logging, "log more stuff", "" },
220      { NULL, 't', arg_integer, &ftpd_timeout, "initial timeout" },
221      { NULL, 'T', arg_integer, &maxtimeout, "max timeout" },
222      { NULL, 'u', arg_string, &umask_string, "umask for user logins" },
223      { NULL, 'U', arg_negative_flag, &restricted_data_ports, "don't use high data ports" },
224      { NULL, 'd', arg_flag, &debug, "enable debugging" },
225      { NULL, 'v', arg_flag, &debug, "enable debugging" },
226      { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" },
227      { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" },
228      { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" },
229  #ifdef KRB5
230      { "gss-bindings", 0,  arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL},
231  #endif
232      { "version", 0, arg_flag, &version_flag },
233      { "help", 'h', arg_flag, &help_flag }
234  };
235  
236  static int num_args = sizeof(args) / sizeof(args[0]);
237  
238  static void
usage(int code)239  usage (int code)
240  {
241      arg_printusage(args, num_args, NULL, "");
242      exit (code);
243  }
244  
245  /* output contents of a file */
246  static int
show_file(const char * file,int code)247  show_file(const char *file, int code)
248  {
249      FILE *f;
250      char buf[128];
251  
252      f = fopen(file, "r");
253      if(f == NULL)
254  	return -1;
255      while(fgets(buf, sizeof(buf), f)){
256  	buf[strcspn(buf, "\r\n")] = '\0';
257  	lreply(code, "%s", buf);
258      }
259      fclose(f);
260      return 0;
261  }
262  
263  int
main(int argc,char ** argv)264  main(int argc, char **argv)
265  {
266      socklen_t his_addr_len, ctrl_addr_len;
267      int on = 1;
268      int port;
269      struct servent *sp;
270  
271      int optind = 0;
272  
273      setprogname (argv[0]);
274  
275      if(getarg(args, num_args, argc, argv, &optind))
276  	usage(1);
277  
278      if(help_flag)
279  	usage(0);
280  
281      if(version_flag) {
282  	print_version(NULL);
283  	exit(0);
284      }
285  
286      if(auth_string)
287  	auth_level = parse_auth_level(auth_string);
288      {
289  	char *p;
290  	long val = 0;
291  
292  	if(guest_umask_string) {
293  	    val = strtol(guest_umask_string, &p, 8);
294  	    if (*p != '\0' || val < 0)
295  		warnx("bad value for -g");
296  	    else
297  		guest_umask = val;
298  	}
299  	if(umask_string) {
300  	    val = strtol(umask_string, &p, 8);
301  	    if (*p != '\0' || val < 0)
302  		warnx("bad value for -u");
303  	    else
304  		defumask = val;
305  	}
306      }
307      sp = getservbyname("ftp", "tcp");
308      if(sp)
309  	port = sp->s_port;
310      else
311  	port = htons(21);
312      if(port_string) {
313  	sp = getservbyname(port_string, "tcp");
314  	if(sp)
315  	    port = sp->s_port;
316  	else
317  	    if(isdigit((unsigned char)port_string[0]))
318  		port = htons(atoi(port_string));
319  	    else
320  		warnx("bad value for -p");
321      }
322  
323      if (maxtimeout < ftpd_timeout)
324  	maxtimeout = ftpd_timeout;
325  
326  #if 0
327      if (ftpd_timeout > maxtimeout)
328  	ftpd_timeout = maxtimeout;
329  #endif
330  
331      if(interactive_flag)
332  	mini_inetd(port, NULL);
333  
334      /*
335       * LOG_NDELAY sets up the logging connection immediately,
336       * necessary for anonymous ftp's that chroot and can't do it later.
337       */
338      openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
339      his_addr_len = sizeof(his_addr_ss);
340      if (getpeername(STDIN_FILENO, his_addr, &his_addr_len) < 0) {
341  	syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
342  	exit(1);
343      }
344      ctrl_addr_len = sizeof(ctrl_addr_ss);
345      if (getsockname(STDIN_FILENO, ctrl_addr, &ctrl_addr_len) < 0) {
346  	syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
347  	exit(1);
348      }
349  #if defined(IP_TOS)
350      if (ctrl_addr->sa_family == AF_INET)
351  	socket_set_tos(STDIN_FILENO, IP_TOS);
352  #endif
353      data_source->sa_family = ctrl_addr->sa_family;
354      socket_set_port (data_source,
355  		     htons(ntohs(socket_get_port(ctrl_addr)) - 1));
356  
357      /* set this here so it can be put in wtmp */
358      snprintf(ttyline, sizeof(ttyline), "ftp%u", (unsigned)getpid());
359  
360  
361      /*	freopen(_PATH_DEVNULL, "w", stderr); */
362      signal(SIGPIPE, lostconn);
363      signal(SIGCHLD, SIG_IGN);
364  #ifdef SIGURG
365      if (signal(SIGURG, myoob) == SIG_ERR)
366  	syslog(LOG_ERR, "signal: %m");
367  #endif
368  
369      /* Try to handle urgent data inline */
370  #if defined(SO_OOBINLINE) && defined(HAVE_SETSOCKOPT)
371      if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (void *)&on,
372  		   sizeof(on)) < 0)
373  	syslog(LOG_ERR, "setsockopt: %m");
374  #endif
375  
376  #ifdef	F_SETOWN
377      if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
378  	syslog(LOG_ERR, "fcntl F_SETOWN: %m");
379  #endif
380      dolog(his_addr, his_addr_len);
381      /*
382       * Set up default state
383       */
384      data = -1;
385      type = TYPE_A;
386      form = FORM_N;
387      stru = STRU_F;
388      mode = MODE_S;
389      tmpline[0] = '\0';
390  
391      /* If logins are disabled, print out the message. */
392      if(show_file(_PATH_NOLOGIN, 530) == 0) {
393  	reply(530, "System not available.");
394  	exit(0);
395      }
396      show_file(_PATH_FTPWELCOME, 220);
397      /* reply(220,) must follow */
398      gethostname(hostname, sizeof(hostname));
399  
400      reply(220, "%s FTP server (%s"
401  #ifdef KRB5
402  	  "+%s"
403  #endif
404  	  ") ready.", hostname, version
405  #ifdef KRB5
406  	  ,heimdal_version
407  #endif
408  	  );
409  
410      for (;;)
411  	yyparse();
412      /* NOTREACHED */
413  }
414  
415  static RETSIGTYPE
lostconn(int signo)416  lostconn(int signo)
417  {
418  
419  	if (debug)
420  		syslog(LOG_DEBUG, "lost connection");
421  	dologout(-1);
422  }
423  
424  /*
425   * Helper function for sgetpwnam().
426   */
427  static char *
sgetsave(char * s)428  sgetsave(char *s)
429  {
430  	char *new = strdup(s);
431  
432  	if (new == NULL) {
433  		perror_reply(421, "Local resource failure: malloc");
434  		dologout(1);
435  		/* NOTREACHED */
436  	}
437  	return new;
438  }
439  
440  /*
441   * Save the result of a getpwnam.  Used for USER command, since
442   * the data returned must not be clobbered by any other command
443   * (e.g., globbing).
444   */
445  static struct passwd *
sgetpwnam(char * name)446  sgetpwnam(char *name)
447  {
448  	static struct passwd save;
449  	struct passwd *p;
450  
451  	if ((p = k_getpwnam(name)) == NULL)
452  		return (p);
453  	if (save.pw_name) {
454  		free(save.pw_name);
455  		free(save.pw_passwd);
456  		free(save.pw_gecos);
457  		free(save.pw_dir);
458  		free(save.pw_shell);
459  	}
460  	save = *p;
461  	save.pw_name = sgetsave(p->pw_name);
462  	save.pw_passwd = sgetsave(p->pw_passwd);
463  	save.pw_gecos = sgetsave(p->pw_gecos);
464  	save.pw_dir = sgetsave(p->pw_dir);
465  	save.pw_shell = sgetsave(p->pw_shell);
466  	return (&save);
467  }
468  
469  static int login_attempts;	/* number of failed login attempts */
470  static int askpasswd;		/* had user command, ask for passwd */
471  static char curname[10];	/* current USER name */
472  #ifdef OTP
473  OtpContext otp_ctx;
474  #endif
475  
476  /*
477   * USER command.
478   * Sets global passwd pointer pw if named account exists and is acceptable;
479   * sets askpasswd if a PASS command is expected.  If logged in previously,
480   * need to reset state.  If name is "ftp" or "anonymous", the name is not in
481   * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
482   * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
483   * requesting login privileges.  Disallow anyone who does not have a standard
484   * shell as returned by getusershell().  Disallow anyone mentioned in the file
485   * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
486   */
487  void
user(char * name)488  user(char *name)
489  {
490  	char *cp, *shell;
491  
492  	if(auth_level == 0 && !sec_complete){
493  	    reply(530, "No login allowed without authorization.");
494  	    return;
495  	}
496  
497  	if (logged_in) {
498  		if (guest) {
499  			reply(530, "Can't change user from guest login.");
500  			return;
501  		} else if (dochroot) {
502  			reply(530, "Can't change user from chroot user.");
503  			return;
504  		}
505  		end_login();
506  	}
507  
508  	guest = 0;
509  	if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
510  	    if ((auth_level & AUTH_FTP) == 0 ||
511  		checkaccess("ftp") ||
512  		checkaccess("anonymous"))
513  		reply(530, "User %s access denied.", name);
514  	    else if ((pw = sgetpwnam("ftp")) != NULL) {
515  		guest = 1;
516  		defumask = guest_umask;	/* paranoia for incoming */
517  		askpasswd = 1;
518  		reply(331, "Guest login ok, type your name as password.");
519  	    } else
520  		reply(530, "User %s unknown.", name);
521  	    if (!askpasswd && logging) {
522  		char data_addr[256];
523  
524  		if (inet_ntop (his_addr->sa_family,
525  			       socket_get_address(his_addr),
526  			       data_addr, sizeof(data_addr)) == NULL)
527  			strlcpy (data_addr, "unknown address",
528  					 sizeof(data_addr));
529  
530  		syslog(LOG_NOTICE,
531  		       "ANONYMOUS FTP LOGIN REFUSED FROM %s(%s)",
532  		       remotehost, data_addr);
533  	    }
534  	    return;
535  	}
536  	if((auth_level & AUTH_PLAIN) == 0 && !sec_complete){
537  	    reply(530, "Only authorized and anonymous login allowed.");
538  	    return;
539  	}
540  	if ((pw = sgetpwnam(name))) {
541  		if ((shell = pw->pw_shell) == NULL || *shell == 0)
542  			shell = _PATH_BSHELL;
543  		while ((cp = getusershell()) != NULL)
544  			if (strcmp(cp, shell) == 0)
545  				break;
546  		endusershell();
547  
548  		if (cp == NULL || checkaccess(name)) {
549  			reply(530, "User %s access denied.", name);
550  			if (logging) {
551  				char data_addr[256];
552  
553  				if (inet_ntop (his_addr->sa_family,
554  					       socket_get_address(his_addr),
555  					       data_addr,
556  					       sizeof(data_addr)) == NULL)
557  					strlcpy (data_addr,
558  							 "unknown address",
559  							 sizeof(data_addr));
560  
561  				syslog(LOG_NOTICE,
562  				       "FTP LOGIN REFUSED FROM %s(%s), %s",
563  				       remotehost,
564  				       data_addr,
565  				       name);
566  			}
567  			pw = (struct passwd *) NULL;
568  			return;
569  		}
570  	}
571  	if (logging)
572  	    strlcpy(curname, name, sizeof(curname));
573  	if(sec_complete) {
574  	    if(sec_userok(name) == 0) {
575  		do_login(232, name);
576  		sec_session(name);
577  	    } else
578  		reply(530, "User %s access denied.", name);
579  	} else {
580  #ifdef OTP
581  		char ss[256];
582  
583  		if (otp_challenge(&otp_ctx, name, ss, sizeof(ss)) == 0) {
584  			reply(331, "Password %s for %s required.",
585  			      ss, name);
586  			askpasswd = 1;
587  		} else
588  #endif
589  		if ((auth_level & AUTH_OTP) == 0) {
590  		    reply(331, "Password required for %s.", name);
591  		    askpasswd = 1;
592  		} else {
593  #ifdef OTP
594  		    char *s;
595  
596  		    if ((s = otp_error (&otp_ctx)) != NULL)
597  			lreply(530, "OTP: %s", s);
598  #endif
599  		    reply(530,
600  			  "Only authorized, anonymous"
601  #ifdef OTP
602  			  " and OTP "
603  #endif
604  			  "login allowed.");
605  		}
606  
607  	}
608  	/*
609  	 * Delay before reading passwd after first failed
610  	 * attempt to slow down passwd-guessing programs.
611  	 */
612  	if (login_attempts)
613  		sleep(login_attempts);
614  }
615  
616  /*
617   * Check if a user is in the file "fname"
618   */
619  static int
checkuser(char * fname,char * name)620  checkuser(char *fname, char *name)
621  {
622  	FILE *fd;
623  	int found = 0;
624  	char *p, line[BUFSIZ];
625  
626  	if ((fd = fopen(fname, "r")) != NULL) {
627  		while (fgets(line, sizeof(line), fd) != NULL)
628  			if ((p = strchr(line, '\n')) != NULL) {
629  				*p = '\0';
630  				if (line[0] == '#')
631  					continue;
632  				if (strcmp(line, name) == 0) {
633  					found = 1;
634  					break;
635  				}
636  			}
637  		fclose(fd);
638  	}
639  	return (found);
640  }
641  
642  
643  /*
644   * Determine whether a user has access, based on information in
645   * _PATH_FTPUSERS. The users are listed one per line, with `allow'
646   * or `deny' after the username. If anything other than `allow', or
647   * just nothing, is given after the username, `deny' is assumed.
648   *
649   * If the user is not found in the file, but the pseudo-user `*' is,
650   * the permission is taken from that line.
651   *
652   * This preserves the old semantics where if a user was listed in the
653   * file he was denied, otherwise he was allowed.
654   *
655   * Return 1 if the user is denied, or 0 if he is allowed.  */
656  
657  static int
match(const char * pattern,const char * string)658  match(const char *pattern, const char *string)
659  {
660      return fnmatch(pattern, string, FNM_NOESCAPE);
661  }
662  
663  static int
checkaccess(char * name)664  checkaccess(char *name)
665  {
666  #define ALLOWED		0
667  #define	NOT_ALLOWED	1
668      FILE *fd;
669      int allowed = ALLOWED;
670      char *user, *perm, line[BUFSIZ];
671      char *foo;
672  
673      fd = fopen(_PATH_FTPUSERS, "r");
674  
675      if(fd == NULL)
676  	return allowed;
677  
678      while (fgets(line, sizeof(line), fd) != NULL)  {
679  	foo = NULL;
680  	user = strtok_r(line, " \t\n", &foo);
681  	if (user == NULL || user[0] == '#')
682  	    continue;
683  	perm = strtok_r(NULL, " \t\n", &foo);
684  	if (match(user, name) == 0){
685  	    if(perm && strcmp(perm, "allow") == 0)
686  		allowed = ALLOWED;
687  	    else
688  		allowed = NOT_ALLOWED;
689  	    break;
690  	}
691      }
692      fclose(fd);
693      return allowed;
694  }
695  #undef	ALLOWED
696  #undef	NOT_ALLOWED
697  
698  
do_login(int code,char * passwd)699  int do_login(int code, char *passwd)
700  {
701      login_attempts = 0;		/* this time successful */
702      if (setegid((gid_t)pw->pw_gid) < 0) {
703  	reply(550, "Can't set gid.");
704  	return -1;
705      }
706      initgroups(pw->pw_name, pw->pw_gid);
707  #if defined(KRB5)
708      if(k_hasafs())
709  	k_setpag();
710  #endif
711  
712      /* open wtmp before chroot */
713      ftpd_logwtmp(ttyline, pw->pw_name, remotehost);
714      logged_in = 1;
715  
716      dochroot = checkuser(_PATH_FTPCHROOT, pw->pw_name);
717      if (guest) {
718  	/*
719  	 * We MUST do a chdir() after the chroot. Otherwise
720  	 * the old current directory will be accessible as "."
721  	 * outside the new root!
722  	 */
723  	if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
724  	    reply(550, "Can't set guest privileges.");
725  	    return -1;
726  	}
727      } else if (dochroot) {
728  	if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
729  	    reply(550, "Can't change root.");
730  	    return -1;
731  	}
732      } else if (chdir(pw->pw_dir) < 0) {
733  	if (chdir("/") < 0) {
734  	    reply(530, "User %s: can't change directory to %s.",
735  		  pw->pw_name, pw->pw_dir);
736  	    return -1;
737  	} else
738  	    lreply(code, "No directory! Logging in with home=/");
739      }
740      if (seteuid((uid_t)pw->pw_uid) < 0) {
741  	reply(550, "Can't set uid.");
742  	return -1;
743      }
744  
745      if(use_builtin_ls == -1) {
746  	struct stat st;
747  	/* if /bin/ls exist and is a regular file, use it, otherwise
748             use built-in ls */
749  	if(stat("/bin/ls", &st) == 0 &&
750  	   S_ISREG(st.st_mode))
751  	    use_builtin_ls = 0;
752  	else
753  	    use_builtin_ls = 1;
754      }
755  
756      /*
757       * Display a login message, if it exists.
758       * N.B. reply(code,) must follow the message.
759       */
760      show_file(_PATH_FTPLOGINMESG, code);
761      if(show_file(_PATH_ISSUE_NET, code) != 0)
762  	show_file(_PATH_ISSUE, code);
763      if (guest) {
764  	reply(code, "Guest login ok, access restrictions apply.");
765  #ifdef HAVE_SETPROCTITLE
766  	snprintf (proctitle, sizeof(proctitle),
767  		  "%s: anonymous/%s",
768  		  remotehost,
769  		  passwd);
770  	setproctitle("%s", proctitle);
771  #endif /* HAVE_SETPROCTITLE */
772  	if (logging) {
773  	    char data_addr[256];
774  
775  	    if (inet_ntop (his_addr->sa_family,
776  			   socket_get_address(his_addr),
777  			   data_addr, sizeof(data_addr)) == NULL)
778  		strlcpy (data_addr, "unknown address",
779  				 sizeof(data_addr));
780  
781  	    syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s",
782  		   remotehost,
783  		   data_addr,
784  		   passwd);
785  	}
786      } else {
787  	reply(code, "User %s logged in.", pw->pw_name);
788  #ifdef HAVE_SETPROCTITLE
789  	snprintf(proctitle, sizeof(proctitle), "%s: %s", remotehost, pw->pw_name);
790  	setproctitle("%s", proctitle);
791  #endif /* HAVE_SETPROCTITLE */
792  	if (logging) {
793  	    char data_addr[256];
794  
795  	    if (inet_ntop (his_addr->sa_family,
796  			   socket_get_address(his_addr),
797  			   data_addr, sizeof(data_addr)) == NULL)
798  		strlcpy (data_addr, "unknown address",
799  				 sizeof(data_addr));
800  
801  	    syslog(LOG_INFO, "FTP LOGIN FROM %s(%s) as %s",
802  		   remotehost,
803  		   data_addr,
804  		   pw->pw_name);
805  	}
806      }
807      umask(defumask);
808      return 0;
809  }
810  
811  /*
812   * Terminate login as previous user, if any, resetting state;
813   * used when USER command is given or login fails.
814   */
815  static void
end_login(void)816  end_login(void)
817  {
818  
819  	if (seteuid((uid_t)0) < 0)
820  		fatal("Failed to seteuid");
821  	if (logged_in)
822  		ftpd_logwtmp(ttyline, "", "");
823  	pw = NULL;
824  	logged_in = 0;
825  	guest = 0;
826  	dochroot = 0;
827  }
828  
829  #ifdef KRB5
830  static int
krb5_verify(struct passwd * pwd,char * passwd)831  krb5_verify(struct passwd *pwd, char *passwd)
832  {
833     krb5_context context;
834     krb5_ccache  id;
835     krb5_principal princ;
836     krb5_error_code ret;
837  
838     ret = krb5_init_context(&context);
839     if(ret)
840          return ret;
841  
842    ret = krb5_parse_name(context, pwd->pw_name, &princ);
843    if(ret){
844          krb5_free_context(context);
845          return ret;
846    }
847    ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id);
848    if(ret){
849          krb5_free_principal(context, princ);
850          krb5_free_context(context);
851          return ret;
852    }
853    ret = krb5_verify_user(context,
854                           princ,
855                           id,
856                           passwd,
857                           1,
858                           NULL);
859    krb5_free_principal(context, princ);
860    if (k_hasafs()) {
861        krb5_afslog_uid_home(context, id,NULL, NULL,pwd->pw_uid, pwd->pw_dir);
862    }
863    krb5_cc_destroy(context, id);
864    krb5_free_context (context);
865    if(ret)
866        return ret;
867    return 0;
868  }
869  #endif /* KRB5 */
870  
871  void
pass(char * passwd)872  pass(char *passwd)
873  {
874  	int rval;
875  
876  	/* some clients insists on sending a password */
877  	if (logged_in && askpasswd == 0){
878  	    reply(230, "Password not necessary");
879  	    return;
880  	}
881  
882  	if (logged_in || askpasswd == 0) {
883  		reply(503, "Login with USER first.");
884  		return;
885  	}
886  	askpasswd = 0;
887  	rval = 1;
888  	if (!guest) {		/* "ftp" is only account allowed no password */
889  		if (pw == NULL)
890  			rval = 1;	/* failure below */
891  #ifdef OTP
892  		else if (otp_verify_user (&otp_ctx, passwd) == 0) {
893  		    rval = 0;
894  		}
895  #endif
896  		else if((auth_level & AUTH_OTP) == 0) {
897  #ifdef KRB5
898  		    rval = krb5_verify(pw, passwd);
899  #endif
900  		    if (rval)
901  			rval = unix_verify_user(pw->pw_name, passwd);
902  		} else {
903  #ifdef OTP
904  		    char *s;
905  		    if ((s = otp_error(&otp_ctx)) != NULL)
906  			lreply(530, "OTP: %s", s);
907  #endif
908  		}
909  		memset (passwd, 0, strlen(passwd));
910  
911  		/*
912  		 * If rval == 1, the user failed the authentication
913  		 * check above.  If rval == 0, either Kerberos or
914  		 * local authentication succeeded.
915  		 */
916  		if (rval) {
917  			char data_addr[256];
918  
919  			if (inet_ntop (his_addr->sa_family,
920  				       socket_get_address(his_addr),
921  				       data_addr, sizeof(data_addr)) == NULL)
922  				strlcpy (data_addr, "unknown address",
923  						 sizeof(data_addr));
924  
925  			reply(530, "Login incorrect.");
926  			if (logging)
927  				syslog(LOG_NOTICE,
928  				    "FTP LOGIN FAILED FROM %s(%s), %s",
929  				       remotehost,
930  				       data_addr,
931  				       curname);
932  			pw = NULL;
933  			if (login_attempts++ >= 5) {
934  				syslog(LOG_NOTICE,
935  				       "repeated login failures from %s(%s)",
936  				       remotehost,
937  				       data_addr);
938  				exit(0);
939  			}
940  			return;
941  		}
942  	}
943  	if(!do_login(230, passwd))
944  	  return;
945  
946  	/* Forget all about it... */
947  	end_login();
948  }
949  
950  void
retrieve(const char * cmd,char * name)951  retrieve(const char *cmd, char *name)
952  {
953  	FILE *fin = NULL, *dout;
954  	struct stat st;
955  	int (*closefunc) (FILE *);
956  	char line[BUFSIZ];
957  
958  
959  	if (cmd == 0) {
960  		fin = fopen(name, "r");
961  		closefunc = fclose;
962  		st.st_size = 0;
963  		if(fin == NULL){
964  		    int save_errno = errno;
965  		    struct cmds {
966  			const char *ext;
967  			const char *cmd;
968  		        const char *rev_cmd;
969  		    } cmds[] = {
970  			{".tar", "/bin/gtar cPf - %s", NULL},
971  			{".tar.gz", "/bin/gtar zcPf - %s", NULL},
972  			{".tar.Z", "/bin/gtar ZcPf - %s", NULL},
973  			{".gz", "/bin/gzip -c -- %s", "/bin/gzip -c -d -- %s"},
974  			{".Z", "/bin/compress -c -- %s", "/bin/uncompress -c -- %s"},
975  			{NULL, NULL}
976  		    };
977  		    struct cmds *p;
978  		    for(p = cmds; p->ext; p++){
979  			char *tail = name + strlen(name) - strlen(p->ext);
980  			char c = *tail;
981  
982  			if(strcmp(tail, p->ext) == 0 &&
983  			   (*tail  = 0) == 0 &&
984  			   access(name, R_OK) == 0){
985  			    snprintf (line, sizeof(line), p->cmd, name);
986  			    *tail  = c;
987  			    break;
988  			}
989  			*tail = c;
990  			if (p->rev_cmd != NULL) {
991  			    char *ext;
992  			    int ret;
993  
994  			    ret = asprintf(&ext, "%s%s", name, p->ext);
995  			    if (ret != -1) {
996    			        if (access(ext, R_OK) == 0) {
997  				    snprintf (line, sizeof(line),
998  					      p->rev_cmd, ext);
999  				    free(ext);
1000  				    break;
1001  				}
1002  			        free(ext);
1003  			    }
1004  			}
1005  
1006  		    }
1007  		    if(p->ext){
1008  			fin = ftpd_popen(line, "r", 0, 0);
1009  			closefunc = ftpd_pclose;
1010  			st.st_size = -1;
1011  			cmd = line;
1012  		    } else
1013  			errno = save_errno;
1014  		}
1015  	} else {
1016  		snprintf(line, sizeof(line), cmd, name);
1017  		name = line;
1018  		fin = ftpd_popen(line, "r", 1, 0);
1019  		closefunc = ftpd_pclose;
1020  		st.st_size = -1;
1021  	}
1022  	if (fin == NULL) {
1023  		if (errno != 0) {
1024  			perror_reply(550, name);
1025  			if (cmd == 0) {
1026  				LOGCMD("get", name);
1027  			}
1028  		}
1029  		return;
1030  	}
1031  	byte_count = -1;
1032  	if (cmd == 0){
1033  	    if(fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
1034  		reply(550, "%s: not a plain file.", name);
1035  		goto done;
1036  	    }
1037  	}
1038  	if (restart_point) {
1039  		if (type == TYPE_A) {
1040  			off_t i, n;
1041  			int c;
1042  
1043  			n = restart_point;
1044  			i = 0;
1045  			while (i++ < n) {
1046  				if ((c=getc(fin)) == EOF) {
1047  					perror_reply(550, name);
1048  					goto done;
1049  				}
1050  				if (c == '\n')
1051  					i++;
1052  			}
1053  		} else if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
1054  			perror_reply(550, name);
1055  			goto done;
1056  		}
1057  	}
1058  	dout = dataconn(name, st.st_size, "w");
1059  	if (dout == NULL)
1060  		goto done;
1061  	set_buffer_size(fileno(dout), 0);
1062  	send_data(fin, dout);
1063  	fclose(dout);
1064  	data = -1;
1065  	pdata = -1;
1066  done:
1067  	if (cmd == 0)
1068  		LOGBYTES("get", name, byte_count);
1069  	(*closefunc)(fin);
1070  }
1071  
1072  /* filename sanity check */
1073  
1074  int
filename_check(char * filename)1075  filename_check(char *filename)
1076  {
1077      char *p;
1078  
1079      p = strrchr(filename, '/');
1080      if(p)
1081  	filename = p + 1;
1082  
1083      p = filename;
1084  
1085      if(isalnum((unsigned char)*p)){
1086  	p++;
1087  	while(*p && (isalnum((unsigned char)*p) || strchr(good_chars, (unsigned char)*p)))
1088  	    p++;
1089  	if(*p == '\0')
1090  	    return 0;
1091      }
1092      lreply(553, "\"%s\" is not an acceptable filename.", filename);
1093      lreply(553, "The filename must start with an alphanumeric "
1094  	   "character and must only");
1095      reply(553, "consist of alphanumeric characters or any of the following: %s",
1096  	  good_chars);
1097      return 1;
1098  }
1099  
1100  void
do_store(char * name,char * mode,int unique)1101  do_store(char *name, char *mode, int unique)
1102  {
1103  	FILE *fout, *din;
1104  	struct stat st;
1105  	int (*closefunc) (FILE *);
1106  
1107  	if(guest && filename_check(name))
1108  	    return;
1109  	if (unique) {
1110  	    char *uname;
1111  	    if (stat(name, &st) == 0) {
1112  		if ((uname = gunique(name)) == NULL)
1113  		    return;
1114  		name = uname;
1115  	    }
1116  	    LOGCMD(*mode == 'w' ? "put" : "append", name);
1117  	}
1118  
1119  	if (restart_point)
1120  		mode = "r+";
1121  	fout = fopen(name, mode);
1122  	closefunc = fclose;
1123  	if (fout == NULL) {
1124  		perror_reply(553, name);
1125  		LOGCMD(*mode == 'w' ? "put" : "append", name);
1126  		return;
1127  	}
1128  	byte_count = -1;
1129  	if (restart_point) {
1130  		if (type == TYPE_A) {
1131  			off_t i, n;
1132  			int c;
1133  
1134  			n = restart_point;
1135  			i = 0;
1136  			while (i++ < n) {
1137  				if ((c=getc(fout)) == EOF) {
1138  					perror_reply(550, name);
1139  					goto done;
1140  				}
1141  				if (c == '\n')
1142  					i++;
1143  			}
1144  			/*
1145  			 * We must do this seek to "current" position
1146  			 * because we are changing from reading to
1147  			 * writing.
1148  			 */
1149  			if (fseek(fout, 0L, SEEK_CUR) < 0) {
1150  				perror_reply(550, name);
1151  				goto done;
1152  			}
1153  		} else if (lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1154  			perror_reply(550, name);
1155  			goto done;
1156  		}
1157  	}
1158  	din = dataconn(name, (off_t)-1, "r");
1159  	if (din == NULL)
1160  		goto done;
1161  	set_buffer_size(fileno(din), 1);
1162  	if (receive_data(din, fout) == 0) {
1163  	    if((*closefunc)(fout) < 0)
1164  		perror_reply(552, name);
1165  	    else {
1166  		if (unique)
1167  			reply(226, "Transfer complete (unique file name:%s).",
1168  			    name);
1169  		else
1170  			reply(226, "Transfer complete.");
1171  	    }
1172  	} else
1173  	    (*closefunc)(fout);
1174  	fclose(din);
1175  	data = -1;
1176  	pdata = -1;
1177  done:
1178  	LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
1179  }
1180  
1181  static FILE *
getdatasock(const char * mode,int domain)1182  getdatasock(const char *mode, int domain)
1183  {
1184  	int s, t, tries;
1185  
1186  	if (data >= 0)
1187  		return (fdopen(data, mode));
1188  	if (seteuid(0) < 0)
1189  		fatal("Failed to seteuid");
1190  	s = socket(domain, SOCK_STREAM, 0);
1191  	if (s < 0)
1192  		goto bad;
1193  	socket_set_reuseaddr (s, 1);
1194  	/* anchor socket to avoid multi-homing problems */
1195  	socket_set_address_and_port (data_source,
1196  				     socket_get_address (ctrl_addr),
1197  				     socket_get_port (data_source));
1198  
1199  	for (tries = 1; ; tries++) {
1200  		if (bind(s, data_source,
1201  			 socket_sockaddr_size (data_source)) >= 0)
1202  			break;
1203  		if (errno != EADDRINUSE || tries > 10)
1204  			goto bad;
1205  		sleep(tries);
1206  	}
1207  	if (seteuid(pw->pw_uid) < 0)
1208  		fatal("Failed to seteuid");
1209  #ifdef IPTOS_THROUGHPUT
1210  	socket_set_tos (s, IPTOS_THROUGHPUT);
1211  #endif
1212  	return (fdopen(s, mode));
1213  bad:
1214  	/* Return the real value of errno (close may change it) */
1215  	t = errno;
1216  	if (seteuid((uid_t)pw->pw_uid) < 0)
1217  		fatal("Failed to seteuid");
1218  	close(s);
1219  	errno = t;
1220  	return (NULL);
1221  }
1222  
1223  static int
accept_with_timeout(int socket,struct sockaddr * address,socklen_t * address_len,struct timeval * timeout)1224  accept_with_timeout(int socket,
1225  		    struct sockaddr *address,
1226  		    socklen_t *address_len,
1227  		    struct timeval *timeout)
1228  {
1229      int ret;
1230      fd_set rfd;
1231      FD_ZERO(&rfd);
1232      FD_SET(socket, &rfd);
1233      ret = select(socket + 1, &rfd, NULL, NULL, timeout);
1234      if(ret < 0)
1235  	return ret;
1236      if(ret == 0) {
1237  	errno = ETIMEDOUT;
1238  	return -1;
1239      }
1240      return accept(socket, address, address_len);
1241  }
1242  
1243  static FILE *
dataconn(const char * name,off_t size,const char * mode)1244  dataconn(const char *name, off_t size, const char *mode)
1245  {
1246  	char sizebuf[32];
1247  	FILE *file;
1248  	int domain, retry = 0;
1249  
1250  	file_size = size;
1251  	byte_count = 0;
1252  	if (size >= 0)
1253  	    snprintf(sizebuf, sizeof(sizebuf), " (%ld bytes)", (long)size);
1254  	else
1255  	    *sizebuf = '\0';
1256  	if (pdata >= 0) {
1257  		struct sockaddr_storage from_ss;
1258  		struct sockaddr *from = (struct sockaddr *)&from_ss;
1259  		struct timeval timeout;
1260  		int s;
1261  		socklen_t fromlen = sizeof(from_ss);
1262  
1263  		timeout.tv_sec = 15;
1264  		timeout.tv_usec = 0;
1265  		s = accept_with_timeout(pdata, from, &fromlen, &timeout);
1266  		if (s < 0) {
1267  			reply(425, "Can't open data connection.");
1268  			close(pdata);
1269  			pdata = -1;
1270  			return (NULL);
1271  		}
1272  		close(pdata);
1273  		pdata = s;
1274  #if defined(IPTOS_THROUGHPUT)
1275  		if (from->sa_family == AF_INET)
1276  		    socket_set_tos(s, IPTOS_THROUGHPUT);
1277  #endif
1278  		reply(150, "Opening %s mode data connection for '%s'%s.",
1279  		     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1280  		return (fdopen(pdata, mode));
1281  	}
1282  	if (data >= 0) {
1283  		reply(125, "Using existing data connection for '%s'%s.",
1284  		    name, sizebuf);
1285  		usedefault = 1;
1286  		return (fdopen(data, mode));
1287  	}
1288  	if (usedefault)
1289  		data_dest = his_addr;
1290  	usedefault = 1;
1291  	/*
1292  	 * Default to using the same socket type as the ctrl address,
1293  	 * unless we know the type of the data address.
1294  	 */
1295  	domain = data_dest->sa_family;
1296  	if (domain == PF_UNSPEC)
1297  	    domain = ctrl_addr->sa_family;
1298  
1299  	file = getdatasock(mode, domain);
1300  	if (file == NULL) {
1301  		char data_addr[256];
1302  
1303  		if (inet_ntop (data_source->sa_family,
1304  			       socket_get_address(data_source),
1305  			       data_addr, sizeof(data_addr)) == NULL)
1306  			strlcpy (data_addr, "unknown address",
1307  					 sizeof(data_addr));
1308  
1309  		reply(425, "Can't create data socket (%s,%d): %s.",
1310  		      data_addr,
1311  		      socket_get_port (data_source),
1312  		      strerror(errno));
1313  		return (NULL);
1314  	}
1315  	data = fileno(file);
1316  	while (connect(data, data_dest,
1317  		       socket_sockaddr_size(data_dest)) < 0) {
1318  		if (errno == EADDRINUSE && retry < swaitmax) {
1319  			sleep(swaitint);
1320  			retry += swaitint;
1321  			continue;
1322  		}
1323  		perror_reply(425, "Can't build data connection");
1324  		fclose(file);
1325  		data = -1;
1326  		return (NULL);
1327  	}
1328  	reply(150, "Opening %s mode data connection for '%s'%s.",
1329  	     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
1330  	return (file);
1331  }
1332  
1333  /*
1334   * Tranfer the contents of "instr" to "outstr" peer using the appropriate
1335   * encapsulation of the data subject * to Mode, Structure, and Type.
1336   *
1337   * NB: Form isn't handled.
1338   */
1339  static void
send_data(FILE * instr,FILE * outstr)1340  send_data(FILE *instr, FILE *outstr)
1341  {
1342  	int c, cnt, filefd, netfd;
1343  	static char *buf;
1344  	static size_t bufsize;
1345  
1346  	transflag = 1;
1347  	switch (type) {
1348  
1349  	case TYPE_A:
1350  	    while ((c = getc(instr)) != EOF) {
1351  		if (urgflag && handleoobcmd())
1352  		    return;
1353  		byte_count++;
1354  		if(c == '\n')
1355  		    sec_putc('\r', outstr);
1356  		sec_putc(c, outstr);
1357  	    }
1358  	    sec_fflush(outstr);
1359  	    transflag = 0;
1360  	    urgflag = 0;
1361  	    if (ferror(instr))
1362  		goto file_err;
1363  	    if (ferror(outstr))
1364  		goto data_err;
1365  	    reply(226, "Transfer complete.");
1366  	    return;
1367  
1368  	case TYPE_I:
1369  	case TYPE_L:
1370  #if 0 /* XXX handle urg flag */
1371  #if defined(HAVE_MMAP) && !defined(NO_MMAP)
1372  #ifndef MAP_FAILED
1373  #define MAP_FAILED (-1)
1374  #endif
1375  	    {
1376  		struct stat st;
1377  		char *chunk;
1378  		int in = fileno(instr);
1379  		if(fstat(in, &st) == 0 && S_ISREG(st.st_mode)
1380  		   && st.st_size > 0) {
1381  		    /*
1382  		     * mmap zero bytes has potential of loosing, don't do it.
1383  		     */
1384  		    chunk = mmap(0, st.st_size, PROT_READ,
1385  				 MAP_SHARED, in, 0);
1386  		    if((void *)chunk != (void *)MAP_FAILED) {
1387  			cnt = st.st_size - restart_point;
1388  			sec_write(fileno(outstr), chunk + restart_point, cnt);
1389  			if (munmap(chunk, st.st_size) < 0)
1390  			    warn ("munmap");
1391  			sec_fflush(outstr);
1392  			byte_count = cnt;
1393  			transflag = 0;
1394  			urgflag = 0;
1395  		    }
1396  		}
1397  	    }
1398  #endif
1399  #endif
1400  	if(transflag) {
1401  	    struct stat st;
1402  
1403  	    netfd = fileno(outstr);
1404  	    filefd = fileno(instr);
1405  	    buf = alloc_buffer (buf, &bufsize,
1406  				fstat(filefd, &st) >= 0 ? &st : NULL);
1407  	    if (buf == NULL) {
1408  		transflag = 0;
1409  		urgflag = 0;
1410  		perror_reply(451, "Local resource failure: malloc");
1411  		return;
1412  	    }
1413  	    while ((cnt = read(filefd, buf, bufsize)) > 0 &&
1414  		   sec_write(netfd, buf, cnt) == cnt) {
1415  		byte_count += cnt;
1416  		if (urgflag && handleoobcmd())
1417  		    return;
1418  	    }
1419  	    sec_fflush(outstr); /* to end an encrypted stream */
1420  	    transflag = 0;
1421  	    urgflag = 0;
1422  	    if (cnt != 0) {
1423  		if (cnt < 0)
1424  		    goto file_err;
1425  		goto data_err;
1426  	    }
1427  	}
1428  	reply(226, "Transfer complete.");
1429  	return;
1430  	default:
1431  	    transflag = 0;
1432  	    urgflag = 0;
1433  	    reply(550, "Unimplemented TYPE %d in send_data", type);
1434  	    return;
1435  	}
1436  
1437  data_err:
1438  	transflag = 0;
1439  	urgflag = 0;
1440  	perror_reply(426, "Data connection");
1441  	return;
1442  
1443  file_err:
1444  	transflag = 0;
1445  	urgflag = 0;
1446  	perror_reply(551, "Error on input file");
1447  }
1448  
1449  /*
1450   * Transfer data from peer to "outstr" using the appropriate encapulation of
1451   * the data subject to Mode, Structure, and Type.
1452   *
1453   * N.B.: Form isn't handled.
1454   */
1455  static int
receive_data(FILE * instr,FILE * outstr)1456  receive_data(FILE *instr, FILE *outstr)
1457  {
1458      int cnt, bare_lfs = 0;
1459      static char *buf;
1460      static size_t bufsize;
1461      struct stat st;
1462  
1463      transflag = 1;
1464  
1465      buf = alloc_buffer (buf, &bufsize,
1466  			fstat(fileno(outstr), &st) >= 0 ? &st : NULL);
1467      if (buf == NULL) {
1468  	transflag = 0;
1469  	urgflag = 0;
1470  	perror_reply(451, "Local resource failure: malloc");
1471  	return -1;
1472      }
1473  
1474      switch (type) {
1475  
1476      case TYPE_I:
1477      case TYPE_L:
1478  	while ((cnt = sec_read(fileno(instr), buf, bufsize)) > 0) {
1479  	    if (write(fileno(outstr), buf, cnt) != cnt)
1480  		goto file_err;
1481  	    byte_count += cnt;
1482  	    if (urgflag && handleoobcmd())
1483  		return (-1);
1484  	}
1485  	if (cnt < 0)
1486  	    goto data_err;
1487  	transflag = 0;
1488  	urgflag = 0;
1489  	return (0);
1490  
1491      case TYPE_E:
1492  	reply(553, "TYPE E not implemented.");
1493  	transflag = 0;
1494  	urgflag = 0;
1495  	return (-1);
1496  
1497      case TYPE_A:
1498      {
1499  	char *p, *q;
1500  	int cr_flag = 0;
1501  	while ((cnt = sec_read(fileno(instr),
1502  				buf + cr_flag,
1503  				bufsize - cr_flag)) > 0){
1504  	    if (urgflag && handleoobcmd())
1505  		return (-1);
1506  	    byte_count += cnt;
1507  	    cnt += cr_flag;
1508  	    cr_flag = 0;
1509  	    for(p = buf, q = buf; p < buf + cnt;) {
1510  		if(*p == '\n')
1511  		    bare_lfs++;
1512  		if(*p == '\r') {
1513  		    if(p == buf + cnt - 1){
1514  			cr_flag = 1;
1515  			p++;
1516  			continue;
1517  		    }else if(p[1] == '\n'){
1518  			*q++ = '\n';
1519  			p += 2;
1520  			continue;
1521  		    }
1522  		}
1523  		*q++ = *p++;
1524  	    }
1525  	    fwrite(buf, q - buf, 1, outstr);
1526  	    if(cr_flag)
1527  		buf[0] = '\r';
1528  	}
1529  	if(cr_flag)
1530  	    putc('\r', outstr);
1531  	fflush(outstr);
1532  	if (ferror(instr))
1533  	    goto data_err;
1534  	if (ferror(outstr))
1535  	    goto file_err;
1536  	transflag = 0;
1537  	urgflag = 0;
1538  	if (bare_lfs) {
1539  	    lreply(226, "WARNING! %d bare linefeeds received in ASCII mode\r\n"
1540  		   "    File may not have transferred correctly.\r\n",
1541  		   bare_lfs);
1542  	}
1543  	return (0);
1544      }
1545      default:
1546  	reply(550, "Unimplemented TYPE %d in receive_data", type);
1547  	transflag = 0;
1548  	urgflag = 0;
1549  	return (-1);
1550      }
1551  
1552  data_err:
1553      transflag = 0;
1554      urgflag = 0;
1555      perror_reply(426, "Data Connection");
1556      return (-1);
1557  
1558  file_err:
1559      transflag = 0;
1560      urgflag = 0;
1561      perror_reply(452, "Error writing file");
1562      return (-1);
1563  }
1564  
1565  void
statfilecmd(char * filename)1566  statfilecmd(char *filename)
1567  {
1568  	FILE *fin;
1569  	int c;
1570  	char line[LINE_MAX];
1571  
1572  	snprintf(line, sizeof(line), "/bin/ls -la -- %s", filename);
1573  	fin = ftpd_popen(line, "r", 1, 0);
1574  	lreply(211, "status of %s:", filename);
1575  	while ((c = getc(fin)) != EOF) {
1576  		if (c == '\n') {
1577  			if (ferror(stdout)){
1578  				perror_reply(421, "control connection");
1579  				ftpd_pclose(fin);
1580  				dologout(1);
1581  				/* NOTREACHED */
1582  			}
1583  			if (ferror(fin)) {
1584  				perror_reply(551, filename);
1585  				ftpd_pclose(fin);
1586  				return;
1587  			}
1588  			putc('\r', stdout);
1589  		}
1590  		putc(c, stdout);
1591  	}
1592  	ftpd_pclose(fin);
1593  	reply(211, "End of Status");
1594  }
1595  
1596  void
statcmd(void)1597  statcmd(void)
1598  {
1599  #if 0
1600  	struct sockaddr_in *sin;
1601  	u_char *a, *p;
1602  
1603  	lreply(211, "%s FTP server (%s) status:", hostname, version);
1604  	printf("     %s\r\n", version);
1605  	printf("     Connected to %s", remotehost);
1606  	if (!isdigit((unsigned char)remotehost[0]))
1607  		printf(" (%s)", inet_ntoa(his_addr.sin_addr));
1608  	printf("\r\n");
1609  	if (logged_in) {
1610  		if (guest)
1611  			printf("     Logged in anonymously\r\n");
1612  		else
1613  			printf("     Logged in as %s\r\n", pw->pw_name);
1614  	} else if (askpasswd)
1615  		printf("     Waiting for password\r\n");
1616  	else
1617  		printf("     Waiting for user name\r\n");
1618  	printf("     TYPE: %s", typenames[type]);
1619  	if (type == TYPE_A || type == TYPE_E)
1620  		printf(", FORM: %s", formnames[form]);
1621  	if (type == TYPE_L)
1622  #if NBBY == 8
1623  		printf(" %d", NBBY);
1624  #else
1625  		printf(" %d", bytesize);	/* need definition! */
1626  #endif
1627  	printf("; STRUcture: %s; transfer MODE: %s\r\n",
1628  	    strunames[stru], modenames[mode]);
1629  	if (data != -1)
1630  		printf("     Data connection open\r\n");
1631  	else if (pdata != -1) {
1632  		printf("     in Passive mode");
1633  		sin = &pasv_addr;
1634  		goto printaddr;
1635  	} else if (usedefault == 0) {
1636  		printf("     PORT");
1637  		sin = &data_dest;
1638  printaddr:
1639  		a = (u_char *) &sin->sin_addr;
1640  		p = (u_char *) &sin->sin_port;
1641  #define UC(b) (((int) b) & 0xff)
1642  		printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
1643  			UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
1644  #undef UC
1645  	} else
1646  		printf("     No data connection\r\n");
1647  #endif
1648  	reply(211, "End of status");
1649  }
1650  
1651  void
fatal(char * s)1652  fatal(char *s)
1653  {
1654  
1655  	reply(451, "Error in server: %s\n", s);
1656  	reply(221, "Closing connection due to server error.");
1657  	dologout(0);
1658  	/* NOTREACHED */
1659  }
1660  
1661  static void
1662  int_reply(int, char *, const char *, va_list)
1663  #ifdef __GNUC__
1664  __attribute__ ((format (printf, 3, 0)))
1665  #endif
1666  ;
1667  
1668  static void
int_reply(int n,char * c,const char * fmt,va_list ap)1669  int_reply(int n, char *c, const char *fmt, va_list ap)
1670  {
1671      char buf[10240];
1672      char *p;
1673      p=buf;
1674      if(n){
1675  	snprintf(p, sizeof(buf), "%d%s", n, c);
1676  	p+=strlen(p);
1677      }
1678      vsnprintf(p, sizeof(buf) - strlen(p), fmt, ap);
1679      p+=strlen(p);
1680      snprintf(p, sizeof(buf) - strlen(p), "\r\n");
1681      p+=strlen(p);
1682      sec_fprintf(stdout, "%s", buf);
1683      fflush(stdout);
1684      if (debug)
1685  	syslog(LOG_DEBUG, "<--- %s- ", buf);
1686  }
1687  
1688  void
reply(int n,const char * fmt,...)1689  reply(int n, const char *fmt, ...)
1690  {
1691    va_list ap;
1692    va_start(ap, fmt);
1693    int_reply(n, " ", fmt, ap);
1694    delete_ftp_command();
1695    va_end(ap);
1696  }
1697  
1698  void
lreply(int n,const char * fmt,...)1699  lreply(int n, const char *fmt, ...)
1700  {
1701    va_list ap;
1702    va_start(ap, fmt);
1703    int_reply(n, "-", fmt, ap);
1704    va_end(ap);
1705  }
1706  
1707  void
nreply(const char * fmt,...)1708  nreply(const char *fmt, ...)
1709  {
1710    va_list ap;
1711    va_start(ap, fmt);
1712    int_reply(0, NULL, fmt, ap);
1713    va_end(ap);
1714  }
1715  
1716  static void
ack(char * s)1717  ack(char *s)
1718  {
1719  
1720  	reply(250, "%s command successful.", s);
1721  }
1722  
1723  void
nack(char * s)1724  nack(char *s)
1725  {
1726  
1727  	reply(502, "%s command not implemented.", s);
1728  }
1729  
1730  void
do_delete(char * name)1731  do_delete(char *name)
1732  {
1733  	struct stat st;
1734  
1735  	LOGCMD("delete", name);
1736  	if (stat(name, &st) < 0) {
1737  		perror_reply(550, name);
1738  		return;
1739  	}
1740  	if (S_ISDIR(st.st_mode)) {
1741  		if (rmdir(name) < 0) {
1742  			perror_reply(550, name);
1743  			return;
1744  		}
1745  		goto done;
1746  	}
1747  	if (unlink(name) < 0) {
1748  		perror_reply(550, name);
1749  		return;
1750  	}
1751  done:
1752  	ack("DELE");
1753  }
1754  
1755  void
cwd(const char * path)1756  cwd(const char *path)
1757  {
1758  
1759  	if (chdir(path) < 0)
1760  		perror_reply(550, path);
1761  	else
1762  		ack("CWD");
1763  }
1764  
1765  void
makedir(char * name)1766  makedir(char *name)
1767  {
1768  
1769  	LOGCMD("mkdir", name);
1770  	if(guest && filename_check(name))
1771  	    return;
1772  	if (mkdir(name, 0777) < 0)
1773  		perror_reply(550, name);
1774  	else{
1775  	    if(guest)
1776  		chmod(name, 0700); /* guest has umask 777 */
1777  	    reply(257, "MKD command successful.");
1778  	}
1779  }
1780  
1781  void
removedir(char * name)1782  removedir(char *name)
1783  {
1784  
1785  	LOGCMD("rmdir", name);
1786  	if (rmdir(name) < 0)
1787  		perror_reply(550, name);
1788  	else
1789  		ack("RMD");
1790  }
1791  
1792  void
pwd(void)1793  pwd(void)
1794  {
1795      char path[MaxPathLen];
1796      char *ret;
1797  
1798      /* SunOS has a broken getcwd that does popen(pwd) (!!!), this
1799       * failes miserably when running chroot
1800       */
1801      ret = getcwd(path, sizeof(path));
1802      if (ret == NULL)
1803  	reply(550, "%s.", strerror(errno));
1804      else
1805  	reply(257, "\"%s\" is current directory.", path);
1806  }
1807  
1808  char *
renamefrom(char * name)1809  renamefrom(char *name)
1810  {
1811  	struct stat st;
1812  
1813  	if (stat(name, &st) < 0) {
1814  		perror_reply(550, name);
1815  		return NULL;
1816  	}
1817  	reply(350, "File exists, ready for destination name");
1818  	return (name);
1819  }
1820  
1821  void
renamecmd(char * from,char * to)1822  renamecmd(char *from, char *to)
1823  {
1824  
1825  	LOGCMD2("rename", from, to);
1826  	if(guest && filename_check(to))
1827  	    return;
1828  	if (rename(from, to) < 0)
1829  		perror_reply(550, "rename");
1830  	else
1831  		ack("RNTO");
1832  }
1833  
1834  static void
dolog(struct sockaddr * sa,int len)1835  dolog(struct sockaddr *sa, int len)
1836  {
1837  	getnameinfo_verified (sa, len, remotehost, sizeof(remotehost),
1838  			      NULL, 0, 0);
1839  #ifdef HAVE_SETPROCTITLE
1840  	snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
1841  	setproctitle("%s", proctitle);
1842  #endif /* HAVE_SETPROCTITLE */
1843  
1844  	if (logging) {
1845  		char data_addr[256];
1846  
1847  		if (inet_ntop (his_addr->sa_family,
1848  			       socket_get_address(his_addr),
1849  			       data_addr, sizeof(data_addr)) == NULL)
1850  			strlcpy (data_addr, "unknown address",
1851  					 sizeof(data_addr));
1852  
1853  
1854  		syslog(LOG_INFO, "connection from %s(%s)",
1855  		       remotehost,
1856  		       data_addr);
1857  	}
1858  }
1859  
1860  /*
1861   * Record logout in wtmp file
1862   * and exit with supplied status.
1863   */
1864  void
dologout(int status)1865  dologout(int status)
1866  {
1867      transflag = 0;
1868      urgflag = 0;
1869      if (logged_in) {
1870  #if KRB5
1871  	cond_kdestroy();
1872  #endif
1873  	seteuid((uid_t)0); /* No need to check, we call exit() below */
1874  	ftpd_logwtmp(ttyline, "", "");
1875      }
1876      /* beware of flushing buffers after a SIGPIPE */
1877  #ifdef XXX
1878      exit(status);
1879  #else
1880      _exit(status);
1881  #endif
1882  }
1883  
abor(void)1884  void abor(void)
1885  {
1886      if (!transflag)
1887  	return;
1888      reply(426, "Transfer aborted. Data connection closed.");
1889      reply(226, "Abort successful");
1890      transflag = 0;
1891  }
1892  
1893  static void
myoob(int signo)1894  myoob(int signo)
1895  {
1896      urgflag = 1;
1897  }
1898  
1899  static char *
mec_space(char * p)1900  mec_space(char *p)
1901  {
1902      while(isspace(*(unsigned char *)p))
1903  	  p++;
1904      return p;
1905  }
1906  
1907  static int
handleoobcmd(void)1908  handleoobcmd(void)
1909  {
1910  	char *cp;
1911  
1912  	/* only process if transfer occurring */
1913  	if (!transflag)
1914  		return 0;
1915  
1916  	urgflag = 0;
1917  
1918  	cp = tmpline;
1919  	if (ftpd_getline(cp, sizeof(tmpline)) == NULL) {
1920  		reply(221, "You could at least say goodbye.");
1921  		dologout(0);
1922  	}
1923  
1924  	if (strncasecmp("MIC", cp, 3) == 0) {
1925  	    mec(mec_space(cp + 3), prot_safe);
1926  	} else if (strncasecmp("CONF", cp, 4) == 0) {
1927  	    mec(mec_space(cp + 4), prot_confidential);
1928  	} else if (strncasecmp("ENC", cp, 3) == 0) {
1929  	    mec(mec_space(cp + 3), prot_private);
1930  	} else if (!allow_insecure_oob) {
1931  	    reply(533, "Command protection level denied "
1932  		  "for paranoid reasons.");
1933  	    goto out;
1934  	}
1935  
1936  	if (secure_command())
1937  	    cp = ftp_command;
1938  
1939  	if (strcasecmp(cp, "ABOR\r\n") == 0) {
1940  		abor();
1941  	} else if (strcasecmp(cp, "STAT\r\n") == 0) {
1942  		if (file_size != (off_t) -1)
1943  			reply(213, "Status: %ld of %ld bytes transferred",
1944  			      (long)byte_count,
1945  			      (long)file_size);
1946  		else
1947  			reply(213, "Status: %ld bytes transferred",
1948  			      (long)byte_count);
1949  	}
1950  out:
1951  	return (transflag == 0);
1952  }
1953  
1954  /*
1955   * Note: a response of 425 is not mentioned as a possible response to
1956   *	the PASV command in RFC959. However, it has been blessed as
1957   *	a legitimate response by Jon Postel in a telephone conversation
1958   *	with Rick Adams on 25 Jan 89.
1959   */
1960  void
pasv(void)1961  pasv(void)
1962  {
1963  	socklen_t len;
1964  	char *p, *a;
1965  	struct sockaddr_in *sin;
1966  
1967  	if (ctrl_addr->sa_family != AF_INET) {
1968  		reply(425,
1969  		      "You cannot do PASV with something that's not IPv4");
1970  		return;
1971  	}
1972  
1973  	if(pdata != -1)
1974  	    close(pdata);
1975  
1976  	pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
1977  	if (pdata < 0) {
1978  		perror_reply(425, "Can't open passive connection");
1979  		return;
1980  	}
1981  	pasv_addr->sa_family = ctrl_addr->sa_family;
1982  	socket_set_address_and_port (pasv_addr,
1983  				     socket_get_address (ctrl_addr),
1984  				     0);
1985  	socket_set_portrange(pdata, restricted_data_ports,
1986  	    pasv_addr->sa_family);
1987  	if (seteuid(0) < 0)
1988  		fatal("Failed to seteuid");
1989  	if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
1990  		if (seteuid(pw->pw_uid) < 0)
1991  			fatal("Failed to seteuid");
1992  		goto pasv_error;
1993  	}
1994  	if (seteuid(pw->pw_uid) < 0)
1995  		fatal("Failed to seteuid");
1996  	len = sizeof(pasv_addr_ss);
1997  	if (getsockname(pdata, pasv_addr, &len) < 0)
1998  		goto pasv_error;
1999  	if (listen(pdata, 1) < 0)
2000  		goto pasv_error;
2001  	sin = (struct sockaddr_in *)pasv_addr;
2002  	a = (char *) &sin->sin_addr;
2003  	p = (char *) &sin->sin_port;
2004  
2005  #define UC(b) (((int) b) & 0xff)
2006  
2007  	reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
2008  		UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
2009  	return;
2010  
2011  pasv_error:
2012  	close(pdata);
2013  	pdata = -1;
2014  	perror_reply(425, "Can't open passive connection");
2015  	return;
2016  }
2017  
2018  void
epsv(char * proto)2019  epsv(char *proto)
2020  {
2021  	socklen_t len;
2022  
2023  	pdata = socket(ctrl_addr->sa_family, SOCK_STREAM, 0);
2024  	if (pdata < 0) {
2025  		perror_reply(425, "Can't open passive connection");
2026  		return;
2027  	}
2028  	pasv_addr->sa_family = ctrl_addr->sa_family;
2029  	socket_set_address_and_port (pasv_addr,
2030  				     socket_get_address (ctrl_addr),
2031  				     0);
2032  	socket_set_portrange(pdata, restricted_data_ports,
2033  	    pasv_addr->sa_family);
2034  	if (seteuid(0) < 0)
2035  		fatal("Failed to seteuid");
2036  	if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) {
2037  		if (seteuid(pw->pw_uid))
2038  			fatal("Failed to seteuid");
2039  		goto pasv_error;
2040  	}
2041  	if (seteuid(pw->pw_uid) < 0)
2042  		fatal("Failed to seteuid");
2043  	len = sizeof(pasv_addr_ss);
2044  	if (getsockname(pdata, pasv_addr, &len) < 0)
2045  		goto pasv_error;
2046  	if (listen(pdata, 1) < 0)
2047  		goto pasv_error;
2048  
2049  	reply(229, "Entering Extended Passive Mode (|||%d|)",
2050  	      ntohs(socket_get_port (pasv_addr)));
2051  	return;
2052  
2053  pasv_error:
2054  	close(pdata);
2055  	pdata = -1;
2056  	perror_reply(425, "Can't open passive connection");
2057  	return;
2058  }
2059  
2060  void
eprt(char * str)2061  eprt(char *str)
2062  {
2063  	char *end;
2064  	char sep;
2065  	int af;
2066  	int ret;
2067  	int port;
2068  
2069  	usedefault = 0;
2070  	if (pdata >= 0) {
2071  	    close(pdata);
2072  	    pdata = -1;
2073  	}
2074  
2075  	sep = *str++;
2076  	if (sep == '\0') {
2077  		reply(500, "Bad syntax in EPRT");
2078  		return;
2079  	}
2080  	af = strtol (str, &end, 0);
2081  	if (af == 0 || *end != sep) {
2082  		reply(500, "Bad syntax in EPRT");
2083  		return;
2084  	}
2085  	str = end + 1;
2086  	switch (af) {
2087  #ifdef HAVE_IPV6
2088  	case 2 :
2089  	    data_dest->sa_family = AF_INET6;
2090  	    break;
2091  #endif
2092  	case 1 :
2093  	    data_dest->sa_family = AF_INET;
2094  		break;
2095  	default :
2096  		reply(522, "Network protocol %d not supported, use (1"
2097  #ifdef HAVE_IPV6
2098  		      ",2"
2099  #endif
2100  		      ")", af);
2101  		return;
2102  	}
2103  	end = strchr (str, sep);
2104  	if (end == NULL) {
2105  		reply(500, "Bad syntax in EPRT");
2106  		return;
2107  	}
2108  	*end = '\0';
2109  	ret = inet_pton (data_dest->sa_family, str,
2110  			 socket_get_address (data_dest));
2111  
2112  	if (ret != 1) {
2113  		reply(500, "Bad address syntax in EPRT");
2114  		return;
2115  	}
2116  	str = end + 1;
2117  	port = strtol (str, &end, 0);
2118  	if (port == 0 || *end != sep) {
2119  		reply(500, "Bad port syntax in EPRT");
2120  		return;
2121  	}
2122  	if (port < IPPORT_RESERVED) {
2123  		reply(500, "Bad port in invalid range in EPRT");
2124  		return;
2125  	}
2126  	socket_set_port (data_dest, htons(port));
2127  
2128  	if (paranoid &&
2129  	    (data_dest->sa_family != his_addr->sa_family ||
2130  	     memcmp(socket_get_address(data_dest), socket_get_address(his_addr), socket_sockaddr_size(data_dest)) != 0))
2131  	{
2132  		reply(500, "Bad address in EPRT");
2133  	}
2134  	reply(200, "EPRT command successful.");
2135  }
2136  
2137  /*
2138   * Generate unique name for file with basename "local".
2139   * The file named "local" is already known to exist.
2140   * Generates failure reply on error.
2141   */
2142  static char *
gunique(char * local)2143  gunique(char *local)
2144  {
2145  	static char new[MaxPathLen];
2146  	struct stat st;
2147  	int count;
2148  	char *cp;
2149  
2150  	cp = strrchr(local, '/');
2151  	if (cp)
2152  		*cp = '\0';
2153  	if (stat(cp ? local : ".", &st) < 0) {
2154  		perror_reply(553, cp ? local : ".");
2155  		return NULL;
2156  	}
2157  	if (cp)
2158  		*cp = '/';
2159  	for (count = 1; count < 100; count++) {
2160  		snprintf (new, sizeof(new), "%s.%d", local, count);
2161  		if (stat(new, &st) < 0)
2162  			return (new);
2163  	}
2164  	reply(452, "Unique file name cannot be created.");
2165  	return (NULL);
2166  }
2167  
2168  /*
2169   * Format and send reply containing system error number.
2170   */
2171  void
perror_reply(int code,const char * string)2172  perror_reply(int code, const char *string)
2173  {
2174  	reply(code, "%s: %s.", string, strerror(errno));
2175  }
2176  
2177  static char *onefile[] = {
2178  	"",
2179  	0
2180  };
2181  
2182  void
list_file(char * file)2183  list_file(char *file)
2184  {
2185      if(use_builtin_ls) {
2186  	FILE *dout;
2187  	dout = dataconn(file, -1, "w");
2188  	if (dout == NULL)
2189  	    return;
2190  	set_buffer_size(fileno(dout), 0);
2191  	if(builtin_ls(dout, file) == 0)
2192  	    reply(226, "Transfer complete.");
2193  	else
2194  	    reply(451, "Requested action aborted. Local error in processing.");
2195  	fclose(dout);
2196  	data = -1;
2197  	pdata = -1;
2198      } else {
2199  #ifdef HAVE_LS_A
2200  	const char *cmd = "/bin/ls -lA %s";
2201  #else
2202  	const char *cmd = "/bin/ls -la %s";
2203  #endif
2204  	retrieve(cmd, file);
2205      }
2206  }
2207  
2208  void
send_file_list(char * whichf)2209  send_file_list(char *whichf)
2210  {
2211      struct stat st;
2212      DIR *dirp = NULL;
2213      struct dirent *dir;
2214      FILE *dout = NULL;
2215      char **dirlist, *dirname;
2216      int simple = 0;
2217      int freeglob = 0;
2218      glob_t gl;
2219      char buf[MaxPathLen];
2220  
2221      if (strpbrk(whichf, "~{[*?") != NULL) {
2222  	int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE|
2223  #ifdef GLOB_MAXPATH
2224  	    GLOB_MAXPATH
2225  #else
2226  	    GLOB_LIMIT
2227  #endif
2228  	    ;
2229  
2230  	memset(&gl, 0, sizeof(gl));
2231  	freeglob = 1;
2232  	if (glob(whichf, flags, 0, &gl)) {
2233  	    reply(550, "not found");
2234  	    goto out;
2235  	} else if (gl.gl_pathc == 0) {
2236  	    errno = ENOENT;
2237  	    perror_reply(550, whichf);
2238  	    goto out;
2239  	}
2240  	dirlist = gl.gl_pathv;
2241      } else {
2242  	onefile[0] = whichf;
2243  	dirlist = onefile;
2244  	simple = 1;
2245      }
2246  
2247      while ((dirname = *dirlist++)) {
2248  
2249  	if (urgflag && handleoobcmd())
2250  	    goto out;
2251  
2252  	if (stat(dirname, &st) < 0) {
2253  	    /*
2254  	     * If user typed "ls -l", etc, and the client
2255  	     * used NLST, do what the user meant.
2256  	     */
2257  	    if (dirname[0] == '-' && *dirlist == NULL &&
2258  		transflag == 0) {
2259  		list_file(dirname);
2260  		goto out;
2261  	    }
2262  	    perror_reply(550, whichf);
2263  	    goto out;
2264  	}
2265  
2266  	if (S_ISREG(st.st_mode)) {
2267  	    if (dout == NULL) {
2268  		dout = dataconn("file list", (off_t)-1, "w");
2269  		if (dout == NULL)
2270  		    goto out;
2271  		transflag = 1;
2272  	    }
2273  	    snprintf(buf, sizeof(buf), "%s%s\n", dirname,
2274  		     type == TYPE_A ? "\r" : "");
2275  	    sec_write(fileno(dout), buf, strlen(buf));
2276  	    byte_count += strlen(dirname) + 1;
2277  	    continue;
2278  	} else if (!S_ISDIR(st.st_mode))
2279  	    continue;
2280  
2281  	if ((dirp = opendir(dirname)) == NULL)
2282  	    continue;
2283  
2284  	while ((dir = readdir(dirp)) != NULL) {
2285  	    char nbuf[MaxPathLen];
2286  
2287  	    if (urgflag && handleoobcmd())
2288  		goto out;
2289  
2290  	    if (!strcmp(dir->d_name, "."))
2291  		continue;
2292  	    if (!strcmp(dir->d_name, ".."))
2293  		continue;
2294  
2295  	    snprintf(nbuf, sizeof(nbuf), "%s/%s", dirname, dir->d_name);
2296  
2297  	    /*
2298  	     * We have to do a stat to insure it's
2299  	     * not a directory or special file.
2300  	     */
2301  	    if (simple || (stat(nbuf, &st) == 0 &&
2302  			   S_ISREG(st.st_mode))) {
2303  		if (dout == NULL) {
2304  		    dout = dataconn("file list", (off_t)-1, "w");
2305  		    if (dout == NULL)
2306  			goto out;
2307  		    transflag = 1;
2308  		}
2309  		if(strncmp(nbuf, "./", 2) == 0)
2310  		    snprintf(buf, sizeof(buf), "%s%s\n", nbuf +2,
2311  			     type == TYPE_A ? "\r" : "");
2312  		else
2313  		    snprintf(buf, sizeof(buf), "%s%s\n", nbuf,
2314  			     type == TYPE_A ? "\r" : "");
2315  		sec_write(fileno(dout), buf, strlen(buf));
2316  		byte_count += strlen(nbuf) + 1;
2317  	    }
2318  	}
2319  	closedir(dirp);
2320      }
2321      if (dout == NULL)
2322  	reply(550, "No files found.");
2323      else if (ferror(dout) != 0)
2324  	perror_reply(550, "Data connection");
2325      else
2326  	reply(226, "Transfer complete.");
2327  
2328  out:
2329      transflag = 0;
2330      if (dout != NULL){
2331  	sec_write(fileno(dout), buf, 0); /* XXX flush */
2332  
2333  	fclose(dout);
2334      }
2335      data = -1;
2336      pdata = -1;
2337      if (freeglob)
2338  	globfree(&gl);
2339  }
2340  
2341  
2342  int
find(char * pattern)2343  find(char *pattern)
2344  {
2345      char line[1024];
2346      FILE *f;
2347  
2348      snprintf(line, sizeof(line),
2349  	     "/bin/locate -d %s -- %s",
2350  	     ftp_rooted("/etc/locatedb"),
2351  	     pattern);
2352      f = ftpd_popen(line, "r", 1, 1);
2353      if(f == NULL){
2354  	perror_reply(550, "/bin/locate");
2355  	return 1;
2356      }
2357      lreply(200, "Output from find.");
2358      while(fgets(line, sizeof(line), f)){
2359  	if(line[strlen(line)-1] == '\n')
2360  	    line[strlen(line)-1] = 0;
2361  	nreply("%s", line);
2362      }
2363      reply(200, "Done");
2364      ftpd_pclose(f);
2365      return 0;
2366  }
2367  
2368