summaryrefslogtreecommitdiffstats
path: root/libexec/ftpd
diff options
context:
space:
mode:
authoryar <yar@FreeBSD.org>2003-02-04 17:50:38 +0000
committeryar <yar@FreeBSD.org>2003-02-04 17:50:38 +0000
commit92b68c76468d0d53c9e24c28d2e8095beb711a75 (patch)
tree80264f18f20defbb32908ad168f043399925b4a9 /libexec/ftpd
parent21f12932c485a7565c0a491c72f751f6236581cb (diff)
downloadFreeBSD-src-92b68c76468d0d53c9e24c28d2e8095beb711a75.zip
FreeBSD-src-92b68c76468d0d53c9e24c28d2e8095beb711a75.tar.gz
Let tilde expansion be done even if a file/directory doesn't exist yet.
This makes such natural commands as "MKD ~user/newdir" or "STOR ~/newfile" do what they are supposed to instead of failing miserably with the "File not found" error. This involves a bit of code reorganization. Namely, the code doing glob(3) expansion has been separated to a function; a new function has been introduced to do tilde expansion; the latter function is invoked on a pathname before the former one. Thus behaviour mimicing that of the Bourne shell has been achieved.
Diffstat (limited to 'libexec/ftpd')
-rw-r--r--libexec/ftpd/ftpcmd.y133
1 files changed, 98 insertions, 35 deletions
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index b74c1fd..c9d5263 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -964,43 +964,24 @@ mode_code
pathname
: pathstring
{
- /*
- * Problem: this production is used for all pathname
- * processing, but only gives a 550 error reply.
- * This is a valid reply in some cases but not in others.
- */
if (logged_in && $1) {
- glob_t gl;
- char *p, **pp;
- int flags =
- GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
- int n;
-
- memset(&gl, 0, sizeof(gl));
- flags |= GLOB_LIMIT;
- gl.gl_matchc = MAXGLOBARGS;
- if (glob($1, flags, NULL, &gl) ||
- gl.gl_pathc == 0) {
- reply(550, "wildcard expansion error");
+ char *p;
+
+ /*
+ * Expand ~user manually since glob(3)
+ * will return the unexpanded pathname
+ * if the corresponding file/directory
+ * doesn't exist yet. Using sole glob(3)
+ * would break natural commands like
+ * MKD ~user/newdir
+ * or
+ * RNTO ~/newfile
+ */
+ if ((p = exptilde($1)) != NULL) {
+ $$ = expglob(p);
+ free(p);
+ } else
$$ = NULL;
- } else {
- n = 0;
- for (pp = gl.gl_pathv; *pp; pp++)
- if (strcspn(*pp, "\r\n") ==
- strlen(*pp)) {
- p = *pp;
- n++;
- }
- if (n == 0)
- $$ = strdup($1);
- else if (n == 1)
- $$ = strdup(p);
- else {
- reply(550, "ambiguous");
- $$ = NULL;
- }
- }
- globfree(&gl);
free($1);
} else
$$ = $1;
@@ -1158,6 +1139,8 @@ struct tab sitetab[] = {
};
static char *copy(char *);
+static char *expglob(char *);
+static char *exptilde(char *);
static void help(struct tab *, char *);
static struct tab *
lookup(struct tab *, char *);
@@ -1669,6 +1652,86 @@ check_login1(void)
}
}
+/*
+ * Replace leading "~user" in a pathname by the user's login directory.
+ * Returned string will be in a freshly malloced buffer unless it's NULL.
+ */
+static char *
+exptilde(char *s)
+{
+ char *p, *q;
+ char *path, *user;
+ struct passwd *ppw;
+
+ if ((p = strdup(s)) == NULL)
+ return (NULL);
+ if (*p != '~')
+ return (p);
+
+ user = p + 1; /* skip tilde */
+ if ((path = strchr(p, '/')) != NULL)
+ *(path++) = '\0'; /* separate ~user from the rest of path */
+ ppw = *user ? getpwnam(user) : pw;
+ if (ppw) {
+ /* user found, substitute login directory for ~user */
+ if (path)
+ asprintf(&q, "%s/%s", ppw->pw_dir, path);
+ else
+ q = strdup(ppw->pw_dir);
+ free(p);
+ p = q;
+ } else {
+ /* user not found, undo the damage */
+ if (path)
+ path[-1] = '/';
+ }
+ return (p);
+}
+
+/*
+ * Expand glob(3) patterns possibly present in a pathname.
+ * Avoid expanding to a pathname including '\r' or '\n' in order to
+ * not disrupt the FTP protocol.
+ * The expansion found must be unique.
+ * Return the result as a malloced string, or NULL if an error occured.
+ *
+ * Problem: this production is used for all pathname
+ * processing, but only gives a 550 error reply.
+ * This is a valid reply in some cases but not in others.
+ */
+static char *
+expglob(char *s)
+{
+ char *p, **pp, *rval;
+ int flags = GLOB_BRACE | GLOB_NOCHECK;
+ int n;
+ glob_t gl;
+
+ memset(&gl, 0, sizeof(gl));
+ flags |= GLOB_LIMIT;
+ gl.gl_matchc = MAXGLOBARGS;
+ if (glob(s, flags, NULL, &gl) == 0 && gl.gl_pathc != 0) {
+ for (pp = gl.gl_pathv, p = NULL, n = 0; *pp; pp++)
+ if (*(*pp + strcspn(*pp, "\r\n")) == '\0') {
+ p = *pp;
+ n++;
+ }
+ if (n == 0)
+ rval = strdup(s);
+ else if (n == 1)
+ rval = strdup(p);
+ else {
+ reply(550, "ambiguous");
+ rval = NULL;
+ }
+ } else {
+ reply(550, "wildcard expansion error");
+ rval = NULL;
+ }
+ globfree(&gl);
+ return (rval);
+}
+
#ifdef INET6
/* Return 1, if port check is done. Return 0, if not yet. */
static int
OpenPOWER on IntegriCloud