Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/libexec/ftpd various fixes suggested by Robert Elz:



details:   https://anonhg.NetBSD.org/src/rev/596a0dda7234
branches:  trunk
changeset: 488144:596a0dda7234
user:      lukem <lukem%NetBSD.org@localhost>
date:      Mon Jun 19 15:15:03 2000 +0000

description:
various fixes suggested by Robert Elz:
* implement closedataconn() and use appropriately (including in mlsd())
* only put leading space in front of MLST output (not MLSD output)
* MLSD: only output pdir and cdir entries when the type fact is requested.
* change error code for giving MLSD a non-directory from 550 to 501
* remove MLSx Type fact support for UNIX.* for now; it's not standardised yet.
* do a check_login when MLSD and MLST are given no args
* detect & complain about null facts in OPTS MLST
* cache getgroups() at login instead of calling each time in fact_perm()

other mods:
* implement cprintf(); as per fprintf() but increments total_bytes{,_out}
* implement CPUTC(); as per putc() but increments total_bytes{,_out}
* implement base64_encode()
* fact_unique() display base64 encoding of dev_t and ino_t rather than
  hex output; should scale if size of those changes
* change reply() so that a negative code acts as the initial line in a reply,
  code == 0 prefixes the line with 4 spaces, and code > 0 works as before.
  deprecate lreply(code, ) and lreply(0, ) in favour of reply(-code, ) and
  reply(0, ) respectively.
