📄 mod_proxy_ftp.c
字号:
/* ignore it silently */; return ret;}/* Return the current directory which we have selected on the FTP server, or NULL */static char *ftp_get_PWD(request_rec *r, conn_rec *ftp_ctrl, apr_bucket_brigade *bb){ char *cwd = NULL; char *ftpmessage = NULL; /* responses: 257, 500, 501, 502, 421, 550 */ /* 257 "<directory-name>" <commentary> */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 502 Command not implemented. */ /* 550 Requested action not taken. */ switch (proxy_ftp_command("PWD" CRLF, r, ftp_ctrl, bb, &ftpmessage)) { case -1: case 421: case 550: ap_proxyerror(r, HTTP_BAD_GATEWAY, "Failed to read PWD on ftp server"); break; case 257: { const char *dirp = ftpmessage; cwd = ap_getword_conf(r->pool, &dirp); } } return cwd;}/* 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 = PROXYREQ_NONE; /* * Log failed requests if they supplied a password (log username/password * guessing attempts) */ if (log_it) ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "proxy: missing or failed auth to %s", apr_uri_unparse(r->pool, &r->parsed_uri, APR_URI_UNP_OMITPATHINFO)); apr_table_setn(r->err_headers_out, "WWW-Authenticate", apr_pstrcat(r->pool, "Basic realm=\"", apr_uri_unparse(r->pool, &r->parsed_uri, APR_URI_UNP_OMITPASSWORD | APR_URI_UNP_OMITPATHINFO), "\"", NULL)); return HTTP_UNAUTHORIZED;}staticapr_status_t proxy_ftp_cleanup(request_rec *r, proxy_conn_rec *backend){ backend->close_on_recycle = 1; ap_set_module_config(r->connection->conn_config, &proxy_ftp_module, NULL); ap_proxy_release_connection("FTP", backend, r->server); return OK;}staticint ftp_proxyerror(request_rec *r, proxy_conn_rec *conn, int statuscode, const char *message){ proxy_ftp_cleanup(r, conn); return ap_proxyerror(r, statuscode, message);}/* * Handles direct access of ftp:// URLs * Original (Non-PASV) version from * Troy Morrison <spiffnet@zoom.com> * PASV added by Chuck * Filters by [Graham Leggett <minfrin@sharp.fm>] */static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyhost, apr_port_t proxyport){ apr_pool_t *p = r->pool; conn_rec *c = r->connection; proxy_conn_rec *backend; apr_socket_t *sock, *local_sock, *data_sock = NULL; apr_sockaddr_t *connect_addr = NULL; apr_status_t rv; conn_rec *origin, *data = NULL; apr_status_t err = APR_SUCCESS; apr_status_t uerr = APR_SUCCESS; apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); char *buf, *connectname; apr_port_t connectport; char buffer[MAX_STRING_LEN]; char *ftpmessage = NULL; char *path, *strp, *type_suffix, *cwd = NULL; apr_uri_t uri; char *user = NULL;/* char *account = NULL; how to supply an account in a URL? */ const char *password = NULL; int len, rc; int one = 1; char *size = NULL; char xfer_type = 'A'; /* after ftp login, the default is ASCII */ int dirlisting = 0;#if defined(USE_MDTM) && (defined(HAVE_TIMEGM) || defined(HAVE_GMTOFF)) apr_time_t mtime = 0L;#endif /* stuff for PASV mode */ int connect = 0, use_port = 0; char dates[APR_RFC822_DATE_LEN]; int status; apr_pool_t *address_pool; /* is this for us? */ if (proxyhost) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: declining URL %s - proxyhost %s specified:", url, proxyhost); return DECLINED; /* proxy connections are via HTTP */ } if (strncasecmp(url, "ftp:", 4)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: declining URL %s - not ftp:", url); return DECLINED; /* only interested in FTP */ } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: serving URL %s", url); /* * I: Who Do I Connect To? ----------------------- * * Break up the URL to determine the host to connect to */ /* we only support GET and HEAD */ if (r->method_number != M_GET) return HTTP_NOT_IMPLEMENTED; /* We break the URL into host, port, path-search */ if (r->parsed_uri.hostname == NULL) { if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) { return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_psprintf(p, "URI cannot be parsed: %s", url)); } connectname = uri.hostname; connectport = uri.port; path = apr_pstrdup(p, uri.path); } else { connectname = r->parsed_uri.hostname; connectport = r->parsed_uri.port; path = apr_pstrdup(p, r->parsed_uri.path); } if (connectport == 0) { connectport = apr_uri_port_of_scheme("ftp"); } path = (path != NULL && path[0] != '\0') ? &path[1] : ""; type_suffix = strchr(path, ';'); if (type_suffix != NULL) *(type_suffix++) = '\0'; if (type_suffix != NULL && strncmp(type_suffix, "type=", 5) == 0 && apr_isalpha(type_suffix[5])) { /* "type=d" forces a dir listing. * The other types (i|a|e) are directly used for the ftp TYPE command */ if ( ! (dirlisting = (apr_tolower(type_suffix[5]) == 'd'))) xfer_type = apr_toupper(type_suffix[5]); /* Check valid types, rather than ignoring invalid types silently: */ if (strchr("AEI", xfer_type) == NULL) return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool, "ftp proxy supports only types 'a', 'i', or 'e': \"", type_suffix, "\" is invalid.", NULL)); } else { /* make binary transfers the default */ xfer_type = 'I'; } /* * The "Authorization:" header must be checked first. We allow the user * to "override" the URL-coded user [ & password ] in the Browsers' * User&Password Dialog. NOTE that this is only marginally more secure * than having the password travel in plain as part of the URL, because * Basic Auth simply uuencodes the plain text password. But chances are * still smaller that the URL is logged regularly. */ if ((password = apr_table_get(r->headers_in, "Authorization")) != NULL && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0 && (password = ap_pbase64decode(r->pool, password))[0] != ':') { /* * Note that this allocation has to be made from r->connection->pool * because it has the lifetime of the connection. The other * allocations are temporary and can be tossed away any time. */ user = ap_getword_nulls(r->connection->pool, &password, ':'); r->ap_auth_type = "Basic"; r->user = r->parsed_uri.user = user; } else if ((user = r->parsed_uri.user) != NULL) { user = apr_pstrdup(p, user); decodeenc(user); if ((password = r->parsed_uri.password) != NULL) { char *tmp = apr_pstrdup(p, password); decodeenc(tmp); password = tmp; } } else { user = "anonymous"; password = "apache-proxy@"; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: connecting %s to %s:%d", url, connectname, connectport); if (worker->is_address_reusable) { if (!worker->cp->addr) { if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, "proxy: FTP: lock"); return HTTP_INTERNAL_SERVER_ERROR; } } connect_addr = worker->cp->addr; address_pool = worker->cp->pool; } else address_pool = r->pool; /* do a DNS lookup for the destination host */ if (!connect_addr) err = apr_sockaddr_info_get(&(connect_addr), connectname, APR_UNSPEC, connectport, 0, address_pool); if (worker->is_address_reusable && !worker->cp->addr) { worker->cp->addr = connect_addr; if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, uerr, r->server, "proxy: FTP: unlock"); } } /* * get all the possible IP addresses for the destname and loop through * them until we get a successful connection */ if (APR_SUCCESS != err) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p, "DNS lookup failure for: ", connectname, NULL)); } /* check if ProxyBlock directive on this host */ if (OK != ap_proxy_checkproxyblock(r, conf, connect_addr)) { return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } /* create space for state information */ backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module); if (!backend) { status = ap_proxy_acquire_connection("FTP", &backend, worker, r->server); if (status != OK) { if (backend) { backend->close_on_recycle = 1; ap_proxy_release_connection("FTP", backend, r->server); } return status; } /* TODO: see if ftp could use determine_connection */ backend->addr = connect_addr; ap_set_module_config(c->conn_config, &proxy_ftp_module, backend); } /* * II: Make the Connection ----------------------- * * We have determined who to connect to. Now make the connection. */ if (ap_proxy_connect_backend("FTP", backend, worker, r->server)) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: an error occurred creating a new connection to %pI (%s)", connect_addr, connectname); proxy_ftp_cleanup(r, backend); return HTTP_SERVICE_UNAVAILABLE; } if (!backend->connection) { status = ap_proxy_connection_create("FTP", backend, c, r->server); if (status != OK) { proxy_ftp_cleanup(r, backend); return status; } } /* Use old naming */ origin = backend->connection; sock = backend->sock; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: control connection complete"); /* * III: Send Control Request ------------------------- * * Log into the ftp server, send the username & password, change to the * correct directory... */ /* possible results: */ /* 120 Service ready in nnn minutes. */ /* 220 Service ready for new user. */ /* 421 Service not available, closing control connection. */ rc = proxy_ftp_command(NULL, r, origin, bb, &ftpmessage); if (rc == -1 || rc == 421) { return ftp_proxyerror(r, backend, HTTP_BAD_GATEWAY, "Error reading from remote server"); } if (rc == 120) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -