bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const int port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { struct gc_arena gc = gc_new (); char buf[512]; char buf2[128]; char get[80]; int status; int nparms; bool ret = false; bool processed = false; /* get user/pass if not previously given */ if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_DIGEST || p->auth_method == HTTP_AUTH_NTLM) get_user_pass_http (p, false); /* are we being called again after getting the digest server nonce in the previous transaction? */ if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) { nparms = 1; status = 407; } else { /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); if (!send_line_crlf(sd, buf)) goto error; /* send User-Agent string if provided */ if (p->options.user_agent) { openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", p->options.user_agent); if (!send_line_crlf (sd, buf)) goto error; } /* auth specified? */ switch (p->auth_method) { case HTTP_AUTH_NONE: break; case HTTP_AUTH_BASIC: openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", username_password_as_base64 (p, &gc)); msg (D_PROXY, "Attempting Basic Proxy-Authorization"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #if NTLM case HTTP_AUTH_NTLM: case HTTP_AUTH_NTLM2: /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1 (p, &gc)); msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; break; #endif default: ASSERT (0); } /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); } /* check for a "407 Proxy Authentication Required" response */ while (nparms >= 1 && status == 407) { msg (D_PROXY, "Proxy requires authentication"); if (p->auth_method == HTTP_AUTH_BASIC && !processed) { processed = true; } else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ { #if NTLM /* look for the phase 2 response */ while (true) { if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) { /* parse buf2 */ msg (D_PROXY, "auth string: '%s'", buf2); break; } } /* if we are here then auth string was got */ msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); /* receive and discard everything else */ while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) ; /* now send the phase 3 reply */ /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); { const char *np3 = ntlm_phase_3 (p, buf2, &gc); if (!np3) { msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); goto error; } openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); } msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* ok so far... */ /* send empty CR, LF */ if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; #endif } #if PROXY_DIGEST_AUTH else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) { char *pa = p->proxy_authenticate; const int method = p->auth_method; ASSERT(pa); if (method == HTTP_AUTH_DIGEST) { const char *http_method = "CONNECT"; const char *nonce_count = "00000001"; const char *qop = "auth"; const char *username = p->up.username; const char *password = p->up.password; char *opaque_kv = ""; char uri[128]; uint8_t cnonce_raw[8]; uint8_t *cnonce; HASHHEX session_key; HASHHEX response; const char *realm = get_pa_var("realm", pa, &gc); const char *nonce = get_pa_var("nonce", pa, &gc); const char *algor = get_pa_var("algorithm", pa, &gc); const char *opaque = get_pa_var("opaque", pa, &gc); /* generate a client nonce */ ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); /* build the digest response */ openvpn_snprintf (uri, sizeof(uri), "%s:%d", host, port); if (opaque) { const int len = strlen(opaque)+16; opaque_kv = gc_malloc(len, false, &gc); openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); } DigestCalcHA1(algor, username, realm, password, nonce, (char *)cnonce, session_key); DigestCalcResponse(session_key, nonce, nonce_count, (char *)cnonce, qop, http_method, uri, NULL, response); /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", http_method, uri, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; /* send digest response */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", username, realm, nonce, uri, qop, nonce_count, cnonce, response, opaque_kv ); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); processed = true; } else { msg (D_PROXY, "HTTP proxy: digest method not supported"); goto error; } } #endif else if (p->options.auth_retry) { /* figure out what kind of authentication the proxy needs */ char *pa = NULL; const int method = get_proxy_authenticate(sd, p->options.timeout, &pa, NULL, signal_received); if (method != HTTP_AUTH_NONE) { if (pa) msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) { msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); goto error; } p->auth_method = method; store_proxy_authenticate(p, pa); ret = true; goto done; } else { msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); free (pa); goto error; } } else { if (!processed) msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); goto error; } /* clear state */ if (p->options.auth_retry) clear_user_pass_http(); store_proxy_authenticate(p, NULL); } /* check return code, success = 200 */ if (nparms < 1 || status != 200) { msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ dump_residual(sd, p->options.timeout, signal_received); #endif goto error; } /* SUCCESS */ /* receive line from proxy and discard */ if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) goto error; /* * Toss out any extraneous chars, but don't throw away the * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) ; /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ p->queried_creds = false; #if 0 if (lookahead && BLEN (lookahead)) msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); #endif done: gc_free (&gc); return ret; error: /* on error, should we exit or restart? */ if (!*signal_received) *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; }
int CMakeSip::addAuth(char *un, char *pwd, SIP_MSG *psMsg) { HASHHEX HA1; HASHHEX HA2 = ""; HASHHEX respHex32; HDR_AUT * hdrAuth=&psMsg->hdrProxyAuthen; if (psMsg==NULL || un==NULL || pwd==NULL) return -1; DEBUG_T(0,"add proxy auth"); if(psMsg->sipHdr.dstrStatusCode.uiVal==401) { hdrAuth=&sMsg->hdrWWWAuth; } char *pCNonce=hdrAuth->dstrQOP.strVal?(char *)"6ad34fc1":NULL; char *pNC=(char *)"00000001"; if (false==DigestCalcHA1(hdrAuth,(unsigned char *)un,(unsigned char *)pwd, HA1)) return -2; if (false==DigestCalcResponse(HA1, hdrAuth,psMsg->hdrCSeq.uiMethodID,pCNonce,pNC, &strDstAddr, HA2, respHex32)) return -2; if(psMsg->sipHdr.dstrStatusCode.uiVal==407) { ADD_STR(buf,uiLen,"Proxy-Authorization: "); } else { ADD_STR(buf,uiLen,"Authorization: "); } //" //TODO add MD5 or MD5 sess uiLen+= (unsigned int)sprintf(buf+uiLen, "Digest username=\"%s\", realm=\"%.*s\", nonce=\"%.*s\", uri=\"%.*s\", response=\"%.*s\"" ,un ,D_STR(hdrAuth->dstrRealm) ,D_STR(hdrAuth->dstrNonce) ,strDstAddr.len,strDstAddr.s ,32,respHex32 ); if(hdrAuth->iFlag & 4) { uiLen+= (unsigned int)sprintf(buf+uiLen,", algorithm=%.*s",D_STR(hdrAuth->dstrAlgo)); } if(hdrAuth->iFlag & 128) { uiLen+= (unsigned int)sprintf(buf+uiLen,", opaque=\"%.*s\"",D_STR(hdrAuth->dstrOpaque)); } if(hdrAuth->iFlag & 32) { uiLen+= (unsigned int)sprintf(buf+uiLen,", qop=\"%.*s\"",D_STR(hdrAuth->dstrQOP)); if(pNC) { uiLen+= (unsigned int)sprintf(buf+uiLen,", nc=%s",pNC); } if(pCNonce) { uiLen+= (unsigned int)sprintf(buf+uiLen,", cnonce=%s",pCNonce); } } ADD_CRLF(buf,uiLen); return 0; }
/* log a digest user in */ static void authenticateDigestAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) { auth_user_t *auth_user; digest_request_h *digest_request; digest_user_h *digest_user; HASHHEX SESSIONKEY; HASHHEX HA2 = ""; HASHHEX Response; assert(auth_user_request->auth_user != NULL); auth_user = auth_user_request->auth_user; assert(auth_user->scheme_data != NULL); digest_user = auth_user->scheme_data; digest_request = auth_user_request->scheme_data; assert(auth_user_request->scheme_data != NULL); /* if the check has corrupted the user, just return */ if (digest_request->flags.credentials_ok == 3) { return; } /* do we have the HA1 */ if (!digest_user->HA1created) { digest_request->flags.credentials_ok = 2; return; } if (digest_request->nonce == NULL) { /* this isn't a nonce we issued */ digest_request->flags.credentials_ok = 3; return; } DigestCalcHA1(digest_request->algorithm, NULL, NULL, NULL, authenticateDigestNonceNonceb64(digest_request->nonce), digest_request->cnonce, digest_user->HA1, SESSIONKEY); DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce), digest_request->nc, digest_request->cnonce, digest_request->qop, RequestMethodStr[request->method], digest_request->uri, HA2, Response); debug(29, 9) ("\nResponse = '%s'\n" "squid is = '%s'\n", digest_request->response, Response); if (strcasecmp(digest_request->response, Response) != 0) { if (!digest_request->flags.helper_queried) { /* Query the helper in case the password has changed */ digest_request->flags.helper_queried = 1; digest_request->flags.credentials_ok = 2; return; } if (digestConfig->PostWorkaround && request->method != METHOD_GET) { /* Ugly workaround for certain very broken browsers using the * wrong method to calculate the request-digest on POST request. * This should be deleted once Digest authentication becomes more * widespread and such broken browsers no longer are commonly * used. */ DigestCalcResponse(SESSIONKEY, authenticateDigestNonceNonceb64(digest_request->nonce), digest_request->nc, digest_request->cnonce, digest_request->qop, RequestMethodStr[METHOD_GET], digest_request->uri, HA2, Response); if (strcasecmp(digest_request->response, Response)) { digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Incorrect password"); return; } else { const char *useragent = httpHeaderGetStr(&request->header, HDR_USER_AGENT); static struct in_addr last_broken_addr; static int seen_broken_client = 0; if (!seen_broken_client) { last_broken_addr = no_addr; seen_broken_client = 1; } if (memcmp(&last_broken_addr, &request->client_addr, sizeof(last_broken_addr)) != 0) { debug(29, 1) ("\nDigest POST bug detected from %s using '%s'. Please upgrade browser. See Bug #630 for details.\n", inet_ntoa(request->client_addr), useragent ? useragent : "-"); last_broken_addr = request->client_addr; } } } else { digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Incorrect password"); return; } } /* check for stale nonce */ if (!authDigestNonceIsValid(digest_request->nonce, digest_request->nc)) { debug(29, 3) ("authenticateDigestAuthenticateuser: user '%s' validated OK but nonce stale\n", digest_user->username); digest_request->flags.nonce_stale = 1; digest_request->flags.credentials_ok = 3; safe_free(auth_user_request->message); auth_user_request->message = xstrdup("Stale nonce"); return; } /* password was checked and did match */ digest_request->flags.credentials_ok = 1; debug(29, 4) ("authenticateDigestAuthenticateuser: user '%s' validated OK\n", digest_user->username); /* auth_user is now linked, we reset these values * after external auth occurs anyway */ auth_user->expiretime = current_time.tv_sec; return; }