📄 proxy_ftp.c
字号:
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;}/* * 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>] */int ap_proxy_ftp_handler(request_rec *r, 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; apr_status_t rv; conn_rec *origin, *data = NULL; int err; 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; apr_socket_t *origin_sock = 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]; /* 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); /* create space for state information */ backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config, &proxy_ftp_module); if (!backend) { backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec)); backend->connection = NULL; backend->hostname = NULL; backend->port = 0; ap_set_module_config(c->conn_config, &proxy_ftp_module, backend); } if (backend->connection) origin_sock = ap_get_module_config(backend->connection->conn_config, &core_module); /* * 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); /* do a DNS lookup for the destination host */ err = apr_sockaddr_info_get(&connect_addr, connectname, APR_UNSPEC, connectport, 0, p); /* 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"); } /* * II: Make the Connection ----------------------- * * We have determined who to connect to. Now make the connection. */ /* * 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)); } /* * At this point we have a list of one or more IP addresses of the * machine to connect to. If configured, reorder this list so that the * "best candidate" is first try. "best candidate" could mean the least * loaded server, the fastest responding server, whatever. * * For now we do nothing, ie we get DNS round robin. XXX FIXME */ /* try each IP address until we connect successfully */ { int failed = 1; while (connect_addr) { if ((rv = apr_socket_create(&sock, connect_addr->family, SOCK_STREAM, r->pool)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: FTP: error creating socket"); connect_addr = connect_addr->next; continue; }#if !defined(TPF) && !defined(BEOS) if (conf->recv_buffer_size > 0 && (rv = apr_socket_opt_set(sock, APR_SO_RCVBUF, conf->recv_buffer_size))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_socket_opt_set(APR_SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); }#endif if (APR_SUCCESS != (rv = apr_socket_opt_set(sock, APR_SO_REUSEADDR, one))) { apr_socket_close(sock);#ifndef _OSD_POSIX /* BS2000 has this option "always on" */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "proxy: FTP: error setting reuseaddr option: apr_socket_opt_set(APR_SO_REUSEADDR)"); connect_addr = connect_addr->next; continue;#endif /* _OSD_POSIX */ } /* Set a timeout on the socket */ if (conf->timeout_set == 1) { apr_socket_timeout_set(sock, conf->timeout); } else { apr_socket_timeout_set(sock, r->server->timeout); } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: FTP: fam %d socket created, trying to connect to %pI (%s)...", connect_addr->family, connect_addr, connectname); /* make the connection out of the socket */ rv = apr_connect(sock, connect_addr); /* if an error occurred, loop round and try again */ if (rv != APR_SUCCESS) { apr_socket_close(sock); ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server, "proxy: FTP: attempt to connect to %pI (%s) failed", connect_addr, connectname); connect_addr = connect_addr->next; continue; } /* if we get here, all is well */ failed = 0; break; } /* handle a permanent error from the above loop */ if (failed) { return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_psprintf(r->pool, "Could not connect to remote machine: %s port %d", connectname, connectport)); } } /* the socket is now open, create a new connection */ origin = ap_run_create_connection(p, r->server, sock, r->connection->id, r->connection->sbh, c->bucket_alloc); if (!origin) { /* * the peer reset the connection already; ap_run_create_connection() closed * the socket */ 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); return HTTP_INTERNAL_SERVER_ERROR; } /* if a keepalive connection is floating around, close it first! */ /* we might support ftp keepalives later, but not now... */ if (backend->connection) { apr_socket_close(origin_sock); backend->connection = NULL; origin_sock = NULL; } 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... */ /* set up the connection filters */ rc = ap_run_pre_connection(origin, sock); if (rc != OK && rc != DONE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -