コード例 #1
0
ファイル: proxy.c プロジェクト: ThomasHabets/openvpn
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;
}
コード例 #2
0
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;
}
コード例 #3
0
ファイル: auth_digest.c プロジェクト: OPSF/uClinux
/* 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;
}