⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proxy_ftp.c

📁 apache简化版
💻 C
📖 第 1 页 / 共 3 页
字号:
     */    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 + -