diff options
author | joerg <joerg@pkgsrc.org> | 2010-03-21 16:48:42 +0000 |
---|---|---|
committer | joerg <joerg@pkgsrc.org> | 2010-03-21 16:48:42 +0000 |
commit | a9575b4a73cb78c23ef26a6f17153da465e2086b (patch) | |
tree | 6211a32fe98465f7d2349355551748ae410696f5 /net | |
parent | f437aa96800c3b8ff05894fc907d6b91e88a56c9 (diff) | |
download | pkgsrc-a9575b4a73cb78c23ef26a6f17153da465e2086b.tar.gz |
libfetch-2.31:
PR 43013 by Brook Milligan: fetch(3) violates RFC 1738 for ftp:// URLs
if the home directory is not the root directory.
Remember the current directory the first time a CWD / CDUP has to be
issued. Use the document as full URL if the URL started with two /
(quoted or not), otherwise append it to the initial directory.
Diffstat (limited to 'net')
-rw-r--r-- | net/libfetch/Makefile | 4 | ||||
-rw-r--r-- | net/libfetch/files/common.c | 4 | ||||
-rw-r--r-- | net/libfetch/files/common.h | 4 | ||||
-rw-r--r-- | net/libfetch/files/ftp.c | 92 |
4 files changed, 77 insertions, 27 deletions
diff --git a/net/libfetch/Makefile b/net/libfetch/Makefile index f527a907e36..97e3b71a71d 100644 --- a/net/libfetch/Makefile +++ b/net/libfetch/Makefile @@ -1,7 +1,7 @@ -# $NetBSD: Makefile,v 1.37 2010/01/23 14:53:08 joerg Exp $ +# $NetBSD: Makefile,v 1.38 2010/03/21 16:48:42 joerg Exp $ # -DISTNAME= libfetch-2.30 +DISTNAME= libfetch-2.31 CATEGORIES= net MASTER_SITES= # empty DISTFILES= # empty diff --git a/net/libfetch/files/common.c b/net/libfetch/files/common.c index fd2c0aa8a68..5be2a8e78ca 100644 --- a/net/libfetch/files/common.c +++ b/net/libfetch/files/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.25 2010/01/24 16:54:23 joerg Exp $ */ +/* $NetBSD: common.c,v 1.26 2010/03/21 16:48:43 joerg Exp $ */ /*- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org> @@ -231,6 +231,7 @@ fetch_reopen(int sd) /* allocate and fill connection structure */ if ((conn = calloc(1, sizeof(*conn))) == NULL) return (NULL); + conn->ftp_home = NULL; conn->cache_url = NULL; conn->next_buf = NULL; conn->next_len = 0; @@ -711,6 +712,7 @@ fetch_close(conn_t *conn) ret = close(conn->sd); if (conn->cache_url) fetchFreeURL(conn->cache_url); + free(conn->ftp_home); free(conn->buf); free(conn); return (ret); diff --git a/net/libfetch/files/common.h b/net/libfetch/files/common.h index 2039aedcdf5..4e4408cb79b 100644 --- a/net/libfetch/files/common.h +++ b/net/libfetch/files/common.h @@ -1,4 +1,4 @@ -/* $NetBSD: common.h,v 1.15 2010/01/23 14:25:26 joerg Exp $ */ +/* $NetBSD: common.h,v 1.16 2010/03/21 16:48:43 joerg Exp $ */ /*- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav * All rights reserved. @@ -73,6 +73,8 @@ struct fetchconn { # endif #endif + char *ftp_home; + struct url *cache_url; int cache_af; int (*cache_close)(conn_t *); diff --git a/net/libfetch/files/ftp.c b/net/libfetch/files/ftp.c index 600222ed6f8..9ef5ac939d4 100644 --- a/net/libfetch/files/ftp.c +++ b/net/libfetch/files/ftp.c @@ -1,4 +1,4 @@ -/* $NetBSD: ftp.c,v 1.34 2010/01/23 14:25:26 joerg Exp $ */ +/* $NetBSD: ftp.c,v 1.35 2010/03/21 16:48:43 joerg Exp $ */ /*- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav * Copyright (c) 2008, 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> @@ -252,7 +252,7 @@ ftp_filename(const char *file, int *len, int *type, int subdir) * command. */ static int -ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen) +ftp_pwd(conn_t *conn, char **pwd) { char *src, *dst, *end; int q; @@ -264,7 +264,10 @@ ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen) src = conn->buf + 4; if (src >= end || *src++ != '"') return (FTP_PROTOCOL_ERROR); - for (q = 0, dst = pwd; src < end && pwdlen--; ++src) { + *pwd = malloc(end - src + 1); + if (*pwd == NULL) + return (FTP_PROTOCOL_ERROR); + for (q = 0, dst = *pwd; src < end; ++src) { if (!q && *src == '"') q = 1; else if (q && *src != '"') @@ -274,9 +277,12 @@ ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen) else *dst++ = *src; } - if (!pwdlen) - return (FTP_PROTOCOL_ERROR); *dst = '\0'; + if (**pwd != '/') { + free(*pwd); + *pwd = NULL; + return (FTP_PROTOCOL_ERROR); + } return (FTP_OK); } @@ -285,69 +291,109 @@ ftp_pwd(conn_t *conn, char *pwd, size_t pwdlen) * file. */ static int -ftp_cwd(conn_t *conn, const char *file, int subdir) +ftp_cwd(conn_t *conn, const char *path, int subdir) { const char *beg, *end; - char pwd[PATH_MAX]; + char *pwd, *dst; int e, i, len; - /* If no slashes in name, no need to change dirs. */ - if (subdir) - end = file + strlen(file); - else if ((end = strrchr(file, '/')) == NULL) - return (0); + if (*path != '/') { + ftp_seterr(501); + return (-1); + } + ++path; + + /* Simple case: still in the home directory and no directory change. */ + if (conn->ftp_home == NULL && strchr(path, '/') == NULL && + (!subdir || *path == '\0')) + return 0; + if ((e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY || - (e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) { + (e = ftp_pwd(conn, &pwd)) != FTP_OK) { ftp_seterr(e); return (-1); } + if (conn->ftp_home == NULL && (conn->ftp_home = strdup(pwd)) == NULL) { + fetch_syserr(); + free(pwd); + return (-1); + } + if (*path == '/') { + while (path[1] == '/') + ++path; + dst = strdup(path); + } else if (strcmp(conn->ftp_home, "/") == 0) { + dst = strdup(path - 1); + } else { + asprintf(&dst, "%s/%s", conn->ftp_home, path); + } + if (dst == NULL) { + fetch_syserr(); + free(pwd); + return (-1); + } + + if (subdir) + end = dst + strlen(dst); + else + end = strrchr(dst, '/'); + for (;;) { len = strlen(pwd); /* Look for a common prefix between PWD and dir to fetch. */ - for (i = 0; i <= len && i <= end - file; ++i) - if (pwd[i] != file[i]) + for (i = 0; i <= len && i <= end - dst; ++i) + if (pwd[i] != dst[i]) break; /* Keep going up a dir until we have a matching prefix. */ if (strcmp(pwd, "/") == 0) break; - if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/')) + if (pwd[i] == '\0' && (dst[i - 1] == '/' || dst[i] == '/')) break; + free(pwd); if ((e = ftp_cmd(conn, "CDUP\r\n")) != FTP_FILE_ACTION_OK || (e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY || - (e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) { + (e = ftp_pwd(conn, &pwd)) != FTP_OK) { ftp_seterr(e); + free(dst); return (-1); } } + free(pwd); #ifdef FTP_COMBINE_CWDS /* Skip leading slashes, even "////". */ - for (beg = file + i; beg < end && *beg == '/'; ++beg, ++i) + for (beg = dst + i; beg < end && *beg == '/'; ++beg, ++i) /* nothing */ ; /* If there is no trailing dir, we're already there. */ - if (beg >= end) + if (beg >= end) { + free(dst); return (0); + } /* Change to the directory all in one chunk (e.g., foo/bar/baz). */ e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(end - beg), beg); - if (e == FTP_FILE_ACTION_OK) + if (e == FTP_FILE_ACTION_OK) { + free(dst); return (0); + } #endif /* FTP_COMBINE_CWDS */ /* That didn't work so go back to legacy behavior (multiple CWDs). */ - for (beg = file + i; beg < end; beg = file + i + 1) { + for (beg = dst + i; beg < end; beg = dst + i + 1) { while (*beg == '/') ++beg, ++i; - for (++i; file + i < end && file[i] != '/'; ++i) + for (++i; dst + i < end && dst[i] != '/'; ++i) /* nothing */ ; - e = ftp_cmd(conn, "CWD %.*s\r\n", file + i - beg, beg); + e = ftp_cmd(conn, "CWD %.*s\r\n", dst + i - beg, beg); if (e != FTP_FILE_ACTION_OK) { + free(dst); ftp_seterr(e); return (-1); } } + free(dst); return (0); } |