eliminate local version of glob (cf ftp)
[unix-history] / usr / src / libexec / ftpd / ftpd.c
index a786b54..09dc72d 100644 (file)
@@ -1,28 +1,18 @@
 /*
 /*
- * Copyright (c) 1985, 1988 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1985, 1988 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)ftpd.c     5.29    (Berkeley) %G%";
+static char sccsid[] = "@(#)ftpd.c     8.2 (Berkeley) %G%";
 #endif /* not lint */
 
 /*
 #endif /* not lint */
 
 /*
@@ -32,11 +22,11 @@ static char sccsid[] = "@(#)ftpd.c  5.29    (Berkeley) %G%";
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <sys/file.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
-#include <sys/dir.h>
 
 #include <netinet/in.h>
 
 #include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
 
 #define        FTP_NAMES
 #include <arpa/ftp.h>
 
 #define        FTP_NAMES
 #include <arpa/ftp.h>
@@ -44,31 +34,35 @@ static char sccsid[] = "@(#)ftpd.c  5.29    (Berkeley) %G%";
 #include <arpa/telnet.h>
 
 #include <ctype.h>
 #include <arpa/telnet.h>
 
 #include <ctype.h>
-#include <stdio.h>
-#include <signal.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <limits.h>
+#include <netdb.h>
 #include <pwd.h>
 #include <setjmp.h>
 #include <pwd.h>
 #include <setjmp.h>
-#include <netdb.h>
-#include <errno.h>
-#include <strings.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <syslog.h>
 #include <syslog.h>
-#include <varargs.h>
+#include <time.h>
+#include <unistd.h>
+
 #include "pathnames.h"
 #include "pathnames.h"
+#include "extern.h"
 
 
-/*
- * File containing login names
- * NOT to be used on this machine.
- * Commonly used to disallow uucp.
- */
-extern int errno;
-extern char *sys_errlist[];
-extern int sys_nerr;
-extern char *crypt();
-extern char version[];
-extern char *home;             /* pointer to home directory for glob */
-extern FILE *ftpd_popen(), *fopen(), *freopen();
-extern int  ftpd_pclose(), fclose();
-extern char *getline();
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+static char version[] = "Version 6.00";
+
+extern off_t restart_point;
 extern char cbuf[];
 
 struct sockaddr_in ctrl_addr;
 extern char cbuf[];
 
 struct sockaddr_in ctrl_addr;
@@ -92,7 +86,7 @@ int   stru;                   /* avoid C keyword */
 int    mode;
 int    usedefault = 1;         /* for data transfers */
 int    pdata = -1;             /* for passive mode */
 int    mode;
 int    usedefault = 1;         /* for data transfers */
 int    pdata = -1;             /* for passive mode */
-int    transflag;
+sig_atomic_t transflag;
 off_t  file_size;
 off_t  byte_count;
 #if !defined(CMASK) || CMASK == 0
 off_t  file_size;
 off_t  byte_count;
 #if !defined(CMASK) || CMASK == 0
@@ -115,37 +109,92 @@ char      remotehost[MAXHOSTNAMELEN];
 int    swaitmax = SWAITMAX;
 int    swaitint = SWAITINT;
 
 int    swaitmax = SWAITMAX;
 int    swaitint = SWAITINT;
 
-int    lostconn();
-int    myoob();
-FILE   *getdatasock(), *dataconn();
-
 #ifdef SETPROCTITLE
 char   **Argv = NULL;          /* pointer to argument vector */
 char   *LastArgv = NULL;       /* end of argv */
 #ifdef SETPROCTITLE
 char   **Argv = NULL;          /* pointer to argument vector */
 char   *LastArgv = NULL;       /* end of argv */
-char   proctitle[BUFSIZ];      /* initial part of title */
+char   proctitle[LINE_MAX];    /* initial part of title */
 #endif /* SETPROCTITLE */
 
 #endif /* SETPROCTITLE */
 
+#define LOGCMD(cmd, file) \
+       if (logging > 1) \
+           syslog(LOG_INFO,"%s %s%s", cmd, \
+               *(file) == '/' ? "" : curdir(), file);
+#define LOGCMD2(cmd, file1, file2) \
+        if (logging > 1) \
+           syslog(LOG_INFO,"%s %s%s %s%s", cmd, \
+               *(file1) == '/' ? "" : curdir(), file1, \
+               *(file2) == '/' ? "" : curdir(), file2);
+#define LOGBYTES(cmd, file, cnt) \
+       if (logging > 1) { \
+               if (cnt == (off_t)-1) \
+                   syslog(LOG_INFO,"%s %s%s", cmd, \
+                       *(file) == '/' ? "" : curdir(), file); \
+               else \
+                   syslog(LOG_INFO, "%s %s%s = %qd bytes", \
+                       cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \
+       }
+
+static void     ack __P((char *));
+static void     myoob __P((int));
+static int      checkuser __P((char *));
+static FILE    *dataconn __P((char *, off_t, char *));
+static void     dolog __P((struct sockaddr_in *));
+static char    *curdir __P((void));
+static void     end_login __P((void));
+static FILE    *getdatasock __P((char *));
+static char    *gunique __P((char *));
+static void     lostconn __P((int));
+static int      receive_data __P((FILE *, FILE *));
+static void     send_data __P((FILE *, FILE *, off_t));
+static struct passwd *
+                sgetpwnam __P((char *));
+static char    *sgetsave __P((char *));
+
+static char *
+curdir()
+{
+       static char path[MAXPATHLEN+1+1];       /* path + '/' + '\0' */
+
+       if (getcwd(path, sizeof(path)-2) == NULL)
+               return ("");
+       if (path[1] != '\0')            /* special case for root dir. */
+               strcat(path, "/");
+       /* For guest account, skip / since it's chrooted */
+       return (guest ? path+1 : path);
+}
+
+int
 main(argc, argv, envp)
        int argc;
        char *argv[];
        char **envp;
 {
 main(argc, argv, envp)
        int argc;
        char *argv[];
        char **envp;
 {
-       int addrlen, on = 1;
-       char *cp;
+       int addrlen, ch, on = 1, tos;
+       char *cp, line[LINE_MAX];
+       FILE *fd;
 
 
-       addrlen = sizeof (his_addr);
+       /*
+        * LOG_NDELAY sets up the logging connection immediately,
+        * necessary for anonymous ftp's that chroot and can't do it later.
+        */
+       openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+       addrlen = sizeof(his_addr);
        if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
                exit(1);
        }
        if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
                exit(1);
        }
-       addrlen = sizeof (ctrl_addr);
+       addrlen = sizeof(ctrl_addr);
        if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
                exit(1);
        }
        if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
                exit(1);
        }
