summaryrefslogtreecommitdiff
path: root/libexec/ftpd
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-11-14 20:27:02 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2000-11-14 20:27:02 +0000
commit8ab39446f715fe46cc5f457c3c652fbf776d8e35 (patch)
tree91602b21699761e26d7aff16390d8f7bfd44ce04 /libexec/ftpd
parent87b4863a111bc9fb81fdd1fa9a4478f5fc939bb7 (diff)
cleanup EPSV/EPRT error handling. avoid possible memory leak (getaddrinfo).
correct error code on unsupported protocol parameter against EPRT (522).
Diffstat (limited to 'libexec/ftpd')
-rw-r--r--libexec/ftpd/extern.h6
-rw-r--r--libexec/ftpd/ftpcmd.y110
-rw-r--r--libexec/ftpd/ftpd.c213
3 files changed, 200 insertions, 129 deletions
diff --git a/libexec/ftpd/extern.h b/libexec/ftpd/extern.h
index cd92578a36a..131164b1f68 100644
--- a/libexec/ftpd/extern.h
+++ b/libexec/ftpd/extern.h
@@ -79,7 +79,13 @@ void makedir __P((char *));
void nack __P((char *));
void pass __P((char *));
void passive __P((void));
+int lpsvproto2af __P((int));
+int af2lpsvproto __P((int));
+int epsvproto2af __P((int));
+int af2epsvproto __P((int));
void long_passive __P((char *, int));
+int extended_port __P((const char *));
+void epsv_protounsupp __P((const char *));
void perror_reply __P((int, char *));
void pwd __P((void));
void removedir __P((char *));
diff --git a/libexec/ftpd/ftpcmd.y b/libexec/ftpd/ftpcmd.y
index 1631f12520c..1ec6ab95af2 100644
--- a/libexec/ftpd/ftpcmd.y
+++ b/libexec/ftpd/ftpcmd.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftpcmd.y,v 1.23 2000/11/13 16:14:44 itojun Exp $ */
+/* $OpenBSD: ftpcmd.y,v 1.24 2000/11/14 20:27:01 itojun Exp $ */
/* $NetBSD: ftpcmd.y,v 1.7 1996/04/08 19:03:11 jtc Exp $ */
/*
@@ -47,7 +47,7 @@
#if 0
static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94";
#else
-static char rcsid[] = "$OpenBSD: ftpcmd.y,v 1.23 2000/11/13 16:14:44 itojun Exp $";
+static char rcsid[] = "$OpenBSD: ftpcmd.y,v 1.24 2000/11/14 20:27:01 itojun Exp $";
#endif
#endif /* not lint */
@@ -235,93 +235,8 @@ cmd
| EPRT check_login_epsvall SP STRING CRLF
{
- char *tmp = NULL;
- char *result[3];
- char *p, *q;
- char delim;
- struct addrinfo hints;
- struct addrinfo *res;
- int i;
-
- if ($2) { /* XXX indentation */
-
- if (epsvall) {
- reply(501, "EPRT disallowed after EPSV ALL");
- goto eprt_done;
- }
- usedefault = 0;
- if (pdata >= 0) {
- (void) close(pdata);
- pdata = -1;
- }
-
- /*XXX checks for login */
-
- tmp = strdup($4);
- if (!tmp) {
- fatal("not enough core.");
- /*NOTREACHED*/
- }
- p = tmp;
- delim = p[0];
- p++;
- memset(result, 0, sizeof(result));
- for (i = 0; i < 3; i++) {
- q = strchr(p, delim);
- if (!q || *q != delim) {
- parsefail:
- reply(500, "Invalid argument, rejected.");
- if (tmp)
- free(tmp);
- usedefault = 1;
- goto eprt_done;
- }
- *q++ = '\0';
- result[i] = p;
- p = q;
- }
-
- /* some more sanity check */
- p = result[0];
- while (*p) {
- if (!isdigit(*p))
- goto parsefail;
- p++;
- }
- p = result[2];
- while (*p) {
- if (!isdigit(*p))
- goto parsefail;
- p++;
- }
-
- memset(&hints, 0, sizeof(hints));
- if (atoi(result[0]) == 1)
- hints.ai_family = PF_INET;
- if (atoi(result[0]) == 2)
- hints.ai_family = PF_INET6;
- else
- hints.ai_family = PF_UNSPEC; /*XXX*/
- hints.ai_socktype = SOCK_STREAM;
- if (getaddrinfo(result[1], result[2], &hints, &res))
- goto parsefail;
- memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
- if (his_addr.su_family == AF_INET6 &&
- data_dest.su_family == AF_INET6) {
- /* XXX more sanity checks! */
- data_dest.su_sin6.sin6_scope_id =
- his_addr.su_sin6.sin6_scope_id;
- }
- free(tmp);
- tmp = NULL;
- if (pdata >= 0) {
- (void) close(pdata);
- pdata = -1;
- }
- reply(200, "EPRT command successful.");
- eprt_done:;
-
- }
+ if ($2)
+ extended_port($4);
}
| PASV check_login_epsvall CRLF
@@ -336,21 +251,8 @@ cmd
}
| EPSV check_login SP NUMBER CRLF
{
- int pf;
- if ($2) {
- switch ($4) {
- case 1:
- pf = PF_INET;
- break;
- case 2:
- pf = PF_INET6;
- break;
- default:
- pf = -1; /*junk*/
- break;
- }
- long_passive("EPSV", pf);
- }
+ if ($2)
+ long_passive("EPSV", epsvproto2af($4));
}
| EPSV check_login SP ALL CRLF
{
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 0d1a817b7d0..d1f93705ff3 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftpd.c,v 1.79 2000/09/15 07:13:45 deraadt Exp $ */
+/* $OpenBSD: ftpd.c,v 1.80 2000/11/14 20:27:01 itojun Exp $ */
/* $NetBSD: ftpd.c,v 1.15 1995/06/03 22:46:47 mycroft Exp $ */
/*
@@ -2179,6 +2179,61 @@ pasv_error:
}
/*
+ * convert protocol identifier to/from AF
+ */
+int
+lpsvproto2af(int proto)
+{
+
+ switch (proto) {
+ case 4: return AF_INET;
+#ifdef INET6
+ case 6: return AF_INET6;
+#endif
+ default: return -1;
+ }
+}
+
+int
+af2lpsvproto(int af)
+{
+
+ switch (af) {
+ case AF_INET: return 4;
+#ifdef INET6
+ case AF_INET6: return 6;
+#endif
+ default: return -1;
+ }
+}
+
+int
+epsvproto2af(int proto)
+{
+
+ switch (proto) {
+ case 1: return AF_INET;
+#ifdef INET6
+ case 2: return AF_INET6;
+#endif
+ default: return -1;
+ }
+}
+
+int
+af2epsvproto(int af)
+{
+
+ switch (af) {
+ case AF_INET: return 1;
+#ifdef INET6
+ case AF_INET6: return 2;
+#endif
+ default: return -1;
+ }
+}
+
+/*
* 228 Entering Long Passive Mode (af, hal, h1, h2, h3,..., pal, p1, p2...)
* 229 Entering Extended Passive Mode (|||port|)
*/
@@ -2194,31 +2249,17 @@ long_passive(char *cmd, int pf)
return;
}
- if (pf != PF_UNSPEC) {
- if (ctrl_addr.su_family != pf) {
- switch (ctrl_addr.su_family) {
- case AF_INET:
- pf = 1;
- break;
- case AF_INET6:
- pf = 2;
- break;
- default:
- pf = 0;
- break;
- }
- /*
- * XXX
- * only EPRT/EPSV ready clients will understand this
- */
- if (strcmp(cmd, "EPSV") == 0 && pf) {
- reply(522, "Network protocol mismatch, "
- "use (%d)", pf);
- } else
- reply(501, "Network protocol mismatch"); /*XXX*/
+ if (pf != PF_UNSPEC && ctrl_addr.su_family != pf) {
+ /*
+ * XXX
+ * only EPRT/EPSV ready clients will understand this
+ */
+ if (strcmp(cmd, "EPSV") != 0)
+ reply(501, "Network protocol mismatch"); /*XXX*/
+ else
+ epsv_protounsupp("Network protocol mismatch");
- return;
- }
+ return;
}
if (pdata >= 0)
@@ -2312,6 +2353,128 @@ long_passive(char *cmd, int pf)
}
/*
+ * EPRT |proto|addr|port|
+ */
+int
+extended_port(const char *arg)
+{
+ char *tmp = NULL;
+ char *result[3];
+ char *p, *q;
+ char delim;
+ struct addrinfo hints;
+ struct addrinfo *res = NULL;
+ int i;
+ unsigned long proto;
+
+ if (epsvall) {
+ reply(501, "EPRT disallowed after EPSV ALL");
+ return -1;
+ }
+
+ usedefault = 0;
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+
+ tmp = strdup(arg);
+ if (!tmp) {
+ fatal("not enough core.");
+ /*NOTREACHED*/
+ }
+ p = tmp;
+ delim = p[0];
+ p++;
+ memset(result, 0, sizeof(result));
+ for (i = 0; i < 3; i++) {
+ q = strchr(p, delim);
+ if (!q || *q != delim)
+ goto parsefail;
+ *q++ = '\0';
+ result[i] = p;
+ p = q;
+ }
+
+ /* some more sanity check */
+ p = NULL;
+ (void)strtoul(result[2], &p, 10);
+ if (!*result[2] || *p)
+ goto protounsupp;
+ p = NULL;
+ proto = strtoul(result[0], &p, 10);
+ if (!*result[0] || *p)
+ goto protounsupp;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = epsvproto2af((int)proto);
+ if (hints.ai_family < 0)
+ goto protounsupp;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST; /*no DNS*/
+ if (getaddrinfo(result[1], result[2], &hints, &res))
+ goto parsefail;
+ if (res->ai_next)
+ goto parsefail;
+ if (sizeof(data_dest) < res->ai_addrlen)
+ goto parsefail;
+ memcpy(&data_dest, res->ai_addr, res->ai_addrlen);
+ if (his_addr.su_family == AF_INET6 &&
+ data_dest.su_family == AF_INET6) {
+ /* XXX more sanity checks! */
+ data_dest.su_sin6.sin6_scope_id =
+ his_addr.su_sin6.sin6_scope_id;
+ }
+ if (pdata >= 0) {
+ (void) close(pdata);
+ pdata = -1;
+ }
+ reply(200, "EPRT command successful.");
+
+ if (tmp)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return 0;
+
+parsefail:
+ reply(500, "Invalid argument, rejected.");
+ usedefault = 1;
+ if (tmp)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return -1;
+
+protounsupp:
+ epsv_protounsupp("Protocol not supported");
+ usedefault = 1;
+ if (tmp)
+ free(tmp);
+ if (res)
+ freeaddrinfo(res);
+ return -1;
+}
+
+/*
+ * 522 Protocol not supported (proto,...)
+ * as we assume address family for control and data connections are the same,
+ * we do not return the list of address families we support - instead, we
+ * return the address family of the control connection.
+ */
+void
+epsv_protounsupp(const char *message)
+{
+ int proto;
+
+ proto = af2epsvproto(ctrl_addr.su_family);
+ if (proto < 0)
+ reply(501, "%s", message); /*XXX*/
+ else
+ reply(522, "%s, use (%d)", message, proto);
+}
+
+/*
* Generate unique name for file with basename "local".
* The file named "local" is already known to exist.
* Generates failure reply on error.