View | Details | Raw Unified | Return to bug 46798
Collapse All | Expand All

(-)docs/manual/mod/mod_proxy_ftp.xml (+52 lines)
Lines 144-148 Link Here
144
      </note>
144
      </note>
145
    </section> <!-- /ftppass -->
145
    </section> <!-- /ftppass -->
146
146
147
    <section id="wildcard"><title>Why do I get a file listing when I expected
148
        a file to be downloaded?</title>
149
      <p>In order to allow both browsing the directories on an FTP server and
150
        downloading files, Apache looks at the request URL.  If it looks like
151
        a directory, or contains wildcard characters ("*?[{~"), then it
152
        guesses that a listing is wanted instead of a download.</p>
153
      <p>You can disable the special handling of names with wildcard characters.
154
        See the <directive>ProxyFtpListOnWildcard</directive> directive.
155
      </p>
156
    </section> <!-- /wildcard -->
157
       
158
<directivesynopsis>
159
<name>ProxyFtpListOnWildcard</name>
160
<description>Whether wildcards in requested filenames trigger a file listing</description>
161
<syntax>ProxyFtpListOnWildcard [on|off]</syntax>
162
<default>on</default>
163
<contextlist><context>server config</context><context>virtual host</context>
164
  <context>directory</context></contextlist>
165
<compatibility>Available in Apache xxx and later</compatibility>
147
166
167
<usage>
168
  <p>The <directive>ProxyFtpListOnWildcard</directive> directive
169
    controls whether wildcard characters ("*?[{~") in requested
170
    filenames cause <module>mod_proxy_ftp</module> to return a listing
171
    of files instead of downloading a file.  By default (value on),
172
    they do.  Set to "off" to allow downloading files even if they
173
    have wildcard characters in their names.</p>
174
</usage>
175
</directivesynopsis>
176
177
<directivesynopsis>
178
<name>ProxyFtpEscapeWildcards</name>
179
<description>Whether wildcards in requested filenames are escaped when sent to the FTP server</description>
180
<syntax>ProxyFtpEscapeWildcards [on|off]</syntax>
181
<default>on</default>
182
<contextlist><context>server config</context><context>virtual host</context>
183
  <context>directory</context></contextlist>
184
<compatibility>Available in Apache xxx and later</compatibility>
185
186
<usage>
187
  <p>The <directive>ProxyFtpEscapeWildcards</directive> directive
188
    controls whether wildcard characters ("*?[{~") in requested
189
    filenames are escaped with backslash before sending them to the
190
    FTP server.  That is the default behavior, but many FTP servers
191
    don't know about the escaping and try to serve the literal filenames
192
    they were sent, including the backslashes in the names.  </p>
193
    <p>Set to "off" to allow downloading files with wildcards
194
    in their names from FTP servers that don't understand wildcard
195
    escaping.</p>
196
</usage>
197
</directivesynopsis>
198
199
148
</modulesynopsis>
200
</modulesynopsis>
(-)modules/proxy/mod_proxy_ftp.c (-13 / +96 lines)
Lines 37-42 Link Here
37
37
38
module AP_MODULE_DECLARE_DATA proxy_ftp_module;
38
module AP_MODULE_DECLARE_DATA proxy_ftp_module;
39
39
40
typedef struct {
41
    int ftp_list_on_wildcard;
42
    int ftp_list_on_wildcard_set;
43
    int ftp_escape_wildcards;
44
    int ftp_escape_wildcards_set;
45
} proxy_ftp_dir_conf;
46
47
static void *create_proxy_ftp_dir_config(apr_pool_t *p, char *dummy)
48
{
49
    proxy_ftp_dir_conf *new =
50
        (proxy_ftp_dir_conf *) apr_pcalloc(p, sizeof(proxy_ftp_dir_conf));
51
52
    /* Put these in the dir config so they work inside <Location> */
53
    new->ftp_list_on_wildcard = 1;
54
    new->ftp_escape_wildcards = 1;
55
56
    return (void *) new;
57
}
58
59
static void *merge_proxy_ftp_dir_config(apr_pool_t *p, void *basev, void *addv)
60
{
61
    proxy_ftp_dir_conf *new = (proxy_ftp_dir_conf *) apr_pcalloc(p, sizeof(proxy_ftp_dir_conf));
62
    proxy_ftp_dir_conf *add = (proxy_ftp_dir_conf *) addv;
63
    proxy_ftp_dir_conf *base = (proxy_ftp_dir_conf *) basev;
64
65
    /* Put these in the dir config so they work inside <Location> */
66
    new->ftp_list_on_wildcard = add->ftp_list_on_wildcard_set ?
67
                                add->ftp_list_on_wildcard :
68
                                base->ftp_list_on_wildcard;
69
    new->ftp_list_on_wildcard_set = add->ftp_list_on_wildcard_set ?
70
                                1 :
71
                                base->ftp_list_on_wildcard_set;
72
    new->ftp_escape_wildcards = add->ftp_escape_wildcards_set ?
73
                                add->ftp_escape_wildcards :
74
                                base->ftp_escape_wildcards;
75
    new->ftp_escape_wildcards_set = add->ftp_escape_wildcards_set ?
76
                                1 :
77
                                base->ftp_escape_wildcards_set;
78
79
    return new;
80
}
81
82
static const char *set_ftp_list_on_wildcard(cmd_parms *cmd, void *dconf,
83
                                            int flag)
84
{
85
    proxy_ftp_dir_conf *conf = dconf;
86
87
    conf->ftp_list_on_wildcard = flag;
88
    conf->ftp_list_on_wildcard_set = 1;
89
    return NULL;
90
}
91
92
static const char *set_ftp_escape_wildcards(cmd_parms *cmd, void *dconf,
93
                                            int flag)
94
{
95
    proxy_ftp_dir_conf *conf = dconf;
96
97
    conf->ftp_escape_wildcards = flag;
98
    conf->ftp_escape_wildcards_set = 1;
99
    return NULL;
100
}
101
40
/*
102
/*
41
 * Decodes a '%' escaped string, and returns the number of characters
103
 * Decodes a '%' escaped string, and returns the number of characters
42
 */
104
 */
Lines 63-75 Link Here
63
 * Escape the globbing characters in a path used as argument to
125
 * Escape the globbing characters in a path used as argument to
64
 * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
126
 * the FTP commands (SIZE, CWD, RETR, MDTM, ...).
65
 * ftpd assumes '\\' as a quoting character to escape special characters.
127
 * ftpd assumes '\\' as a quoting character to escape special characters.
128
 * Just returns the original string if ProxyFtpEscapeWildcards has been
129
 * configured "off".
66
 * Returns: escaped string
130
 * Returns: escaped string
67
 */
131
 */