+#ifdef IP_TOS
+       tos = IPTOS_LOWDELAY;
+       if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
+               syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
        data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
        debug = 0;
        data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
        debug = 0;
-       openlog("ftpd", LOG_PID, LOG_DAEMON);
 #ifdef SETPROCTITLE
        /*
         *  Save start and extent of argv for setproctitle.
 #ifdef SETPROCTITLE
        /*
         *  Save start and extent of argv for setproctitle.
@@ -156,54 +205,48 @@ main(argc, argv, envp)
        LastArgv = envp[-1] + strlen(envp[-1]);
 #endif /* SETPROCTITLE */
 
        LastArgv = envp[-1] + strlen(envp[-1]);
 #endif /* SETPROCTITLE */
 
-       argc--, argv++;
-       while (argc > 0 && *argv[0] == '-') {
-               for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
-
-               case 'v':
-                       debug = 1;
-                       break;
-
+       while ((ch = getopt(argc, argv, "dlt:T:u:v")) != EOF) {
+               switch (ch) {
                case 'd':
                        debug = 1;
                        break;
 
                case 'l':
                case 'd':
                        debug = 1;
                        break;
 
                case 'l':
-                       logging = 1;
+                       logging++;      /* > 1 == extra logging */
                        break;
 
                case 't':
                        break;
 
                case 't':
-                       timeout = atoi(++cp);
+                       timeout = atoi(optarg);
                        if (maxtimeout < timeout)
                                maxtimeout = timeout;
                        if (maxtimeout < timeout)
                                maxtimeout = timeout;
-                       goto nextopt;
+                       break;
 
                case 'T':
 
                case 'T':
-                       maxtimeout = atoi(++cp);
+                       maxtimeout = atoi(optarg);
                        if (timeout > maxtimeout)
                                timeout = maxtimeout;
                        if (timeout > maxtimeout)
                                timeout = maxtimeout;
-                       goto nextopt;
+                       break;
 
                case 'u':
                    {
 
                case 'u':
                    {
-                       int val = 0;
+                       long val = 0;
 
 
-                       while (*++cp && *cp >= '0' && *cp <= '9')
-                               val = val*8 + *cp - '0';
-                       if (*cp)
-                               fprintf(stderr, "ftpd: Bad value for -u\n");
+                       val = strtol(optarg, &optarg, 8);
+                       if (*optarg != '\0' || val < 0)
+                               warnx("bad value for -u");
                        else
                                defumask = val;
                        else
                                defumask = val;
-                       goto nextopt;
+                       break;
                    }
 
                    }
 
+               case 'v':
+                       debug = 1;
+                       break;
+
                default:
                default:
-                       fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
-                            *cp);
+                       warnx("unknown flag -%c ignored", optopt);
                        break;
                }
                        break;
                }
-nextopt:
-               argc--, argv++;
        }
        (void) freopen(_PATH_DEVNULL, "w", stderr);
        (void) signal(SIGPIPE, lostconn);
        }
        (void) freopen(_PATH_DEVNULL, "w", stderr);
        (void) signal(SIGPIPE, lostconn);
@@ -231,7 +274,30 @@ nextopt:
        stru = STRU_F;
        mode = MODE_S;
        tmpline[0] = '\0';
        stru = STRU_F;
        mode = MODE_S;
        tmpline[0] = '\0';
-       (void) gethostname(hostname, sizeof (hostname));
+
+       /* If logins are disabled, print out the message. */
+       if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) {
+               while (fgets(line, sizeof(line), fd) != NULL) {
+                       if ((cp = strchr(line, '\n')) != NULL)
+                               *cp = '\0';
+                       lreply(530, "%s", line);
+               }
+               (void) fflush(stdout);
+               (void) fclose(fd);
+               reply(530, "System not available.");
+               exit(0);
+       }
+       if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) {
+               while (fgets(line, sizeof(line), fd) != NULL) {
+                       if ((cp = strchr(line, '\n')) != NULL)
+                               *cp = '\0';
+                       lreply(220, "%s", line);
+               }
+               (void) fflush(stdout);
+               (void) fclose(fd);
+               /* reply(220,) must follow */
+       }
+       (void) gethostname(hostname, sizeof(hostname));
        reply(220, "%s FTP server (%s) ready.", hostname, version);
        (void) setjmp(errcatch);
        for (;;)
        reply(220, "%s FTP server (%s) ready.", hostname, version);
        (void) setjmp(errcatch);
        for (;;)
@@ -239,7 +305,9 @@ nextopt:
        /* NOTREACHED */
 }
 
        /* NOTREACHED */
 }
 