* use cprintf() and CPUTC() appropriately (often instead of printf(),
  lreply(-2, ) or lreply(-1, ).
  now we actually account for the data sent by MLST and MLSD.
* remove DEBUG support for sending MLSD output to control connection instead
  of data connection (my ftp client now supports MLSD :-)

diffstat:

 libexec/ftpd/cmds.c    |  249 ++++++++++++++++++++++++------------------------
 libexec/ftpd/conf.c    |   49 ++++-----
 libexec/ftpd/extern.h  |   11 +-
 libexec/ftpd/ftpcmd.y  |   47 +++-----
 libexec/ftpd/ftpd.8    |   18 ++-
 libexec/ftpd/ftpd.c    |  244 ++++++++++++++++++++++-------------------------
 libexec/ftpd/version.h |    4 +-
 7 files changed, 302 insertions(+), 320 deletions(-)

diffs (truncated from 1464 to 300 lines):

diff -r 2f5fed8da8bb -r 596a0dda7234 libexec/ftpd/cmds.c
--- a/libexec/ftpd/cmds.c       Mon Jun 19 14:58:37 2000 +0000
+++ b/libexec/ftpd/cmds.c       Mon Jun 19 15:15:03 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cmds.c,v 1.2 2000/06/16 23:17:41 explorer Exp $        */
+/*     $NetBSD: cmds.c,v 1.3 2000/06/19 15:15:03 lukem Exp $   */
 
 /*
  * Copyright (c) 1999-2000 The NetBSD Foundation, Inc.
@@ -101,7 +101,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: cmds.c,v 1.2 2000/06/16 23:17:41 explorer Exp $");
+__RCSID("$NetBSD: cmds.c,v 1.3 2000/06/19 15:15:03 lukem Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -133,15 +133,13 @@
 } factelem;
 
 static void    ack(const char *);
+static void    base64_encode(const char *, size_t, char *, int);
 static void    fact_type(const char *, FILE *, factelem *);
 static void    fact_size(const char *, FILE *, factelem *);
 static void    fact_modify(const char *, FILE *, factelem *);
 static void    fact_perm(const char *, FILE *, factelem *);
 static void    fact_unique(const char *, FILE *, factelem *);
-static void    fact_unix_group(const char *, FILE *, factelem *);
-static void    fact_unix_mode(const char *, FILE *, factelem *);
-static void    fact_unix_owner(const char *, FILE *, factelem *);
-static int     matchgroup(gid_t, gid_t *, int);
+static int     matchgroup(gid_t);
 static void    mlsname(FILE *, factelem *);
 static void    replydirname(const char *, const char *);
 
@@ -154,13 +152,11 @@
 
 struct ftpfact facttab[] = {
        { "Type",       1, fact_type },
+#define        FACT_TYPE 0
        { "Size",       1, fact_size },
        { "Modify",     1, fact_modify },
        { "Perm",       1, fact_perm },
        { "Unique",     1, fact_unique },
-       { "UNIX.mode",  1, fact_unix_mode },
-       { "UNIX.owner", 0, fact_unix_owner },
-       { "UNIX.group", 0, fact_unix_group },
        /* "Create" */
        /* "Lang" */
        /* "Media-Type" */
@@ -199,16 +195,16 @@
 {
        int i;
 
-       lreply(211, "Features supported");
-       lreply(-1,  " MDTM");
-       lreply(-2,  " MLST ");
+       reply(-211, "Features supported");
+       cprintf(stdout, " MDTM\r\n");
+       cprintf(stdout, " MLST ");
        for (i = 0; facttab[i].name; i++)
-               lreply(-2, "%s%s;", facttab[i].name,
+               cprintf(stdout, "%s%s;", facttab[i].name,
                    facttab[i].enabled ? "*" : "");
-       lreply(-1, "");
-       lreply(-1,  " REST STREAM");
-       lreply(-1,  " SIZE");
-       lreply(-1,  " TVFS");
+       cprintf(stdout, "\r\n");
+       cprintf(stdout, " REST STREAM\r\n");
+       cprintf(stdout, " SIZE\r\n");
+       cprintf(stdout, " TVFS\r\n");
        reply(211,  "End");
 }
 
@@ -228,13 +224,15 @@
 void
 mlsd(const char *path)
 {
-       FILE *dout;
-       DIR *dirp;
-       struct dirent *dp;
-       struct stat sb, pdirstat;
-       char name[MAXPATHLEN];
+       struct dirent   *dp;
+       struct stat      sb, pdirstat;
        factelem f;
+       FILE    *dout;
+       DIR     *dirp;
+       char    name[MAXPATHLEN];
+       int     hastypefact;
 
+       hastypefact = facttab[FACT_TYPE].enabled;
        if (path == NULL)
                path = ".";
        if (stat(path, &pdirstat) == -1) {
@@ -244,53 +242,48 @@
        }
        if (! S_ISDIR(pdirstat.st_mode)) {
                errno = ENOTDIR;
-               goto mlsdperror;
+               perror_reply(501, path);
+               return;
        }
-#ifdef DEBUG           /* send mlsd to ctrl connection not data connection */
-       dout = stdout;
-       lreply(250, "MLSD %s", path);
-#else
        dout = dataconn("MLSD", (off_t)-1, "w");
        if (dout == NULL)
                return;
-#endif
 
        if ((dirp = opendir(path)) == NULL)
                goto mlsdperror;
        f.stat = &sb;
        while ((dp = readdir(dirp)) != NULL) {
                snprintf(name, sizeof(name), "%s/%s", path, dp->d_name);
-/* printf("got >%s< >%s<\n", dp->d_name, name); */
+               if (ISDOTDIR(dp->d_name)) {     /* special case curdir: */
+                       if (! hastypefact)
+                               continue;
+                       f.pdirstat = NULL;      /*   require stat of parent */
+                       f.display = path;       /*   set name to real name */
+                       f.iscurdir = 1;         /*   flag name is curdir */
+               } else {
+                       if (ISDOTDOTDIR(dp->d_name)) {
+                               if (! hastypefact)
+                                       continue;
+                               f.pdirstat = NULL;
+                       } else
+                               f.pdirstat = &pdirstat; /* cache parent stat */
+                       f.display = dp->d_name;
+                       f.iscurdir = 0;
+               }
                if (stat(name, &sb) == -1)
                        continue;
                f.path = name;
-               if (ISDOTDIR(dp->d_name)) {     /* special case curdir: */
-                       f.display = path;       /*   set name to real name */
-                       f.iscurdir = 1;         /*   flag name is curdir */
-                       f.pdirstat = NULL;      /*   require stat of parent */
-               } else {
-                       f.display = dp->d_name;
-                       f.iscurdir = 0;
-                       if (ISDOTDOTDIR(dp->d_name))
-                               f.pdirstat = NULL;
-                       else
-                               f.pdirstat = &pdirstat; /* cache parent stat */
-               }
                mlsname(dout, &f);
        }
        (void)closedir(dirp);
 
-#ifdef DEBUG
-       reply(250, "End");
-#else
        if (ferror(dout) != 0)
                perror_reply(550, "Data connection");
        else
                reply(226, "MLSD complete.");
-       (void) fclose(dout);
+       closedataconn(dout);
        total_xfers_out++;
        total_xfers++;
-#endif
 }
 
 void
@@ -305,12 +298,13 @@
                perror_reply(550, path);
                return;
        }
-       lreply(250, "MLST %s", path);
+       reply(-250, "MLST %s", path);
        f.path = path;
        f.display = path;
        f.stat = &sb;
        f.pdirstat = NULL;
        f.iscurdir = 0;
+       CPUTC(' ', stdout);
        mlsname(stdout, &f);
        reply(250, "End");
 }