68
#define FTP_GLOBBING_CHARS "*?[{~"
132
#define FTP_GLOBBING_CHARS "*?[{~"
69
static char *ftp_escape_globbingchars(apr_pool_t *p, const char *path)
133
static const char *ftp_escape_globbingchars(apr_pool_t *p, const char *path, proxy_ftp_dir_conf *dconf)
70
{
134
{
71
    char *ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
135
    char *ret;
72
    char *d;
136
    char *d;
137
    
138
    if (!dconf->ftp_escape_wildcards) {
139
        return path;
140
    }
141
142
    ret = apr_palloc(p, 2*strlen(path)+sizeof(""));
73
    for (d = ret; *path; ++path) {
143
    for (d = ret; *path; ++path) {
74
        if (strchr(FTP_GLOBBING_CHARS, *path) != NULL)
144
        if (strchr(FTP_GLOBBING_CHARS, *path) != NULL)
75
            *d++ = '\\';
145
            *d++ = '\\';
Lines 809-814 Link Here
809
#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
879
#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF))
810
    apr_time_t mtime = 0L;
880
    apr_time_t mtime = 0L;
811
#endif
881
#endif
882
    proxy_ftp_dir_conf *fdconf = ap_get_module_config(r->per_dir_config,
883
                                                      &proxy_ftp_module);
812
884
813
    /* stuff for PASV mode */
885
    /* stuff for PASV mode */
814
    int connect = 0, use_port = 0;
886
    int connect = 0, use_port = 0;
Lines 1157-1163 Link Here
1157
         * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
1229
         * We could also have extended gen_test_char.c with a special T_ESCAPE_FTP_PATH
1158
         */
1230
         */
1159
        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1231
        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1160
                           ftp_escape_globbingchars(p, path), CRLF, NULL),
1232
                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
1161
                           r, origin, bb, &ftpmessage);
1233
                           r, origin, bb, &ftpmessage);
1162
        *strp = '/';
1234
        *strp = '/';
1163
        /* responses: 250, 421, 500, 501, 502, 530, 550 */
1235
        /* responses: 250, 421, 500, 501, 502, 530, 550 */
Lines 1480-1488 Link Here
1480
    }
1552
    }
1481
1553
1482
    /* If len == 0 then it must be a directory (you can't RETR nothing)
1554
    /* If len == 0 then it must be a directory (you can't RETR nothing)
1483
     * Also, don't allow to RETR by wildcard. Instead, create a dirlisting
1555
     * Also, don't allow to RETR by wildcard. Instead, create a dirlisting,
1556
     * unless ProxyFtpListOnWildcard is off.
1484
     */
1557
     */
1485
    if (len == 0 || ftp_check_globbingchars(path)) {
1558
    if (len == 0 || (ftp_check_globbingchars(path) && fdconf->ftp_list_on_wildcard)) {
1486
        dirlisting = 1;
1559
        dirlisting = 1;
1487
    }
1560
    }
1488
    else {
1561
    else {
Lines 1503-1509 Link Here
1503
        /* Therefore: switch to binary if the user did not specify ";type=a" */
1576
        /* Therefore: switch to binary if the user did not specify ";type=a" */
1504
        ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
1577
        ftp_set_TYPE(xfer_type, r, origin, bb, &ftpmessage);
1505
        rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ",
1578
        rc = proxy_ftp_command(apr_pstrcat(p, "SIZE ",
1506
                           ftp_escape_globbingchars(p, path), CRLF, NULL),
1579
                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
1507
                           r, origin, bb, &ftpmessage);
1580
                           r, origin, bb, &ftpmessage);
1508
        if (rc == -1 || rc == 421) {
1581
        if (rc == -1 || rc == 421) {
1509
            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
1582
            return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY,
Lines 1522-1528 Link Here
1522
                             "proxy: FTP: SIZE shows this is a directory");
1595
                             "proxy: FTP: SIZE shows this is a directory");
1523
            dirlisting = 1;
1596
            dirlisting = 1;
1524
            rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1597
            rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1525
                           ftp_escape_globbingchars(p, path), CRLF, NULL),
1598
                           ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
1526
                           r, origin, bb, &ftpmessage);
1599
                           r, origin, bb, &ftpmessage);
1527
            /* possible results: 250, 421, 500, 501, 502, 530, 550 */
1600
            /* possible results: 250, 421, 500, 501, 502, 530, 550 */
1528
            /* 250 Requested file action okay, completed. */
1601
            /* 250 Requested file action okay, completed. */
Lines 1583-1589 Link Here
1583
         *     The "." and subsequent digits ("sss") are optional. <..>
1656
         *     The "." and subsequent digits ("sss") are optional. <..>
1584
         *     Time values are always represented in UTC (GMT)
1657
         *     Time values are always represented in UTC (GMT)
1585
         */
1658
         */
1586
        rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path), CRLF, NULL),
1659
        rc = proxy_ftp_command(apr_pstrcat(p, "MDTM ", ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
1587
                               r, origin, bb, &ftpmessage);
1660
                               r, origin, bb, &ftpmessage);
1588
        /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
1661
        /* then extract the Last-Modified time from it (YYYYMMDDhhmmss or YYYYMMDDhhmmss.xxx GMT). */
1589
        if (rc == 213) {
1662
        if (rc == 213) {
Lines 1622-1628 Link Here
1622
    }
1695
    }
1623
#endif /* USE_MDTM */
1696
#endif /* USE_MDTM */
1624
/* FIXME: Handle range requests - send REST */
1697
/* FIXME: Handle range requests - send REST */
1625
        buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path), CRLF, NULL);
1698
        buf = apr_pstrcat(p, "RETR ", ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL);
1626
    }
1699
    }
1627
    rc = proxy_ftp_command(buf, r, origin, bb, &ftpmessage);
1700
    rc = proxy_ftp_command(buf, r, origin, bb, &ftpmessage);
1628
    /* rc is an intermediate response for the LIST or RETR commands */
1701
    /* rc is an intermediate response for the LIST or RETR commands */
Lines 1659-1665 Link Here
1659
        ftp_set_TYPE('A', r, origin, bb, NULL);
1732
        ftp_set_TYPE('A', r, origin, bb, NULL);
1660
1733
1661
        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1734
        rc = proxy_ftp_command(apr_pstrcat(p, "CWD ",
1662
                               ftp_escape_globbingchars(p, path), CRLF, NULL),
1735
                               ftp_escape_globbingchars(p, path, fdconf), CRLF, NULL),
1663
                               r, origin, bb, &ftpmessage);
1736
                               r, origin, bb, &ftpmessage);
1664
        /* possible results: 250, 421, 500, 501, 502, 530, 550 */
1737
        /* possible results: 250, 421, 500, 501, 502, 530, 550 */
1665
        /* 250 Requested file action okay, completed. */
1738
        /* 250 Requested file action okay, completed. */
Lines 1929-1940 Link Here
1929
                              NULL, AP_FTYPE_RESOURCE);
2002
                              NULL, AP_FTYPE_RESOURCE);
1930
}
2003
}
1931
2004
2005
static const command_rec proxy_ftp_cmds[] =
2006
{
2007
    AP_INIT_FLAG("ProxyFtpListOnWildcard", set_ftp_list_on_wildcard, NULL,
2008
     RSRC_CONF|ACCESS_CONF, "Whether wildcard characters in a path cause mod_proxy_ftp to list the files instead of trying to get them."),
2009
    AP_INIT_FLAG("ProxyFtpEscapeWildcards", set_ftp_escape_wildcards, NULL,
2010
     RSRC_CONF|ACCESS_CONF, "Whether the proxy should escape wildcards in paths before sending them to the FTP server.  Defaults to on, but most FTP servers will need it turned off if you need to manage paths that contain wildcard characters."),
2011
    {NULL}
2012
};
2013
2014
1932
module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
2015
module AP_MODULE_DECLARE_DATA proxy_ftp_module = {
1933
    STANDARD20_MODULE_STUFF,
2016
    STANDARD20_MODULE_STUFF,
1934
    NULL,                       /* create per-directory config structure */
2017
    create_proxy_ftp_dir_config,/* create per-directory config structure */
1935
    NULL,                       /* merge per-directory config structures */
2018
    merge_proxy_ftp_dir_config, /* merge per-directory config structures */
1936
    NULL,                       /* create per-server config structure */
2019
    NULL,                       /* create per-server config structure */
1937
    NULL,                       /* merge per-server config structures */
2020
    NULL,                       /* merge per-server config structures */
1938
    NULL,                       /* command apr_table_t */
2021
    proxy_ftp_cmds,             /* command apr_table_t */
1939
    ap_proxy_ftp_register_hook  /* register hooks */
2022
    ap_proxy_ftp_register_hook  /* register hooks */
1940
};
2023
};

Return to bug 46798