📄 proxy_ftp.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* FTP routines for Apache proxy */#include "mod_proxy.h"#include "http_main.h"#include "http_log.h"#include "http_core.h"#define AUTODETECT_PWD/* * 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 == '%' && ap_isxdigit(x[i + 1]) && ap_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 == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) { ch = ap_proxy_hex2c(&x[i + 1]); i += 2; } if (ch == CR || ch == LF || (OS_ASC(ch) & 0x80)) 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 == NOT_PROXY && r->args != NULL) { if (strp != NULL) { strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, STD_PROXY); 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, STD_PROXY); 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 *ctrl){ int len, status; char linebuff[100], buff[5]; len = ap_bgets(linebuff, sizeof linebuff, ctrl); 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(ctrl); }/* skip continuation lines */ if (linebuff[3] == '-') { memcpy(buff, linebuff, 3); buff[3] = ' '; do { len = ap_bgets(linebuff, sizeof linebuff, ctrl); if (len == -1) return -1; if (linebuff[len - 1] != '\n') { (void)ap_bskiplf(ctrl); } } 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 *ctrl, char *msgbuf, int msglen){ int len, status; char linebuff[100], buff[5]; char *mb = msgbuf, *me = &msgbuf[msglen]; len = ap_bgets(linebuff, sizeof linebuff, ctrl); 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(ctrl); if (linebuff[3] == '-') { memcpy(buff, linebuff, 3); buff[3] = ' '; do { len = ap_bgets(linebuff, sizeof linebuff, ctrl); if (len == -1) return -1; if (linebuff[len - 1] != '\n') { (void)ap_bskiplf(ctrl); } mb = ap_cpystrn(mb, linebuff + 4, me - mb); } while (memcmp(linebuff, buff, 4) != 0); } return status;}static long int send_dir(BUFF *data, request_rec *r, cache_req *c, char *cwd){ char *buf, *buf2; size_t buf_size; char *filename; int searchidx = 0; char *searchptr = NULL; int firstfile = 1; unsigned long total_bytes_sent = 0; register int n; conn_rec *con = r->connection; pool *p = r->pool; char *dir, *path, *reldir, *site, *type = NULL; char *basedir = ""; /* By default, path is relative to the $HOME * dir */ /* create default sized buffers for the stuff below */ buf_size = IOBUFSIZE; buf = ap_palloc(r->pool, buf_size); buf2 = ap_palloc(r->pool, buf_size); /* Save "scheme://site" prefix without password */ site = ap_unparse_uri_components(p, &r->parsed_uri, UNP_OMITPASSWORD | UNP_OMITPATHINFO); /* ... and path without query args */ path = ap_unparse_uri_components(p, &r->parsed_uri, UNP_OMITSITEPART | UNP_OMITQUERY); /* If path began with /%2f, change the basedir */ if (strncasecmp(path, "/%2f", 4) == 0) { basedir = "/%2f"; } /* Strip off a type qualifier. It is ignored for dir listings */ if ((type = strstr(path, ";type=")) != NULL) *type++ = '\0'; (void)decodeenc(path); while (path[1] == '/') /* collapse multiple leading slashes to one */ ++path; /* Copy path, strip (all except the last) trailing slashes */ /* (the trailing slash is needed for the dir component loop below) */ path = dir = ap_pstrcat(r->pool, path, "/", NULL); for (n = strlen(path); n > 1 && path[n - 1] == '/' && path[n - 2] == '/'; --n) path[n - 1] = '\0'; /* print "ftp://host/" */ n = ap_snprintf(buf, buf_size, DOCTYPE_HTML_3_2 "<html><head><title>%s%s%s</title>\n" "<base href=\"%s%s%s\"></head>\n" "<body><h2>Directory of " "<a href=\"/\">%s</a>/", site, basedir, ap_escape_html(p, path), site, basedir, ap_escape_uri(p, path), site); total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); /* Add a link to the root directory (if %2f hack was used) */ if (basedir[0] != '\0') { total_bytes_sent += ap_proxy_bputs2("<a href=\"/%2f/\">%2f</a>/", con->client, c); } for (dir = path + 1; (dir = strchr(dir, '/')) != NULL;) { *dir = '\0'; if ((reldir = strrchr(path + 1, '/')) == NULL) { reldir = path + 1; } else ++reldir; /* print "path/" component */ ap_snprintf(buf, buf_size, "<a href=\"%s%s/\">%s</a>/", basedir, ap_escape_uri(p, path), ap_escape_html(p, reldir)); total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); *dir = '/'; while (*dir == '/') ++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, buf_size, "</h2>\n<hr /><pre>"); } else { ap_snprintf(buf, buf_size, "</h2>\n(%s)\n<hr /><pre>", ap_escape_html(p, cwd)); } total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); while (!con->aborted) { n = ap_bgets(buf, buf_size, data); if (n == -1) { /* input error */ if (c != NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error reading from %s", c->url); c = ap_proxy_cache_error(c); } break; } if (n == 0) break; /* EOF */ if (buf[n - 1] == '\n') /* strip trailing '\n' */ buf[--n] = '\0'; if (buf[n - 1] == '\r') /* strip trailing '\r' if present */ buf[--n] = '\0'; /* Handle unix-style symbolic link */ if (buf[0] == 'l' && (filename = strstr(buf, " -> ")) != NULL) { char *link_ptr = filename; do { filename--; } while (filename[0] != ' ' && filename > buf); if (filename != buf) *(filename++) = '\0'; *(link_ptr++) = '\0'; ap_snprintf(buf2, buf_size, "%s <a href=\"%s\">%s %s</a>\n", ap_escape_html(p, buf), ap_escape_uri(p, filename), ap_escape_html(p, filename), ap_escape_html(p, link_ptr)); ap_cpystrn(buf, buf2, buf_size); n = strlen(buf); } /* Handle unix style or DOS style directory */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -