diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 7f37b7d67197..e61e23b1425a 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -1387,6 +1388,8 @@ http_connect(struct url *URL, struct url *purl, const char *flags) int verbose; int af, val; int serrno; + bool isproxyauth = false; + http_auth_challenges_t proxy_challenges; #ifdef INET6 af = AF_UNSPEC; @@ -1404,18 +1407,58 @@ http_connect(struct url *URL, struct url *purl, const char *flags) curl = (purl != NULL) ? purl : URL; +retry: if ((conn = fetch_connect(curl->host, curl->port, af, verbose)) == NULL) /* fetch_connect() has already set an error code */ return (NULL); init_http_headerbuf(&headerbuf); if (strcmp(URL->scheme, SCHEME_HTTPS) == 0 && purl) { - http_cmd(conn, "CONNECT %s:%d HTTP/1.1", - URL->host, URL->port); - http_cmd(conn, "Host: %s:%d", - URL->host, URL->port); + init_http_auth_challenges(&proxy_challenges); + http_cmd(conn, "CONNECT %s:%d HTTP/1.1", URL->host, URL->port); + http_cmd(conn, "Host: %s:%d", URL->host, URL->port); + if (isproxyauth) { + http_auth_params_t aparams; + init_http_auth_params(&aparams); + if (*purl->user || *purl->pwd) { + aparams.user = strdup(purl->user); + aparams.password = strdup(purl->pwd); + } else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && + *p != '\0') { + if (http_authfromenv(p, &aparams) < 0) { + http_seterr(HTTP_NEED_PROXY_AUTH); + fetch_syserr(); + goto ouch; + } + } else if (fetch_netrc_auth(purl) == 0) { + aparams.user = strdup(purl->user); + aparams.password = strdup(purl->pwd); + } else { + /* + * No auth information found in system - exiting + * with warning. + */ + warnx("Missing username and/or password set"); + fetch_syserr(); + goto ouch; + } + http_authorize(conn, "Proxy-Authorization", + &proxy_challenges, &aparams, purl); + clean_http_auth_params(&aparams); + } http_cmd(conn, ""); - if (http_get_reply(conn) != HTTP_OK) { - http_seterr(conn->err); + /* Get reply from CONNECT Tunnel attempt */ + int httpreply = http_get_reply(conn); + if (httpreply != HTTP_OK) { + http_seterr(httpreply); + /* If the error is a 407/HTTP_NEED_PROXY_AUTH */ + if (httpreply == HTTP_NEED_PROXY_AUTH && + ! isproxyauth) { + /* Try again with authentication. */ + clean_http_headerbuf(&headerbuf); + fetch_close(conn); + isproxyauth = true; + goto retry; + } goto ouch; } /* Read and discard the rest of the proxy response */