📄 proxy_ftp.c
字号:
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; /* 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 '..': append slash to link */ if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') { ap_snprintf(buf2, buf_size, "%s <a href=\"%s/\">%s</a>\n", ap_escape_html(p, buf), ap_escape_uri(p, filename), ap_escape_html(p, filename)); } else { ap_snprintf(buf2, buf_size, "%s <a href=\"%s\">%s</a>\n", ap_escape_html(p, buf), ap_escape_uri(p, filename), ap_escape_html(p, filename)); } ap_cpystrn(buf, buf2, buf_size); n = strlen(buf); } /* else??? What about other OS's output formats? */ else { strcat(buf, "\n"); /* re-append the newline char */ ap_cpystrn(buf, ap_escape_html(p, buf), buf_size); } total_bytes_sent += ap_proxy_bputs2(buf, con->client, c); ap_reset_timeout(r); /* reset timeout after successfule write */ } 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_bclose(data); 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 = NOT_PROXY; /* * Log failed requests if they supplied a password (log username/password * guessing attempts) */ 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;}/* Set ftp server to TYPE {A,I,E} before transfer of a directory or file */static int ftp_set_TYPE(request_rec *r, BUFF *ctrl, char xfer_type){ static char old_type[2] = {'A', '\0'}; /* After logon, mode is ASCII */ int ret = HTTP_OK; int rc; if (xfer_type == old_type[0]) return ret; /* set desired type */ old_type[0] = xfer_type; ap_bvputs(ctrl, "TYPE ", old_type, CRLF, NULL); ap_bflush(ctrl); ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "FTP: TYPE %s", old_type);/* 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. */ rc = ftp_getrc(ctrl); ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "FTP: returned status %d", rc); if (rc == -1 || rc == 421) { ap_kill_timeout(r); ret = ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } else if (rc != 200 && rc != 504) { ap_kill_timeout(r); ret = ap_proxyerror(r, HTTP_BAD_GATEWAY, "Unable to set transfer type"); }/* Allow not implemented */ else if (rc == 504) /* ignore it silently */ ; return ret;}/* Common cleanup routine: close open BUFFers or sockets, and return an error */static int ftp_cleanup_and_return(request_rec *r, BUFF *ctrl, BUFF *data, int csock, int dsock, int rc){ if (ctrl != NULL) ap_bclose(ctrl); else if (csock != -1) ap_pclosesocket(r->pool, csock); if (data != NULL) ap_bclose(data); else if (dsock != -1) ap_pclosesocket(r->pool, dsock); ap_kill_timeout(r); return rc;}/* * 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 *desthost, *path, *strp, *parms; char *strp2; 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 destport, i, j, len, rc, nocache = 0; int csd = 0, sock = -1, dsock = -1; struct sockaddr_in server; struct hostent server_hp; struct in_addr destaddr; table *resp_hdrs; BUFF *ctrl = NULL; BUFF *data = NULL; pool *p = r->pool; char *destportstr = NULL; const char *urlptr = NULL; int one = 1; NET_SIZE_T clen; char xfer_type = 'A'; /* after ftp login, the default is ASCII */ int get_dirlisting = 0; 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 */ urlptr = strstr(url, "://"); if (urlptr == NULL) return HTTP_BAD_REQUEST; urlptr += 3; destport = 21; strp = strchr(urlptr, '/'); if (strp == NULL) { desthost = ap_pstrdup(p, urlptr); urlptr = "/"; } else { char *q = ap_palloc(p, strp - urlptr + 1); memcpy(q, urlptr, strp - urlptr); q[strp - urlptr] = '\0'; urlptr = strp; desthost = q; } strp2 = strchr(desthost, ':'); if (strp2 != NULL) { *(strp2++) = '\0'; if (ap_isdigit(*strp2)) { destport = atoi(strp2); destportstr = strp2; } } path = strchr(urlptr, '/')+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_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->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(desthost); for (i = 0; i < conf->noproxies->nelts; i++) { if (destaddr.s_addr == npent[i].addr.s_addr || (npent[i].name != NULL && (npent[i].name[0] == '*' || strstr(desthost, npent[i].name) != NULL))) return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); } ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "FTP: connect to %s:%d", desthost, destport); parms = strchr(url, ';'); if (parms != NULL) *(parms++) = '\0'; memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_port = htons((unsigned short)destport); err = ap_proxy_host2addr(desthost, &server_hp); if (err != NULL) return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err); sock = ap_psocket_ex(p, PF_INET, SOCK_STREAM, IPPROTO_TCP, 1); if (sock == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error creating socket"); return HTTP_INTERNAL_SERVER_ERROR; }#if !defined(TPF) && !defined(BEOS) 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"); }#endif 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) { return ftp_cleanup_and_return(r, ctrl, data, sock, dsock, ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool, "Could not connect to remote machine: ",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -