📄 proxy_ftp.c
字号:
/* ==================================================================== * Copyright (c) 1996-1998 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see <http://www.apache.org/>. * *//* FTP routines for Apache proxy */#include "mod_proxy.h"#include "http_main.h"#include "http_log.h"#define AUTODETECT_PWDDEF_Explain/* * Decodes a '%' escaped string, and returns the number of characters */static int decodeenc(char *x){ int i, j, ch; if (x[0] == '\0') return 0; /* special case for no characters */ for (i = 0, j = 0; x[i] != '\0'; i++, j++) {/* decode it if not already done */ ch = x[i]; if (ch == '%' && isxdigit(x[i + 1]) && isxdigit(x[i + 2])) { ch = ap_proxy_hex2c(&x[i + 1]); i += 2; } x[j] = ch; } x[j] = '\0'; return j;}/* * checks an encoded ftp string for bad characters, namely, CR, LF or * non-ascii character */static int ftp_check_string(const char *x){ int i, ch; for (i = 0; x[i] != '\0'; i++) { ch = x[i]; if (ch == '%' && isxdigit(x[i + 1]) && isxdigit(x[i + 2])) { ch = ap_proxy_hex2c(&x[i + 1]); i += 2; }#ifndef CHARSET_EBCDIC if (ch == '\015' || ch == '\012' || (ch & 0x80))#else /*CHARSET_EBCDIC*/ if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80))#endif /*CHARSET_EBCDIC*/ return 0; } return 1;}/* * Canonicalise ftp URLs. */int ap_proxy_ftp_canon(request_rec *r, char *url){ char *user, *password, *host, *path, *parms, *strp, sport[7]; pool *p = r->pool; const char *err; int port; port = DEFAULT_FTP_PORT; err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port); if (err) return HTTP_BAD_REQUEST; if (user != NULL && !ftp_check_string(user)) return HTTP_BAD_REQUEST; if (password != NULL && !ftp_check_string(password)) return HTTP_BAD_REQUEST;/* now parse path/parameters args, according to rfc1738 *//* N.B. if this isn't a true proxy request, then the URL path * (but not query args) has already been decoded. * This gives rise to the problem of a ; being decoded into the * path. */ strp = strchr(url, ';'); if (strp != NULL) { *(strp++) = '\0'; parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq); if (parms == NULL) return HTTP_BAD_REQUEST; } else parms = ""; path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq); if (path == NULL) return HTTP_BAD_REQUEST; if (!ftp_check_string(path)) return HTTP_BAD_REQUEST; if (!r->proxyreq && r->args != NULL) { if (strp != NULL) { strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1); if (strp == NULL) return HTTP_BAD_REQUEST; parms = ap_pstrcat(p, parms, "?", strp, NULL); } else { strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1); if (strp == NULL) return HTTP_BAD_REQUEST; path = ap_pstrcat(p, path, "?", strp, NULL); } r->args = NULL; }/* now, rebuild URL */ if (port != DEFAULT_FTP_PORT) ap_snprintf(sport, sizeof(sport), ":%d", port); else sport[0] = '\0'; r->filename = ap_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "", (password != NULL) ? ":" : "", (password != NULL) ? password : "", (user != NULL) ? "@" : "", host, sport, "/", path, (parms[0] != '\0') ? ";" : "", parms, NULL); return OK;}/* * Returns the ftp status code; * or -1 on I/O error, 0 on data error */static int ftp_getrc(BUFF *f){ int len, status; char linebuff[100], buff[5]; len = ap_bgets(linebuff, sizeof linebuff, f); if (len == -1) return -1;/* check format */ if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) || !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-')) status = 0; else status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0'; if (linebuff[len - 1] != '\n') { (void)ap_bskiplf(f); }/* skip continuation lines */ if (linebuff[3] == '-') { memcpy(buff, linebuff, 3); buff[3] = ' '; do { len = ap_bgets(linebuff, sizeof linebuff, f); if (len == -1) return -1; if (linebuff[len - 1] != '\n') { (void)ap_bskiplf(f); } } while (memcmp(linebuff, buff, 4) != 0); } return status;}/* * Like ftp_getrc but returns both the ftp status code and * remembers the response message in the supplied buffer */static int ftp_getrc_msg(BUFF *f, char *msgbuf, int msglen){ int len, status; char linebuff[100], buff[5]; char *mb = msgbuf, *me = &msgbuf[msglen]; len = ap_bgets(linebuff, sizeof linebuff, f); if (len == -1) return -1; if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) || !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-')) status = 0; else status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0'; mb = ap_cpystrn(mb, linebuff+4, me - mb); if (linebuff[len - 1] != '\n') (void)ap_bskiplf(f); if (linebuff[3] == '-') { memcpy(buff, linebuff, 3); buff[3] = ' '; do { len = ap_bgets(linebuff, sizeof linebuff, f); if (len == -1) return -1; if (linebuff[len - 1] != '\n') { (void)ap_bskiplf(f); } mb = ap_cpystrn(mb, linebuff+4, me - mb); } while (memcmp(linebuff, buff, 4) != 0); } return status;}static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd){ char buf[IOBUFSIZE]; char buf2[IOBUFSIZE]; char *filename; int searchidx = 0; char *searchptr = NULL; int firstfile = 1; unsigned long total_bytes_sent = 0; register int n, o, w; conn_rec *con = r->connection; char *dir, *path, *reldir, *site; /* Save "scheme://site" prefix without password */ site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO); /* ... and path without query args */ path = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITSITEPART|UNP_OMITQUERY); (void)decodeenc(path); /* Copy path, strip (all except the last) trailing slashes */ path = dir = ap_pstrcat(r->pool, path, "/", NULL); while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/') path[n-1] = '\0'; /* print "ftp://host/" */ n = ap_snprintf(buf, sizeof(buf), "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" "<HTML><HEAD><TITLE>%s%s</TITLE>\n" "<BASE HREF=\"%s%s\"></HEAD>\n" "<BODY><H2>Directory of " "<A HREF=\"/\">%s</A>/", site, path, site, path, site); total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); while ((dir = strchr(dir+1, '/')) != NULL) { *dir = '\0'; if ((reldir = strrchr(path+1, '/'))==NULL) reldir = path+1; else ++reldir; /* print "path/" component */ ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir); total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); *dir = '/'; } /* If the caller has determined the current directory, and it differs */ /* from what the client requested, then show the real name */ if (cwd == NULL || strncmp (cwd, path, strlen(cwd)) == 0) { ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>"); } else { ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd); } total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); while (!con->aborted) { n = ap_bgets(buf, sizeof buf, f); if (n == -1) { /* input error */ if (c != NULL) c = ap_proxy_cache_error(c); break; } if (n == 0) break; /* EOF */ if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) { char *link_ptr = filename; do { filename--; } while (filename[0] != ' '); *(filename++) = '\0'; *(link_ptr++) = '\0'; if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n') link_ptr[n - 1] = '\0'; ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr); ap_cpystrn(buf, buf2, sizeof(buf)); n = strlen(buf); } else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || ap_isdigit(buf[0])) { if (ap_isdigit(buf[0])) { /* handle DOS dir */ searchptr = strchr(buf, '<'); if (searchptr != NULL) *searchptr = '['; searchptr = strchr(buf, '>'); if (searchptr != NULL) *searchptr = ']'; } filename = strrchr(buf, ' '); *(filename++) = 0; filename[strlen(filename) - 1] = 0; /* handle filenames with spaces in 'em */ if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) { firstfile = 0; searchidx = filename - buf; } else if (searchidx != 0 && buf[searchidx] != 0) { *(--filename) = ' '; buf[searchidx - 1] = 0; filename = &buf[searchidx]; } /* Special handling for '.' and '..' */ if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') { ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n", buf, filename, filename); } else { ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename); } ap_cpystrn(buf, buf2, sizeof(buf)); n = strlen(buf); } o = 0; total_bytes_sent += n; if (c != NULL && c->fp && ap_bwrite(c->fp, buf, n) != n) c = ap_proxy_cache_error(c); while (n && !r->connection->aborted) { w = ap_bwrite(con->client, &buf[o], n); if (w <= 0) break; ap_reset_timeout(r); /* reset timeout after successfule write */ n -= w; o += w; } } total_bytes_sent += ap_proxy_bputs2("</PRE><HR>\n", con->client, c); total_bytes_sent += ap_proxy_bputs2(ap_psignature("", r), con->client, c); total_bytes_sent += ap_proxy_bputs2("</BODY></HTML>\n", con->client, c); ap_bflush(con->client); return total_bytes_sent;}/* Common routine for failed authorization (i.e., missing or wrong password) * to an ftp service. This causes most browsers to retry the request * with username and password (which was presumably queried from the user) * supplied in the Authorization: header. * Note that we "invent" a realm name which consists of the * ftp://user@host part of the reqest (sans password -if supplied but invalid-) */static int ftp_unauthorized (request_rec *r, int log_it){ r->proxyreq = 0; /* Log failed requests if they supplied a password * (log username/password guessing attempts)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -