proxy_ftp.c revision ec69fc6e323eb1f3112966e06e9e37be608d052c
f743002678eb67b99bbc29fee116b65d9530fec0wrowe/* ====================================================================
80833bb9a1bf25dcf19e814438a4b311d2e1f4cffuankg * The Apache Software License, Version 1.1
793214f67dede32edfd9ee96c664ead04d175cbbjfclere * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
cc5a4a08dc9783fcbc52ce86f11e01c281a43810minfrin * reserved.
aba55cd5d565f6f00a3d0e17c5724fdd3a50827ftrawick * Redistribution and use in source and binary forms, with or without
aba55cd5d565f6f00a3d0e17c5724fdd3a50827ftrawick * modification, are permitted provided that the following conditions
33124689065ade0dfc8c54d8ebb734f9439cb89btrawick * 1. Redistributions of source code must retain the above copyright
3ccfc257819b3bad063cd3ac9dd1670d5d2ae4d2kbrand * notice, this list of conditions and the following disclaimer.
3ccfc257819b3bad063cd3ac9dd1670d5d2ae4d2kbrand * 2. Redistributions in binary form must reproduce the above copyright
3ccfc257819b3bad063cd3ac9dd1670d5d2ae4d2kbrand * notice, this list of conditions and the following disclaimer in
85af5dafbbd8ae9f496e4349ec0d7b0411439a71trawick * the documentation and/or other materials provided with the
85af5dafbbd8ae9f496e4349ec0d7b0411439a71trawick * distribution.
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * 3. The end-user documentation included with the redistribution,
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * if any, must include the following acknowledgment:
9b0076ddd1103e5fa9c1f9bafde4b06ce244fbaecovener * "This product includes software developed by the
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * Apache Software Foundation (http://www.apache.org/)."
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * Alternately, this acknowledgment may appear in the software itself,
249d09d51808cb7981af99762c3b3736ca126cd5jkaluza * if and wherever such third-party acknowledgments normally appear.
56589be3d7a3e9343370df240010c6928cc78b39jkaluza * 4. The names "Apache" and "Apache Software Foundation" must
56589be3d7a3e9343370df240010c6928cc78b39jkaluza * not be used to endorse or promote products derived from this
56589be3d7a3e9343370df240010c6928cc78b39jkaluza * software without prior written permission. For written
8c4967445b49a1612b3f98c1dada65e597ecfe26trawick * permission, please contact apache@apache.org.
8c4967445b49a1612b3f98c1dada65e597ecfe26trawick * 5. Products derived from this software may not be called "Apache",
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * nor may "Apache" appear in their name, without prior written
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * permission of the Apache Software Foundation.
61fefed8ce5211c31b44f3a38a6e76ca055e5780trawick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
6001d914962deabb83a46251001612e969bdf67ajim * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
6001d914962deabb83a46251001612e969bdf67ajim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
6001d914962deabb83a46251001612e969bdf67ajim * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
c4e8006db0cf457c68876d7d4c30dcc451d8cba7jkaluza * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
652bacc79dd7f980249784cc8c4838e8f1de7e8acovener * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
f4db898517ccc6ef1a403630de56918286d3a47eminfrin * SUCH DAMAGE.
f4db898517ccc6ef1a403630de56918286d3a47eminfrin * ====================================================================
28a723b775c7666281298eab813c63ac42270f95humbedooh * This software consists of voluntary contributions made by many
28a723b775c7666281298eab813c63ac42270f95humbedooh * individuals on behalf of the Apache Software Foundation. For more
28a723b775c7666281298eab813c63ac42270f95humbedooh * information on the Apache Software Foundation, please see
067698ad30941e38ef5d7f95f1c2736c2ebc5cb9humbedooh * Portions of this software are based upon public domain software
7a437ce535a5fac890296402ba483c2f41bb6500trawick * originally written at the National Center for Supercomputing Applications,
7a437ce535a5fac890296402ba483c2f41bb6500trawick * University of Illinois, Urbana-Champaign.
6e1e45624d6f32110383bb0bd06c254c1dba8123humbedooh/* FTP routines for Apache proxy */
3e097af23e40c45aa32602545155f0964ab5c69dcovener/* Automatic timestamping (Last-Modified header) based on MDTM is used if:
3e097af23e40c45aa32602545155f0964ab5c69dcovener * 1) the FTP server supports the MDTM command and
3e097af23e40c45aa32602545155f0964ab5c69dcovener * 2) HAVE_TIMEGM (preferred) or HAVE_GMTOFF is available at compile time
344f755169e100ea8ce51e847a0bf30a13b46917covenerint ap_proxy_ftp_handler(request_rec *r, proxy_server_conf *conf,
fcd5c4e9e126e867eb270ed2d4138348cb1e46e5trawickapr_status_t ap_proxy_send_dir_filter(ap_filter_t * f,
5cb0075c38fc868730c4981e346845dad6c7ea58chrisd * Decodes a '%' escaped string, and returns the number of characters
5cb0075c38fc868730c4981e346845dad6c7ea58chrisdstatic int decodeenc(char *x)
ffaa9771884a8664f0e6267efbe9d26b40000461trawick if (x[0] == '\0')
ffaa9771884a8664f0e6267efbe9d26b40000461trawick return 0; /* special case for no characters */
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
f87299dab99bc04b51a6b8cad51b6795db862c0atrawick /* decode it if not already done */
4d12805e6c18253040223ea637acd6b3b3c18f60jorton if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
a4df2cd1e1391575a327c2a90ba4315f805a0a78covener x[j] = '\0';
cb666b29f81df1d11d65002250153353568021fccovener * Escape the globbing characters in a path used as argument to
6a80c3c6f4b8ea7ba5e89402b8b779b09ce020e0covener * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
1c2cab00d988fc48cbe59032cf76cc0bab20d6f7covener * ftpd assumes '\\' as a quoting character to escape special characters.
6a80c3c6f4b8ea7ba5e89402b8b779b09ce020e0covener * Returns: escaped string
75a230a728338d84dcfe81edd375352f34de22d0covenerstatic char *ftp_escape_globbingchars(apr_pool_t *p, const char *path)
1f50dc34ae069adeed20b2986e5ffdefa5c410e0covener char *ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
63a5ea80bddcc84a462e40f402b4f330e0e05411covener *d++ = '\\';
65a4e663b82f8bce28ac22ab2edfd7502de36998sf * Check for globbing characters in a path used as argument to
c7de1955eb0eaeabf7042902476397692672d549sf * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
509622419be000045d461ef38fb97df778fdf81djailletc * ftpd assumes '\\' as a quoting character to escape special characters.
509622419be000045d461ef38fb97df778fdf81djailletc * Returns: 0 (no globbing chars, or all globbing chars escaped), 1 (globbing chars)
509622419be000045d461ef38fb97df778fdf81djailletcstatic int ftp_check_globbingchars(const char *path)
74e7f6c55fd67b10cb400b3f6d1dc718a303d944minfrin if (path != '\0' && strchr(FTP_GLOBBING_CHARS, *path) != NULL)
a511a29faf2ff7ead3b67680154a624effb31aafminfrin * checks an encoded ftp string for bad characters, namely, CR, LF or
a511a29faf2ff7ead3b67680154a624effb31aafminfrin * non-ascii character
63921358ef93fcb41bc71d9894221ba3d7fbb87bminfrinstatic int ftp_check_string(const char *x)
deec48c67d4786bc77112ffbf3a4e70b931097edminfrin int i, ch = 0;
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esf for (i = 0; x[i] != '\0'; i++) {
4c02bab56a528a180bbe394d8b6e6fd9c1a3ac1esf if (ch == '%' && apr_isxdigit(x[i + 1]) && apr_isxdigit(x[i + 2])) {
05a5a9c3e16f21566e1b61f4bd68025ce1b741ccjoes#else /* APR_CHARSET_EBCDIC */
ef82e8fa164e0a1f8b813f7deb6b7ead96018c94niq#endif /* APR_CHARSET_EBCDIC */
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf * Canonicalise ftp URLs.
eafcc0ebf263d0ba69855b6e10958c4c1a2361bdsf char *user, *password, *host, *path, *parms, *strp, sport[7];
d7ffd2da16d58b1a0de212e4d56f7aebb72bef26sf const char *err;
bd3f5647b96d378d9c75c954e3f13582af32c643sf err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port);
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sf /* now parse path/parameters args, according to rfc1738 */
f21e9e3d0bfb7a507ecc5bc963f2159d693503d1sf * N.B. if this isn't a true proxy request, then the URL path (but not
f6b9c755a0b793e8a3a3aebd327ca20a86478117sf * query args) has already been decoded. This gives rise to the problem
f6b9c755a0b793e8a3a3aebd327ca20a86478117sf * of a ; being decoded into the path.
85eacfc96a04547ef25aabbc06440039715084c2jorton parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm,
79c5787b92ac5f0e1cc82393816c77a006399316trawick path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
79c5787b92ac5f0e1cc82393816c77a006399316trawick strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
536e48c08d674acac5d44929318f2ad928edc361jorton strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
53e9b27aba029b18be814df40bcf6f0428771d1efuankg/* now, rebuild URL */
e6dd71992459d05a676b98b7963423dc5dc1e24aminfrin r->filename = apr_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "",
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung/* we chop lines longer than 80 characters */
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung * Reads response lines, returns both the ftp status code and
ec7520b24cd80d34d82bbcaca153cbb23cc04bc0rjung * remembers the response message in the supplied buffer
6249dfa569d3b4f1f539665b979a80c6e335d93etrawickstatic int ftp_getrc_msg(conn_rec *ftp_ctrl, apr_bucket_brigade *bb, char *msgbuf, int msglen)
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim if (APR_SUCCESS != (rv = ap_proxy_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) {
74499a117b3b2cd9666715a14f90c0e5d1a4ee8ajim ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
cfa64348224b66dd1c9979b809406c4d15b1c137fielding "proxy: <FTP: %s", response);
status = 0;
return status;
} state;
request_rec *r = f->r;
if (!ctx) {
++path;
/* print "ftp://host/" */
p, c->bucket_alloc));
++reldir;
++dir;
c->bucket_alloc));
c->bucket_alloc));
p, c->bucket_alloc));
if (readme) {
c->bucket_alloc));
return rv;
char *filename;
int found = 0;
int eos = 0;
apr_bucket *e;
if (APR_BUCKET_IS_EOS(e)) {
return rv;
if (eos) {
if (!found) {
return APR_SUCCESS;
filename--;
else if (ctx->buffer[0] == 'd' || ctx->buffer[0] == '-' || ctx->buffer[0] == 'l' || apr_isdigit(ctx->buffer[0])) {
int searchidx = 0;
firstfile = 0;
filename = apr_pstrndup(p, &ctx->buffer[re_result[2].rm_so], re_result[2].rm_eo - re_result[2].rm_so);
c->bucket_alloc));
return rv;
c->bucket_alloc));
return rv;
return APR_SUCCESS;
char *crlf;
int rc;
return rc;
int rc;
return ret;
return cwd;
* ftp://user@host part of the reqest (sans password -if supplied but invalid-)
if (log_it)
return HTTP_UNAUTHORIZED;
int err;
int dirlisting = 0;
if (proxyhost) {
if (!backend) {
return HTTP_NOT_IMPLEMENTED;
while (connect_addr) {
failed = 0;
if (failed) {
if (!origin) {
return HTTP_INTERNAL_SERVER_ERROR;
while (*secs_str)
return ftp_unauthorized(r, 0);
++path;
* We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
char *data_ip;
char *pstr;
char *tok_cntx;
if (pstr) {
if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
if (!connect) {
char *pstr;
char *tok_cntx;
if ((rv = apr_socket_create(&data_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
apr_sockaddr_info_get(&pasv_addr, apr_psprintf(p, "%d.%d.%d.%d", h3, h2, h1, h0), connect_addr->family, pasvport, 0, p);
if (!connect) {
char *local_ip;
if ((rv = apr_socket_create(&local_sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
!= APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
return ap_proxyerror(r, HTTP_NOT_IMPLEMENTED, "Connect to IPV6 ftp server using EPRT not supported. Enable EPSV.");
/* from draft-ietf-ftpext-mlst-14.txt:
len = 0;
if (dirlisting) {
* queries like: ftp://user@host/apache/src/server/http_*.c
if (len != 0)
/* from draft-ietf-ftpext-mlst-14.txt:
* YYYYMMDDHHMMSS.sss
} time_val;
mtime = 0L;
/* rc is an intermediate response for the LIST command (125 transfer starting, 150 opening data connection) */
if (dirlisting) {
if (r->content_type) {
if (mtime != 0L) {
* @@@ FIXME (e.g., for ftp://user@host/file*.tar.gz,
if (use_port) {
return HTTP_BAD_GATEWAY;
if (!data) {
return HTTP_INTERNAL_SERVER_ERROR;
if (dirlisting) {
if (!r->header_only) {
apr_bucket *e;
bb,
#if DEBUGGING
if (data_sock) {
if (origin_sock) {
return OK;