@@ -341,37 +335,47 @@
 
                        /* special case: MLST */
        if (strcasecmp(command, "MLST") == 0) {
+               int      enabled[sizeof(facttab) / sizeof(struct ftpfact)];
                int      i, onedone;
+               size_t   len;
                char    *p;
 
-               for (i = 0; facttab[i].name; i++)
-                       facttab[i].enabled = 0;
+               for (i = 0; i < sizeof(enabled) / sizeof(int); i++)
+                       enabled[i] = 0;
                if (ep == NULL || *ep == '\0')
                        goto displaymlstopts;
 
                                /* don't like spaces, and need trailing ; */
-               if (strchr(ep, ' ') != NULL || ep[strlen(ep) - 1] != ';') {
+               len = strlen(ep);
+               if (strchr(ep, ' ') != NULL || ep[len - 1] != ';') {
+ badmlstopt:
                        reply(501, "Invalid MLST options");
                        return;
                }
+               ep[len - 1] = '\0';
                while ((p = strsep(&ep, ";")) != NULL) {
+                       if (*p == '\0')
+                               goto badmlstopt;
                        for (i = 0; facttab[i].name; i++)
                                if (strcasecmp(p, facttab[i].name) == 0) {
-                                       facttab[i].enabled = 1;
+                                       enabled[i] = 1;
                                        break;
                                }
                }
 
  displaymlstopts:
-               lreply(-2, "200 MLST OPTS");
+               for (i = 0; facttab[i].name; i++)
+                       facttab[i].enabled = enabled[i];
+               cprintf(stdout, "200 MLST OPTS");
                for (i = onedone = 0; facttab[i].name; i++) {
                        if (facttab[i].enabled) {
-                               lreply(-2, "%s%s;", onedone ? "" : " ",
+                               cprintf(stdout, "%s%s;", onedone ? "" : " ",
                                    facttab[i].name);
                                onedone++;
                        }
                }
-               lreply(-1, "");
+               cprintf(stdout, "\r\n");
+               fflush(stdout);
                return;
        }
 
@@ -488,7 +492,8 @@
 
        argv[2] = (char *)filename;
        fin = ftpd_popen(argv, "r", STDOUT_FILENO);
-       lreply(211, "status of %s:", filename);
+       reply(-211, "status of %s:", filename);
+/* XXX: use fgetln() or fparseln() here? */
        while ((c = getc(fin)) != EOF) {
                if (c == '\n') {
                        if (ferror(stdout)){
@@ -502,13 +507,9 @@
                                (void) ftpd_pclose(fin);
                                return;
                        }
-                       (void) putchar('\r');
-                       total_bytes++;
-                       total_bytes_out++;
+                       CPUTC('\r', stdout);
                }
-               (void) putchar(c);
-               total_bytes++;
-               total_bytes_out++;
+               CPUTC(c, stdout);
        }
        (void) ftpd_pclose(fin);
        reply(211, "End of Status");
@@ -523,13 +524,40 @@
        reply(250, "%s command successful.", s);
 }
 
+/*
+ * Encode len bytes starting at clear using base64 encoding into encoded,
+ * which should be at least ((len + 2) * 4 / 3 + 1) in size.
+ * If nulterm is non-zero, terminate with \0 else pad to len with `='.
+ */
+static void
+base64_encode(const char *clear, size_t len, char *encoded, int nulterm)
+{
+       static const char enc[] =
+           "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+       char    *cp;
+       int      i;
+
+       cp = encoded;
+       for (i = 0; i < len; i += 3) {
+               *(cp++) = enc[((clear[i + 0] >> 2))];
+               *(cp++) = enc[((clear[i + 0] << 4) & 0x30)
+                           | ((clear[i + 1] >> 4) & 0x0f)];
+               *(cp++) = enc[((clear[i + 1] << 2) & 0x3c)
+                           | ((clear[i + 2] >> 6) & 0x03)];
+               *(cp++) = enc[((clear[i + 2]     ) & 0x3f)];
+       }
+       *cp = '\0';
+       while (i-- > len)
+               *(--cp) = nulterm ? '\0' : '=';
+}
+
 static void
 fact_modify(const char *fact, FILE *fd, factelem *fe)
 {



Home | Main Index | Thread Index | Old Index