-lostconn()
+static void
+lostconn(signo)
+       int signo;
 {
 
        if (debug)
 {
 
        if (debug)
@@ -252,11 +320,10 @@ static char ttyline[20];
 /*
  * Helper function for sgetpwnam().
  */
 /*
  * Helper function for sgetpwnam().
  */
-char *
+static char *
 sgetsave(s)
        char *s;
 {
 sgetsave(s)
        char *s;
 {
-       char *malloc();
        char *new = malloc((unsigned) strlen(s) + 1);
 
        if (new == NULL) {
        char *new = malloc((unsigned) strlen(s) + 1);
 
        if (new == NULL) {
@@ -273,13 +340,12 @@ sgetsave(s)
  * the data returned must not be clobbered by any other command
  * (e.g., globbing).
  */
  * the data returned must not be clobbered by any other command
  * (e.g., globbing).
  */
-struct passwd *
+static struct passwd *
 sgetpwnam(name)
        char *name;
 {
        static struct passwd save;
 sgetpwnam(name)
        char *name;
 {
        static struct passwd save;
-       register struct passwd *p;
-       char *sgetsave();
+       struct passwd *p;
 
        if ((p = getpwnam(name)) == NULL)
                return (p);
 
        if ((p = getpwnam(name)) == NULL)
                return (p);
@@ -299,30 +365,26 @@ sgetpwnam(name)
        return (&save);
 }
 
        return (&save);
 }
 
-int login_attempts;            /* number of failed login attempts */
-int askpasswd;                 /* had user command, ask for passwd */
+static int login_attempts;     /* number of failed login attempts */
+static int askpasswd;          /* had user command, ask for passwd */
+static char curname[10];       /* current USER name */
 
 /*
  * USER command.
 
 /*
  * USER command.
- * Sets global passwd pointer pw if named account exists
- * and is acceptable; sets askpasswd if a PASS command is
- * expected. If logged in previously, need to reset state.
- * If name is "ftp" or "anonymous" and ftp account exists,
- * set guest and pw, then just return.
- * If account doesn't exist, ask for passwd anyway.
- * Otherwise, check user requesting login privileges.
- * Disallow anyone who does not have a standard
- * shell as returned by getusershell().
- * Disallow anyone mentioned in the file _PATH_FTPUSERS
- * to allow people such as root and uucp to be avoided.
+ * Sets global passwd pointer pw if named account exists and is acceptable;
+ * sets askpasswd if a PASS command is expected.  If logged in previously,
+ * need to reset state.  If name is "ftp" or "anonymous", the name is not in
+ * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
+ * If account doesn't exist, ask for passwd anyway.  Otherwise, check user
+ * requesting login privileges.  Disallow anyone who does not have a standard
+ * shell as returned by getusershell().  Disallow anyone mentioned in the file
+ * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
  */
  */
+void
 user(name)
        char *name;
 {
 user(name)
        char *name;
 {
-       register char *cp;
-       FILE *fd;
-       char *shell;
-       char line[BUFSIZ], *getusershell();
+       char *cp, *shell;
 
        if (logged_in) {
                if (guest) {
 
        if (logged_in) {
                if (guest) {
@@ -334,12 +396,18 @@ user(name)
 
        guest = 0;
        if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
 
        guest = 0;
        if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
-               if ((pw = sgetpwnam("ftp")) != NULL) {
+               if (checkuser("ftp") || checkuser("anonymous"))
+                       reply(530, "User %s access denied.", name);
+               else if ((pw = sgetpwnam("ftp")) != NULL) {
                        guest = 1;
                        askpasswd = 1;
                        guest = 1;
                        askpasswd = 1;
-                       reply(331, "Guest login ok, send ident as password.");
+                       reply(331,
+                           "Guest login ok, type your name as password.");
                } else
                        reply(530, "User %s unknown.", name);
                } else
                        reply(530, "User %s unknown.", name);
+               if (!askpasswd && logging)
+                       syslog(LOG_NOTICE,
+                           "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost);
                return;
        }
        if (pw = sgetpwnam(name)) {
                return;
        }
        if (pw = sgetpwnam(name)) {
@@ -349,7 +417,8 @@ user(name)
                        if (strcmp(cp, shell) == 0)
                                break;
                endusershell();
                        if (strcmp(cp, shell) == 0)
                                break;
                endusershell();
-               if (cp == NULL) {
+
+               if (cp == NULL || checkuser(name)) {
                        reply(530, "User %s access denied.", name);
                        if (logging)
                                syslog(LOG_NOTICE,
                        reply(530, "User %s access denied.", name);
                        if (logging)
                                syslog(LOG_NOTICE,
@@ -358,24 +427,9 @@ user(name)
                        pw = (struct passwd *) NULL;
                        return;
                }
                        pw = (struct passwd *) NULL;
                        return;
                }
-               if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
-                   while (fgets(line, sizeof (line), fd) != NULL) {
-                       if ((cp = index(line, '\n')) != NULL)
-                               *cp = '\0';
-                       if (strcmp(line, name) == 0) {
-                               reply(530, "User %s access denied.", name);
-                               if (logging)
-                                       syslog(LOG_NOTICE,
-                                           "FTP LOGIN REFUSED FROM %s, %s",
-                                           remotehost, name);
-                               pw = (struct passwd *) NULL;
-                               (void) fclose(fd);
-                               return;
-                       }
-                   }
-                   (void) fclose(fd);
-               }
        }
        }
+       if (logging)
+               strncpy(curname, name, sizeof(curname)-1);
        reply(331, "Password required for %s.", name);
        askpasswd = 1;
        /*
        reply(331, "Password required for %s.", name);
        askpasswd = 1;
        /*
@@ -386,10 +440,38 @@ user(name)
                sleep((unsigned) login_attempts);
 }
 
                sleep((unsigned) login_attempts);
 }
 
+/*
+ * Check if a user is in the file _PATH_FTPUSERS
+ */
+static int
+checkuser(name)
+       char *name;
+{
+       FILE *fd;
+       int found = 0;
+       char *p, line[BUFSIZ];
+
+       if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
+               while (fgets(line, sizeof(line), fd) != NULL)
+                       if ((p = strchr(line, '\n')) != NULL) {
+                               *p = '\0';
+                               if (line[0] == '#')
+                                       continue;
+                               if (strcmp(p, name) == 0) {
+                                       found = 1;
+                                       break;
+                               }
+                       }
+               (void) fclose(fd);
+       }
+       return (found);
+}
+
 /*
  * Terminate login as previous user, if any, resetting state;
  * used when USER command is given or login fails.
  */
 /*
  * Terminate login as previous user, if any, resetting state;
  * used when USER command is given or login fails.
  */
+static void
 end_login()
 {
 
 end_login()
 {
 
@@ -401,10 +483,12 @@ end_login()
        guest = 0;
 }
 
        guest = 0;
 }
 
+void
 pass(passwd)
        char *passwd;
 {
 pass(passwd)
        char *passwd;
 {
-       char *xpasswd, *salt;
+       char *salt, *xpasswd;
+       FILE *fd;
 
        if (logged_in || askpasswd == 0) {
                reply(503, "Login with USER first.");
 
        if (logged_in || askpasswd == 0) {
                reply(503, "Login with USER first.");
@@ -421,6 +505,10 @@ pass(passwd)
                if (pw == NULL || *pw->pw_passwd == '\0' ||
                    strcmp(xpasswd, pw->pw_passwd)) {
                        reply(530, "Login incorrect.");
                if (pw == NULL || *pw->pw_passwd == '\0' ||
                    strcmp(xpasswd, pw->pw_passwd)) {
                        reply(530, "Login incorrect.");
+                       if (logging)
+                               syslog(LOG_NOTICE,
+                                   "FTP LOGIN FAILED FROM %s, %s",
+                                   remotehost, curname);
                        pw = NULL;
                        if (login_attempts++ >= 5) {
                                syslog(LOG_NOTICE,
                        pw = NULL;
                        if (login_attempts++ >= 5) {
                                syslog(LOG_NOTICE,
@@ -432,7 +520,10 @@ pass(passwd)
                }
        }
        login_attempts = 0;             /* this time successful */
                }
        }
        login_attempts = 0;             /* this time successful */
-       (void) setegid((gid_t)pw->pw_gid);
+       if (setegid((gid_t)pw->pw_gid) < 0) {
+               reply(550, "Can't set gid.");
+               return;
+       }
        (void) initgroups(pw->pw_name, pw->pw_gid);
 
        /* open wtmp before chroot */
        (void) initgroups(pw->pw_name, pw->pw_gid);
 
        /* open wtmp before chroot */
@@ -462,10 +553,26 @@ pass(passwd)
                reply(550, "Can't set uid.");
                goto bad;
        }
                reply(550, "Can't set uid.");
                goto bad;
        }
+       /*
+        * Display a login message, if it exists.
+        * N.B. reply(230,) must follow the message.
+        */
+       if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) {
+               char *cp, line[LINE_MAX];
+
+               while (fgets(line, sizeof(line), fd) != NULL) {
+                       if ((cp = strchr(line, '\n')) != NULL)
+                               *cp = '\0';
+                       lreply(230, "%s", line);
+               }
+               (void) fflush(stdout);
+               (void) fclose(fd);
+       }
        if (guest) {
                reply(230, "Guest login ok, access restrictions apply.");
 #ifdef SETPROCTITLE
        if (guest) {
                reply(230, "Guest login ok, access restrictions apply.");
 #ifdef SETPROCTITLE
-               sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
+               snprintf(proctitle, sizeof(proctitle),
+                   "%s: anonymous/%.*s", remotehost,
                    sizeof(proctitle) - sizeof(remotehost) -
                    sizeof(": anonymous/"), passwd);
                setproctitle(proctitle);
                    sizeof(proctitle) - sizeof(remotehost) -
                    sizeof(": anonymous/"), passwd);
                setproctitle(proctitle);
@@ -476,14 +583,14 @@ pass(passwd)
        } else {
                reply(230, "User %s logged in.", pw->pw_name);
 #ifdef SETPROCTITLE
        } else {
                reply(230, "User %s logged in.", pw->pw_name);
 #ifdef SETPROCTITLE
-               sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
+               snprintf(proctitle, sizeof(proctitle),
+                   "%s: %s", remotehost, pw->pw_name);
                setproctitle(proctitle);
 #endif /* SETPROCTITLE */
                if (logging)
                setproctitle(proctitle);
 #endif /* SETPROCTITLE */
                if (logging)
-                       syslog(LOG_INFO, "FTP LOGIN FROM %s, %s",
+                       syslog(LOG_INFO, "FTP LOGIN FROM %s as %s",
                            remotehost, pw->pw_name);
        }
                            remotehost, pw->pw_name);
        }
-       home = pw->pw_dir;              /* home dir for globbing */
        (void) umask(defumask);
        return;
 bad:
        (void) umask(defumask);
        return;
 bad:
@@ -491,12 +598,13 @@ bad:
        end_login();
 }
 
        end_login();
 }
 
+void
 retrieve(cmd, name)
        char *cmd, *name;
 {
        FILE *fin, *dout;
        struct stat st;
 retrieve(cmd, name)
        char *cmd, *name;
 {
        FILE *fin, *dout;
        struct stat st;
-       int (*closefunc)();
+       int (*closefunc) __P((FILE *));
 
        if (cmd == 0) {
                fin = fopen(name, "r"), closefunc = fclose;
 
        if (cmd == 0) {
                fin = fopen(name, "r"), closefunc = fclose;
@@ -510,12 +618,16 @@ retrieve(cmd, name)
                st.st_blksize = BUFSIZ;
        }
        if (fin == NULL) {
                st.st_blksize = BUFSIZ;
        }
        if (fin == NULL) {
-               if (errno != 0)
+               if (errno != 0) {
                        perror_reply(550, name);
                        perror_reply(550, name);
+                       if (cmd == 0) {
+                               LOGCMD("get", name);
+                       }
+               }
                return;
        }
                return;
        }
-       if (cmd == 0 &&
-           (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) {
+       byte_count = -1;
+       if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) {
                reply(550, "%s: not a plain file.", name);
                goto done;
        }
                reply(550, "%s: not a plain file.", name);
                goto done;
        }
@@ -527,26 +639,31 @@ retrieve(cmd, name)
        data = -1;
        pdata = -1;
 done:
        data = -1;
        pdata = -1;
 done:
+       if (cmd == 0)
+               LOGBYTES("get", name, byte_count);
        (*closefunc)(fin);
 }
 
        (*closefunc)(fin);
 }
 
+void
 store(name, mode, unique)
        char *name, *mode;
        int unique;
 {
        FILE *fout, *din;
        struct stat st;
 store(name, mode, unique)
        char *name, *mode;
        int unique;
 {
        FILE *fout, *din;
        struct stat st;
-       int (*closefunc)();
-       char *gunique();
+       int (*closefunc) __P((FILE *));
 
        if (unique && stat(name, &st) == 0 &&
 
        if (unique && stat(name, &st) == 0 &&
-           (name = gunique(name)) == NULL)
+           (name = gunique(name)) == NULL) {
+               LOGCMD(*mode == 'w' ? "put" : "append", name);
                return;
                return;
+       }
 
        fout = fopen(name, mode);
        closefunc = fclose;
        if (fout == NULL) {
                perror_reply(553, name);
 
        fout = fopen(name, mode);
        closefunc = fclose;
        if (fout == NULL) {
                perror_reply(553, name);
+               LOGCMD(*mode == 'w' ? "put" : "append", name);
                return;
        }
        din = dataconn(name, (off_t)-1, "r");
                return;
        }
        din = dataconn(name, (off_t)-1, "r");
@@ -563,44 +680,53 @@ store(name, mode, unique)
        data = -1;
        pdata = -1;
 done:
        data = -1;
        pdata = -1;
 done:
+       LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count);
        (*closefunc)(fout);
 }
 
        (*closefunc)(fout);
 }
 
-FILE *
+static FILE *
 getdatasock(mode)
        char *mode;
 {
 getdatasock(mode)
        char *mode;
 {
-       int s, on = 1, tries;
+       int on = 1, s, t, tries;
 
        if (data >= 0)
                return (fdopen(data, mode));
 
        if (data >= 0)
                return (fdopen(data, mode));
+       (void) seteuid((uid_t)0);
        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s < 0)
        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s < 0)
-               return (NULL);
-       (void) seteuid((uid_t)0);
+               goto bad;
        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
-           (char *) &on, sizeof (on)) < 0)
+           (char *) &on, sizeof(on)) < 0)
                goto bad;
        /* anchor socket to avoid multi-homing problems */
        data_source.sin_family = AF_INET;
        data_source.sin_addr = ctrl_addr.sin_addr;
        for (tries = 1; ; tries++) {
                if (bind(s, (struct sockaddr *)&data_source,
                goto bad;
        /* anchor socket to avoid multi-homing problems */
        data_source.sin_family = AF_INET;
        data_source.sin_addr = ctrl_addr.sin_addr;
        for (tries = 1; ; tries++) {
                if (bind(s, (struct sockaddr *)&data_source,
-                   sizeof (data_source)) >= 0)
+                   sizeof(data_source)) >= 0)
                        break;
                if (errno != EADDRINUSE || tries > 10)
                        goto bad;
                sleep(tries);
        }
        (void) seteuid((uid_t)pw->pw_uid);
                        break;
                if (errno != EADDRINUSE || tries > 10)
                        goto bad;
                sleep(tries);
        }
        (void) seteuid((uid_t)pw->pw_uid);
+#ifdef IP_TOS
+       on = IPTOS_THROUGHPUT;
+       if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
+               syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif
        return (fdopen(s, mode));
 bad:
        return (fdopen(s, mode));
 bad:
+       /* Return the real value of errno (close may change it) */
+       t = errno;
        (void) seteuid((uid_t)pw->pw_uid);
        (void) close(s);
        (void) seteuid((uid_t)pw->pw_uid);
        (void) close(s);
+       errno = t;
        return (NULL);
 }
 
        return (NULL);
 }
 
-FILE *
+static FILE *
 dataconn(name, size, mode)
        char *name;
        off_t size;
 dataconn(name, size, mode)
        char *name;
        off_t size;
@@ -608,12 +734,12 @@ dataconn(name, size, mode)
 {
        char sizebuf[32];
        FILE *file;
 {
        char sizebuf[32];
        FILE *file;
-       int retry = 0;
+       int retry = 0, tos;
 
        file_size = size;
        byte_count = 0;
        if (size != (off_t) -1)
 
        file_size = size;
        byte_count = 0;
        if (size != (off_t) -1)
-               (void) sprintf (sizebuf, " (%ld bytes)", size);
+               (void) sprintf(sizebuf, " (%qd bytes)", size);
        else
                (void) strcpy(sizebuf, "");
        if (pdata >= 0) {
        else
                (void) strcpy(sizebuf, "");
        if (pdata >= 0) {
@@ -625,16 +751,21 @@ dataconn(name, size, mode)
                        reply(425, "Can't open data connection.");
                        (void) close(pdata);
                        pdata = -1;
                        reply(425, "Can't open data connection.");
                        (void) close(pdata);
                        pdata = -1;
-                       return(NULL);
+                       return (NULL);
                }
                (void) close(pdata);
                pdata = s;
                }
                (void) close(pdata);
                pdata = s;
-               reply(150, "Opening %s mode data connection for %s%s.",
+#ifdef IP_TOS
+               tos = IPTOS_LOWDELAY;
+               (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
+                   sizeof(int));
+#endif
+               reply(150, "Opening %s mode data connection for '%s'%s.",
                     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
                     type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
-               return(fdopen(pdata, mode));
+               return (fdopen(pdata, mode));
        }
        if (data >= 0) {
        }
        if (data >= 0) {
-               reply(125, "Using existing data connection for %s%s.",
+               reply(125, "Using existing data connection for '%s'%s.",
                    name, sizebuf);
                usedefault = 1;
                return (fdopen(data, mode));
                    name, sizebuf);
                usedefault = 1;
                return (fdopen(data, mode));
@@ -646,13 +777,12 @@ dataconn(name, size, mode)
        if (file == NULL) {
                reply(425, "Can't create data socket (%s,%d): %s.",
                    inet_ntoa(data_source.sin_addr),
        if (file == NULL) {
                reply(425, "Can't create data socket (%s,%d): %s.",
                    inet_ntoa(data_source.sin_addr),
-                   ntohs(data_source.sin_port),
-                   errno < sys_nerr ? sys_errlist[errno] : "unknown error");
+                   ntohs(data_source.sin_port), strerror(errno));
                return (NULL);
        }
        data = fileno(file);
        while (connect(data, (struct sockaddr *)&data_dest,
                return (NULL);
        }
        data = fileno(file);
        while (connect(data, (struct sockaddr *)&data_dest,
-           sizeof (data_dest)) < 0) {
+           sizeof(data_dest)) < 0) {
                if (errno == EADDRINUSE && retry < swaitmax) {
                        sleep((unsigned) swaitint);
                        retry += swaitint;
                if (errno == EADDRINUSE && retry < swaitmax) {
                        sleep((unsigned) swaitint);
                        retry += swaitint;
@@ -663,26 +793,24 @@ dataconn(name, size, mode)
                data = -1;
                return (NULL);
        }
                data = -1;
                return (NULL);
        }
-       reply(150, "Opening %s mode data connection for %s%s.",
+       reply(150, "Opening %s mode data connection for '%s'%s.",
             type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
        return (file);
 }
 
 /*
             type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
        return (file);
 }
 
 /*
- * Tranfer the contents of "instr" to
- * "outstr" peer using the appropriate
- * encapsulation of the data subject
- * to Mode, Structure, and Type.
+ * Tranfer the contents of "instr" to "outstr" peer using the appropriate
+ * encapsulation of the data subject * to Mode, Structure, and Type.
  *
  * NB: Form isn't handled.
  */
  *
  * NB: Form isn't handled.
  */
+static void
 send_data(instr, outstr, blksize)
        FILE *instr, *outstr;
        off_t blksize;
 {
 send_data(instr, outstr, blksize)
        FILE *instr, *outstr;
        off_t blksize;
 {
-       register int c, cnt;
-       register char *buf;
-       int netfd, filefd;
+       int c, cnt, filefd, netfd;
+       char *buf;
 
        transflag++;
        if (setjmp(urgcatch)) {
 
        transflag++;
        if (setjmp(urgcatch)) {
@@ -748,17 +876,16 @@ file_err:
 }
 
 /*
 }
 
 /*
- * Transfer data from peer to
- * "outstr" using the appropriate
- * encapulation of the data subject
- * to Mode, Structure, and Type.
+ * Transfer data from peer to "outstr" using the appropriate encapulation of
+ * the data subject to Mode, Structure, and Type.
  *
  * N.B.: Form isn't handled.
  */
  *
  * N.B.: Form isn't handled.
  */
+static int
 receive_data(instr, outstr)
        FILE *instr, *outstr;
 {
 receive_data(instr, outstr)
        FILE *instr, *outstr;
 {
-       register int c;
+       int c;
        int cnt, bare_lfs = 0;
        char buf[BUFSIZ];
 
        int cnt, bare_lfs = 0;
        char buf[BUFSIZ];
 
@@ -771,7 +898,7 @@ receive_data(instr, outstr)
 
        case TYPE_I:
        case TYPE_L:
 
        case TYPE_I:
        case TYPE_L:
-               while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
+               while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) {
                        if (write(fileno(outstr), buf, cnt) != cnt)
                                goto file_err;
                        byte_count += cnt;
                        if (write(fileno(outstr), buf, cnt) != cnt)
                                goto file_err;
                        byte_count += cnt;
@@ -831,14 +958,15 @@ file_err:
        return (-1);
 }
 
        return (-1);
 }
 
+void
 statfilecmd(filename)
        char *filename;
 {
 statfilecmd(filename)
        char *filename;
 {
-       char line[BUFSIZ];
        FILE *fin;
        int c;
        FILE *fin;
        int c;
+       char line[LINE_MAX];
 
 
-       (void) sprintf(line, "/bin/ls -lgA %s", filename);
+       (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename);
        fin = ftpd_popen(line, "r");
        lreply(211, "status of %s:", filename);
        while ((c = getc(fin)) != EOF) {
        fin = ftpd_popen(line, "r");
        lreply(211, "status of %s:", filename);
        while ((c = getc(fin)) != EOF) {
@@ -862,6 +990,7 @@ statfilecmd(filename)
        reply(211, "End of Status");
 }
 
        reply(211, "End of Status");
 }
 
+void
 statcmd()
 {
        struct sockaddr_in *sin;
 statcmd()
 {
        struct sockaddr_in *sin;
@@ -914,73 +1043,104 @@ printaddr:
        reply(211, "End of status");
 }
 
        reply(211, "End of status");
 }
 
+void
 fatal(s)
        char *s;
 {
 fatal(s)
        char *s;
 {
+
        reply(451, "Error in server: %s\n", s);
        reply(221, "Closing connection due to server error.");
        dologout(0);
        /* NOTREACHED */
 }
 
        reply(451, "Error in server: %s\n", s);
        reply(221, "Closing connection due to server error.");
        dologout(0);
        /* NOTREACHED */
 }
 
-/* VARARGS2 */
-reply(n, fmt, p0, p1, p2, p3, p4, p5)
+void
+#if __STDC__
+reply(int n, const char *fmt, ...)
+#else
+reply(n, fmt, va_alist)
        int n;
        char *fmt;
        int n;
        char *fmt;
+        va_dcl
+#endif
 {
 {
-       printf("%d ", n);
-       printf(fmt, p0, p1, p2, p3, p4, p5);
-       printf("\r\n");
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)printf("%d ", n);
+       (void)vprintf(fmt, ap);
+       (void)printf("\r\n");
        (void)fflush(stdout);
        if (debug) {
                syslog(LOG_DEBUG, "<--- %d ", n);
        (void)fflush(stdout);
        if (debug) {
                syslog(LOG_DEBUG, "<--- %d ", n);
-               syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
-}
+               vsyslog(LOG_DEBUG, fmt, ap);
+       }
 }
 
 }
 
-/* VARARGS2 */
-lreply(n, fmt, p0, p1, p2, p3, p4, p5)
+void
+#if __STDC__
+lreply(int n, const char *fmt, ...)
+#else
+lreply(n, fmt, va_alist)
        int n;
        char *fmt;
        int n;
        char *fmt;
+        va_dcl
+#endif
 {
 {
-       printf("%d- ", n);
-       printf(fmt, p0, p1, p2, p3, p4, p5);
-       printf("\r\n");
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)printf("%d- ", n);
+       (void)vprintf(fmt, ap);
+       (void)printf("\r\n");
        (void)fflush(stdout);
        if (debug) {
                syslog(LOG_DEBUG, "<--- %d- ", n);
        (void)fflush(stdout);
        if (debug) {
                syslog(LOG_DEBUG, "<--- %d- ", n);
-               syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
+               vsyslog(LOG_DEBUG, fmt, ap);
        }
 }
 
        }
 }
 
+static void
 ack(s)
        char *s;
 {
 ack(s)
        char *s;
 {
+
        reply(250, "%s command successful.", s);
 }
 
        reply(250, "%s command successful.", s);
 }
 
+void
 nack(s)
        char *s;
 {
 nack(s)
        char *s;
 {
+
        reply(502, "%s command not implemented.", s);
 }
 
 /* ARGSUSED */
        reply(502, "%s command not implemented.", s);
 }
 
 /* ARGSUSED */
+void
 yyerror(s)
        char *s;
 {
        char *cp;
 
 yyerror(s)
        char *s;
 {
        char *cp;
 
-       if (cp = index(cbuf,'\n'))
+       if (cp = strchr(cbuf,'\n'))
                *cp = '\0';
        reply(500, "'%s': command not understood.", cbuf);
 }
 
                *cp = '\0';
        reply(500, "'%s': command not understood.", cbuf);
 }
 
+void
 delete(name)
        char *name;
 {
        struct stat st;
 
 delete(name)
        char *name;
 {
        struct stat st;
 
+       LOGCMD("delete", name);
        if (stat(name, &st) < 0) {
                perror_reply(550, name);
                return;
        if (stat(name, &st) < 0) {
                perror_reply(550, name);
                return;
@@ -1000,37 +1160,45 @@ done:
        ack("DELE");
 }
 
        ack("DELE");
 }
 
+void
 cwd(path)
        char *path;
 {
 cwd(path)
        char *path;
 {
+
        if (chdir(path) < 0)
                perror_reply(550, path);
        else
                ack("CWD");
 }
 
        if (chdir(path) < 0)
                perror_reply(550, path);
        else
                ack("CWD");
 }
 
+void
 makedir(name)
        char *name;
 {
 makedir(name)
        char *name;
 {
+
+       LOGCMD("mkdir", name);
        if (mkdir(name, 0777) < 0)
                perror_reply(550, name);
        else
                reply(257, "MKD command successful.");
 }
 
        if (mkdir(name, 0777) < 0)
                perror_reply(550, name);
        else
                reply(257, "MKD command successful.");
 }
 
+void
 removedir(name)
        char *name;
 {
 removedir(name)
        char *name;
 {
+
+       LOGCMD("rmdir", name);
        if (rmdir(name) < 0)
                perror_reply(550, name);
        else
                ack("RMD");
 }
 
        if (rmdir(name) < 0)
                perror_reply(550, name);
        else
                ack("RMD");
 }
 
+void
 pwd()
 {
        char path[MAXPATHLEN + 1];
 pwd()
 {
        char path[MAXPATHLEN + 1];
-       extern char *getwd();
 
        if (getwd(path) == (char *)NULL)
                reply(550, "%s.", path);
 
        if (getwd(path) == (char *)NULL)
                reply(550, "%s.", path);
@@ -1052,47 +1220,48 @@ renamefrom(name)
        return (name);
 }
 
        return (name);
 }
 
+void
 renamecmd(from, to)
        char *from, *to;
 {
 renamecmd(from, to)
        char *from, *to;
 {
+
+       LOGCMD2("rename", from, to);
        if (rename(from, to) < 0)
                perror_reply(550, "rename");
        else
                ack("RNTO");
 }
 
        if (rename(from, to) < 0)
                perror_reply(550, "rename");
        else
                ack("RNTO");
 }
 
+static void
 dolog(sin)
        struct sockaddr_in *sin;
 {
        struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
 dolog(sin)
        struct sockaddr_in *sin;
 {
        struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
-               sizeof (struct in_addr), AF_INET);
-       time_t t, time();
-       extern char *ctime();
+               sizeof(struct in_addr), AF_INET);
 
        if (hp)
 
        if (hp)
-               (void) strncpy(remotehost, hp->h_name, sizeof (remotehost));
+               (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
        else
                (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
        else
                (void) strncpy(remotehost, inet_ntoa(sin->sin_addr),
-                   sizeof (remotehost));
+                   sizeof(remotehost));
 #ifdef SETPROCTITLE
 #ifdef SETPROCTITLE
-       sprintf(proctitle, "%s: connected", remotehost);
+       snprintf(proctitle, sizeof(proctitle), "%s: connected", remotehost);
        setproctitle(proctitle);
 #endif /* SETPROCTITLE */
 
        setproctitle(proctitle);
 #endif /* SETPROCTITLE */
 
-       if (logging) {
-               t = time((time_t *) 0);
-               syslog(LOG_INFO, "connection from %s at %s",
-                   remotehost, ctime(&t));
-       }
+       if (logging)
+               syslog(LOG_INFO, "connection from %s", remotehost);
 }
 
 /*
  * Record logout in wtmp file
  * and exit with supplied status.
  */
 }
 
 /*
  * Record logout in wtmp file
  * and exit with supplied status.
  */
+void
 dologout(status)
        int status;
 {
 dologout(status)
        int status;
 {
+
        if (logged_in) {
                (void) seteuid((uid_t)0);
                logwtmp(ttyline, "", "");
        if (logged_in) {
                (void) seteuid((uid_t)0);
                logwtmp(ttyline, "", "");
@@ -1101,7 +1270,9 @@ dologout(status)
        _exit(status);
 }
 
        _exit(status);
 }
 
-myoob()
+static void
+myoob(signo)
+       int signo;
 {
        char *cp;
 
 {
        char *cp;
 
@@ -1122,23 +1293,24 @@ myoob()
        }
        if (strcmp(cp, "STAT\r\n") == 0) {
                if (file_size != (off_t) -1)
        }
        if (strcmp(cp, "STAT\r\n") == 0) {
                if (file_size != (off_t) -1)
-                       reply(213, "Status: %lu of %lu bytes transferred",
+                       reply(213, "Status: %qd of %qd bytes transferred",
                            byte_count, file_size);
                else
                            byte_count, file_size);
                else
-                       reply(213, "Status: %lu bytes transferred", byte_count);
+                       reply(213, "Status: %qd bytes transferred", byte_count);
        }
 }
 
 /*
  * Note: a response of 425 is not mentioned as a possible response to
        }
 }
 
 /*
  * Note: a response of 425 is not mentioned as a possible response to
- *     the PASV command in RFC959. However, it has been blessed as
- *     a legitimate response by Jon Postel in a telephone conversation
+ *     the PASV command in RFC959. However, it has been blessed as
+ *     a legitimate response by Jon Postel in a telephone conversation
  *     with Rick Adams on 25 Jan 89.
  */
  *     with Rick Adams on 25 Jan 89.
  */
+void
 passive()
 {
        int len;
 passive()
 {
        int len;
-       register char *p, *a;
+       char *p, *a;
 
        pdata = socket(AF_INET, SOCK_STREAM, 0);
        if (pdata < 0) {
 
        pdata = socket(AF_INET, SOCK_STREAM, 0);
        if (pdata < 0) {
@@ -1179,20 +1351,21 @@ pasv_error:
  * The file named "local" is already known to exist.
  * Generates failure reply on error.
  */
  * The file named "local" is already known to exist.
  * Generates failure reply on error.
  */
-char *
+static char *
 gunique(local)
        char *local;
 {
        static char new[MAXPATHLEN];
        struct stat st;
 gunique(local)
        char *local;
 {
        static char new[MAXPATHLEN];
        struct stat st;
-       char *cp = rindex(local, '/');
-       int count = 0;
+       int count;
+       char *cp;
 
 
+       cp = strrchr(local, '/');
        if (cp)
                *cp = '\0';
        if (stat(cp ? local : ".", &st) < 0) {
                perror_reply(553, cp ? local : ".");
        if (cp)
                *cp = '\0';
        if (stat(cp ? local : ".", &st) < 0) {
                perror_reply(553, cp ? local : ".");
-               return((char *) 0);
+               return ((char *) 0);
        }
        if (cp)
                *cp = '/';
        }
        if (cp)
                *cp = '/';
@@ -1200,25 +1373,24 @@ gunique(local)
        cp = new + strlen(new);
        *cp++ = '.';
        for (count = 1; count < 100; count++) {
        cp = new + strlen(new);
        *cp++ = '.';
        for (count = 1; count < 100; count++) {
-               (void) sprintf(cp, "%d", count);
+               (void)sprintf(cp, "%d", count);
                if (stat(new, &st) < 0)
                if (stat(new, &st) < 0)
-                       return(new);
+                       return (new);
        }
        reply(452, "Unique file name cannot be created.");
        }
        reply(452, "Unique file name cannot be created.");
-       return((char *) 0);
+       return (NULL);
 }
 
 /*
  * Format and send reply containing system error number.
  */
 }
 
 /*
  * Format and send reply containing system error number.
  */
+void
 perror_reply(code, string)
        int code;
        char *string;
 {
 perror_reply(code, string)
        int code;
        char *string;
 {
-       if (errno < sys_nerr)
-               reply(code, "%s: %s.", string, sys_errlist[errno]);
-       else
-               reply(code, "%s: unknown error %d.", string, errno);
+
+       reply(code, "%s: %s.", string, strerror(errno));
 }
 
 static char *onefile[] = {
 }
 
 static char *onefile[] = {
@@ -1226,39 +1398,41 @@ static char *onefile[] = {
        0
 };
 
        0
 };
 
-send_file_list(whichfiles)
-       char *whichfiles;
+void
+send_file_list(whichf)
+       char *whichf;
 {
        struct stat st;
        DIR *dirp = NULL;
 {
        struct stat st;
        DIR *dirp = NULL;
-       struct direct *dir;
+       struct dirent *dir;
        FILE *dout = NULL;
        FILE *dout = NULL;
-       register char **dirlist, *dirname;
+       char **dirlist, *dirname;
        int simple = 0;
        int simple = 0;
-       char *strpbrk();
+       int freeglob = 0;
+       glob_t gl;
 
 
-       if (strpbrk(whichfiles, "~{[*?") != NULL) {
-               extern char **glob(), *globerr;
+       if (strpbrk(whichf, "~{[*?") != NULL) {
 
 
-               globerr = NULL;
-               dirlist = glob(whichfiles);
-               if (globerr != NULL) {
-                       reply(550, globerr);
-                       return;
-               } else if (dirlist == NULL) {
+               memset(&gl, 0, sizeof(gl));
+               freeglob = 1;
+               if (glob(whichf, GLOB_BRACE|GLOB_QUOTE|GLOB_TILDE, 0, &gl)) {
+                       reply(550, "not found");
+                       goto out;
+               } else if (gl.gl_pathc == 0) {
                        errno = ENOENT;
                        errno = ENOENT;
-                       perror_reply(550, whichfiles);
-                       return;
+                       perror_reply(550, whichf);
+                       goto out;
                }
                }
+               dirlist = gl.gl_pathv;
        } else {
        } else {
-               onefile[0] = whichfiles;
+               onefile[0] = whichf;
                dirlist = onefile;
                simple = 1;
        }
 
        if (setjmp(urgcatch)) {
                transflag = 0;
                dirlist = onefile;
                simple = 1;
        }
 
        if (setjmp(urgcatch)) {
                transflag = 0;
-               return;
+               goto out;
        }
        while (dirname = *dirlist++) {
                if (stat(dirname, &st) < 0) {
        }
        while (dirname = *dirlist++) {
                if (stat(dirname, &st) < 0) {
@@ -1269,29 +1443,30 @@ send_file_list(whichfiles)
                        if (dirname[0] == '-' && *dirlist == NULL &&
                            transflag == 0) {
                                retrieve("/bin/ls %s", dirname);
                        if (dirname[0] == '-' && *dirlist == NULL &&
                            transflag == 0) {
                                retrieve("/bin/ls %s", dirname);
-                               return;
+                               goto out;
                        }
                        }
-                       perror_reply(550, whichfiles);
+                       perror_reply(550, whichf);
                        if (dout != NULL) {
                                (void) fclose(dout);
                                transflag = 0;
                                data = -1;
                                pdata = -1;
                        }
                        if (dout != NULL) {
                                (void) fclose(dout);
                                transflag = 0;
                                data = -1;
                                pdata = -1;
                        }
-                       return;
+                       goto out;
                }
 
                }
 
-               if ((st.st_mode&S_IFMT) == S_IFREG) {
+               if (S_ISREG(st.st_mode)) {
                        if (dout == NULL) {
                                dout = dataconn("file list", (off_t)-1, "w");
                                if (dout == NULL)
                        if (dout == NULL) {
                                dout = dataconn("file list", (off_t)-1, "w");
                                if (dout == NULL)
-                                       return;
+                                       goto out;
                                transflag++;
                        }
                                transflag++;
                        }
-                       fprintf(dout, "%s\n", dirname);
+                       fprintf(dout, "%s%s\n", dirname,
+                               type == TYPE_A ? "\r" : "");
                        byte_count += strlen(dirname) + 1;
                        continue;
                        byte_count += strlen(dirname) + 1;
                        continue;
-               } else if ((st.st_mode&S_IFMT) != S_IFDIR)
+               } else if (!S_ISDIR(st.st_mode))
                        continue;
 
                if ((dirp = opendir(dirname)) == NULL)
                        continue;
 
                if ((dirp = opendir(dirname)) == NULL)
@@ -1313,18 +1488,20 @@ send_file_list(whichfiles)
                         * not a directory or special file.
                         */
                        if (simple || (stat(nbuf, &st) == 0 &&
                         * not a directory or special file.
                         */
                        if (simple || (stat(nbuf, &st) == 0 &&
-                           (st.st_mode&S_IFMT) == S_IFREG)) {
+                           S_ISREG(st.st_mode))) {
                                if (dout == NULL) {
                                        dout = dataconn("file list", (off_t)-1,
                                                "w");
                                        if (dout == NULL)
                                if (dout == NULL) {
                                        dout = dataconn("file list", (off_t)-1,
                                                "w");
                                        if (dout == NULL)
-                                               return;
+                                               goto out;
                                        transflag++;
                                }
                                if (nbuf[0] == '.' && nbuf[1] == '/')
                                        transflag++;
                                }
                                if (nbuf[0] == '.' && nbuf[1] == '/')
-                                       fprintf(dout, "%s\n", &nbuf[2]);
+                                       fprintf(dout, "%s%s\n", &nbuf[2],
+                                               type == TYPE_A ? "\r" : "");
                                else
                                else
-                                       fprintf(dout, "%s\n", nbuf);
+                                       fprintf(dout, "%s%s\n", nbuf,
+                                               type == TYPE_A ? "\r" : "");
                                byte_count += strlen(nbuf) + 1;
                        }
                }
                                byte_count += strlen(nbuf) + 1;
                        }
                }
@@ -1343,25 +1520,39 @@ send_file_list(whichfiles)
                (void) fclose(dout);
        data = -1;
        pdata = -1;
                (void) fclose(dout);
        data = -1;
        pdata = -1;
+out:
+       if (freeglob) {
+               freeglob = 0;
+               globfree(&gl);
+       }
 }
 
 #ifdef SETPROCTITLE
 /*
 }
 
 #ifdef SETPROCTITLE
 /*
- * clobber argv so ps will show what we're doing.
- * (stolen from sendmail)
- * warning, since this is usually started from inetd.conf, it
- * often doesn't have much of an environment or arglist to overwrite.
+ * Clobber argv so ps will show what we're doing.  (Stolen from sendmail.)
+ * Warning, since this is usually started from inetd.conf, it often doesn't
+ * have much of an environment or arglist to overwrite.
  */
  */
-
-/*VARARGS1*/
-setproctitle(fmt, a, b, c)
-char *fmt;
+void
+#if __STDC__
+setproctitle(const char *fmt, ...)
+#else
+setproctitle(fmt, va_alist)
+       char *fmt;
+        va_dcl
+#endif
 {
 {
-       register char *p, *bp, ch;
-       register int i;
-       char buf[BUFSIZ];
+       int i;
+       va_list ap;
+       char *p, *bp, ch;
+       char buf[LINE_MAX];
 
 
-       (void) sprintf(buf, fmt, a, b, c);
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)vsnprintf(buf, sizeof(buf), fmt, ap);
 
        /* make ps print our process name */
        p = Argv[0];
 
        /* make ps print our process name */
        p = Argv[0];