📄 proxy_ftp.c
字号:
*/ if (log_it) ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r, "proxy: missing or failed auth to %s", ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPATHINFO)); ap_table_setn(r->err_headers_out, "WWW-Authenticate", ap_pstrcat(r->pool, "Basic realm=\"", ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|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 */int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url){ char *host, *path, *strp, *parms; char *cwd = NULL; char *user = NULL;/* char *account = NULL; how to supply an account in a URL? */ const char *password = NULL; const char *err; int port, i, j, len, sock, dsock, rc, nocache = 0; int csd = 0; struct sockaddr_in server; struct hostent server_hp; struct in_addr destaddr; table *resp_hdrs; BUFF *f; BUFF *data = NULL; pool *p = r->pool; int one = 1; const long int zero = 0L; NET_SIZE_T clen; struct tbl_do_args tdo; void *sconf = r->server->module_config; proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts; struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;/* stuff for PASV mode */ unsigned int presult, h0, h1, h2, h3, p0, p1; unsigned int paddr; unsigned short pport; struct sockaddr_in data_addr; int pasvmode = 0; char pasv[64]; char *pstr;/* stuff for responses */ char resp[MAX_STRING_LEN]; char *size = NULL;/* 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 */ host = r->parsed_uri.hostname; port = (r->parsed_uri.port != 0) ? r->parsed_uri.port : ap_default_port_for_request(r); path = ap_pstrdup(p, r->parsed_uri.path); path = (path != NULL && path[0] != '\0') ? &path[1] : ""; /* 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 = ap_table_get(r->headers_in, "Authorization")) != NULL && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0 && (password = ap_uudecode(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->connection->ap_auth_type = "Basic"; r->connection->user = r->parsed_uri.user = user; nocache = 1; /* This resource only accessible with username/password */ } else if ((user = r->parsed_uri.user) != NULL) { user = ap_pstrdup(p, user); decodeenc(user); if ((password = r->parsed_uri.password) != NULL) { char *tmp = ap_pstrdup(p, password); decodeenc(tmp); password = tmp; } nocache = 1; /* This resource only accessible with username/password */ } else { user = "anonymous"; password = "apache_proxy@"; }/* check if ProxyBlock directive on this host */ destaddr.s_addr = ap_inet_addr(host); for (i = 0; i < conf->noproxies->nelts; i++) { if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL) || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*') return ap_proxyerror(r, /*HTTP_FORBIDDEN*/ "Connect to remote machine blocked"); } Explain2("FTP: connect to %s:%d", host, port); parms = strchr(path, ';'); if (parms != NULL) *(parms++) = '\0'; memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons(port); err = ap_proxy_host2addr(host, &server_hp); if (err != NULL) return ap_proxyerror(r, err); /* give up */ sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error creating socket"); return HTTP_INTERNAL_SERVER_ERROR; } if (conf->recv_buffer_size > 0 && setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (const char *) &conf->recv_buffer_size, sizeof(int)) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one, sizeof(one)) == -1) {#ifndef _OSD_POSIX /* BS2000 has this option "always on" */ ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)"); ap_pclosesocket(p, sock); return HTTP_INTERNAL_SERVER_ERROR;#endif /*_OSD_POSIX*/ }#ifdef SINIX_D_RESOLVER_BUG { struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list; for (; ip_addr->s_addr != 0; ++ip_addr) { memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr)); i = ap_proxy_doconnect(sock, &server, r); if (i == 0) break; } }#else j = 0; while (server_hp.h_addr_list[j] != NULL) { memcpy(&server.sin_addr, server_hp.h_addr_list[j], sizeof(struct in_addr)); i = ap_proxy_doconnect(sock, &server, r); if (i == 0) break; j++; }#endif if (i == -1) { ap_pclosesocket(p, sock); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ ap_pstrcat(r->pool, "Could not connect to remote machine: ", strerror(errno), NULL)); } f = ap_bcreate(p, B_RDWR | B_SOCKET); ap_bpushfd(f, sock, sock);/* shouldn't we implement telnet control options here? */#ifdef CHARSET_EBCDIC ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1);#endif /*CHARSET_EBCDIC*//* possible results: */ /* 120 Service ready in nnn minutes. */ /* 220 Service ready for new user. */ /* 421 Service not available, closing control connection. */ ap_hard_timeout("proxy ftp", r); i = ftp_getrc_msg(f, resp, sizeof resp); Explain1("FTP: returned status %d", i); if (i == -1) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ "Error reading from remote server"); }#if 0 if (i == 120) { ap_kill_timeout(r); /* RFC2068 states: * 14.38 Retry-After * * The Retry-After response-header field can be used with a 503 (Service * Unavailable) response to indicate how long the service is expected to * be unavailable to the requesting client. The value of this field can * be either an HTTP-date or an integer number of seconds (in decimal) * after the time of the response. * Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds ) */ ap_set_header("Retry-After", ap_psprintf(p, "%u", 60*wait_mins); return ap_proxyerror(r, /*HTTP_SERVICE_UNAVAILABLE*/ resp); }#endif if (i != 220) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ resp); } Explain0("FTP: connected."); ap_bvputs(f, "USER ", user, CRLF, NULL); ap_bflush(f); /* capture any errors */ Explain1("FTP: USER %s", user);/* possible results; 230, 331, 332, 421, 500, 501, 530 *//* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */ /* 230 User logged in, proceed. */ /* 331 User name okay, need password. */ /* 332 Need account for login. */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* (This may include errors such as command line too long.) */ /* 501 Syntax error in parameters or arguments. */ /* 530 Not logged in. */ i = ftp_getrc(f); Explain1("FTP: returned status %d", i); if (i == -1) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ "Error reading from remote server"); } if (i == 530) { ap_kill_timeout(r); return ftp_unauthorized (r, 1); /* log it: user name guessing attempt? */ } if (i != 230 && i != 331) { ap_kill_timeout(r); return HTTP_BAD_GATEWAY; } if (i == 331) { /* send password */ if (password == NULL) { return ftp_unauthorized (r, 0); } ap_bvputs(f, "PASS ", password, CRLF, NULL); ap_bflush(f); Explain1("FTP: PASS %s", password);/* possible results 202, 230, 332, 421, 500, 501, 503, 530 */ /* 230 User logged in, proceed. */ /* 332 Need account for login. */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 503 Bad sequence of commands. */ /* 530 Not logged in. */ i = ftp_getrc(f); Explain1("FTP: returned status %d", i); if (i == -1) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ "Error reading from remote server"); } if (i == 332) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_UNAUTHORIZED*/ "Need account for login"); } /* @@@ questionable -- we might as well return a 403 Forbidden here */ if (i == 530) { ap_kill_timeout(r); return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */ } if (i != 230 && i != 202) { ap_kill_timeout(r); return HTTP_BAD_GATEWAY; } }/* set the directory (walk directory component by component): * this is what we must do if we don't know the OS type of the remote * machine */ for (;;) { strp = strchr(path, '/'); if (strp == NULL) break; *strp = '\0'; len = decodeenc(path); ap_bvputs(f, "CWD ", path, CRLF, NULL); ap_bflush(f); Explain1("FTP: CWD %s", path); *strp = '/';/* responses: 250, 421, 500, 501, 502, 530, 550 */ /* 250 Requested file action okay, completed. */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 502 Command not implemented. */ /* 530 Not logged in. */ /* 550 Requested action not taken. */ i = ftp_getrc(f); Explain1("FTP: returned status %d", i); if (i == -1) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ "Error reading from remote server"); } if (i == 550) { ap_kill_timeout(r); return HTTP_NOT_FOUND; } if (i != 250) { ap_kill_timeout(r); return HTTP_BAD_GATEWAY; } path = strp + 1; } if (parms != NULL && strncmp(parms, "type=", 5) == 0) { parms += 5; if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') || parms[1] != '\0') parms = ""; } else parms = ""; /* changed to make binary transfers the default */ if (parms[0] != 'a') { /* set type to image */ /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the connection */ ap_bputs("TYPE I" CRLF, f); ap_bflush(f); Explain0("FTP: TYPE I");/* responses: 200, 421, 500, 501, 504, 530 */ /* 200 Command okay. */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 504 Command not implemented for that parameter. */ /* 530 Not logged in. */ i = ftp_getrc(f); Explain1("FTP: returned status %d", i); if (i == -1) { ap_kill_timeout(r); return ap_proxyerror(r, /*HTTP_BAD_GATEWAY*/ "Error reading from remote server"); } if (i != 200 && i != 504) { ap_kill_timeout(r); return HTTP_BAD_GATEWAY; }/* Allow not implemented */ if (i == 504) parms[0] = '\0'; }/* try to set up PASV data connection first */ dsock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP); if (dsock == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error creating PASV socket"); ap_bclose(f); ap_kill_timeout(r); return HTTP_INTERNAL_SERVER_ERROR; } if (conf->recv_buffer_size) { if (setsockopt(dsock, SOL_SOCKET, SO_RCVBUF, (const char *) &conf->recv_buffer_size, sizeof(int)) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default"); } } ap_bputs("PASV" CRLF, f); ap_bflush(f); Explain0("FTP: PASV command issued");/* possible results: 227, 421, 500, 501, 502, 530 */ /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */ /* 421 Service not available, closing control connection. */ /* 500 Syntax error, command unrecognized. */ /* 501 Syntax error in parameters or arguments. */ /* 502 Command not implemented. */ /* 530 Not logged in. */ i = ap_bgets(pasv, sizeof(pasv), f); if (i == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, "PASV: control connection is toast"); ap_pclosesocket(p, dsock); ap_bclose(f); ap_kill_timeout(r); return HTTP_INTERNAL_SERVER_ERROR; } else { pasv[i - 1] = '\0'; pstr = strtok(pasv, " "); /* separate result code */ if (pstr != NULL) { presult = atoi(pstr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -