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

📄 win32district.c

📁 IBE是一种非对称密码技术
💻 C
字号:
/* Copyright 2003-2006, Voltage Security, all rights reserved.
 */

#include "vibe.h"
#include "environment.h"
#include "base.h"
#include "libctx.h"
#include "vsdistrict.h"
#include "derhelp.h"
#include "oidlist.h"
#include "ibe.h"
#include "vtime.h"
#include "errorctx.h"

#if VOLT_OS == VOLT_WINDOWS_32

#include <windows.h>
#include <tchar.h>
#include <wininet.h>
#include <stdio.h>
#include <process.h>

typedef struct
{
  HINTERNET hReq;
  int err;
  const char *header;
  const char *postData;
} sendRequestDataT;

typedef struct
{
  HINTERNET hReq;
  char *data;
  ULONG space;
  VoltLibCtx *libCtx;
} doReadDataT;

static unsigned __stdcall DoSendRequest (
   LPVOID pParam
);

static unsigned __stdcall DoReadData (
   LPVOID pParam
);

static unsigned __stdcall DoCheckNetwork (
   LPVOID pParam
);

static int ConfirmConnected (
   HWND uiOwner
);

static unsigned __stdcall DoSendRequest (
   LPVOID pParam
   )
{
  sendRequestDataT *data = (sendRequestDataT *)pParam;

  HttpSendRequestA (
    data->hReq, data->header,
    (data->header != (void *) 0 ? strlen(data->header) : 0), 
    (void *)data->postData,
    (data->postData != (void *) 0 ? strlen(data->postData) : 0));
  data->err = GetLastError();

  return (0);
}

/* This is a callback, a Windows function will call this routine.
 * Therefore, we'll treat this as a Windows function call and not log
 * any errors.
 */
static unsigned __stdcall DoReadData (
   LPVOID pParam
   )
{
  ULONG num, len, read, space;
  VoltLibCtx *libCtx;

  doReadDataT *data = (doReadDataT *)pParam;
  libCtx = data->libCtx;
  space = data->space;

  len = 0;
  num = 1;

  while (num > 0)
  {
    InternetQueryDataAvailable (data->hReq, &num, 0, 0);
    if ((len + num + 1) > space)
    {
      space = len + num + 1;
      data->data = (char *)Z2Realloc (data->data, space);
      if (data->data == (char *)0)
      {
        data->space = 0;
        return (-1);
      }

      data->space = space;
    }

    if (!InternetReadFile (data->hReq, data->data + len, num, &read))
    {
      Z2Free (data->data);
      data->data = (char *)0;
      data->space = 0;
      return (-1);
    }

    len += read;
  }

  data->data[len] = 0;

  return (0);
}

static unsigned __stdcall DoCheckNetwork( LPVOID pParam )
{
  return (0);
}

static int ConfirmConnected (
   HWND uiOwner
   )
{
  return (0);
}

int mDoHTTP (
  VoltHttpRequestInfo *requestInfo,
  char **response,
  int *responseCode,   
  unsigned char *url,  
  int allowBadCert,
  unsigned char *trustStore,
  unsigned long timeOut,
  void *appData
   )
{
  int status, sysRet, tries, err;
  unsigned long len;  
  HINTERNET hInt = (HINTERNET)0;
  HINTERNET hCon = (HINTERNET)0;
  HINTERNET hReq = (HINTERNET)0;
  char header[128];
  char *headerPtr;
  unsigned int threadID;  
  HANDLE hThread = (HANDLE)0;
  VtWinINetTransportInfo *transInfo = (VtWinINetTransportInfo *)0;
  VoltLibCtx *libCtx = (VoltLibCtx *)0;
  VoltTransportCtx *transCtx = (VoltTransportCtx *)0;
  VoltHttpRequestInfoPost *postInfo = (VoltHttpRequestInfoPost *)0;
  VoltIdentityObject *idObj = (VoltIdentityObject *)0;
  sendRequestDataT *reqData = (sendRequestDataT *)0;
  doReadDataT *readData = (doReadDataT *)0;  
  HWND uiOwner = (HWND)0;
  char safeHost[512];
  char safeURL[512];
  char *relative_url = (char *)0;
  char *hostName = (char *)0;
  unsigned char *parsedURL = (unsigned char *)0;  
  unsigned char *postData = (unsigned char *)0;
  URL_COMPONENTSA URLparts ;
  /* HTTPS is the default
   */
  INTERNET_PORT serverPort = INTERNET_DEFAULT_HTTPS_PORT;
  DWORD flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE ;   
  VOLT_DECLARE_ERROR_TYPE (errorType)
  VOLT_DECLARE_FNCT_LINE (fnctLine)

  /* First check the type of request and set some variables accordingly
   */
   if (requestInfo->requestType == VOLT_REQUEST_TYPE_GET)
   {
     libCtx = (VoltLibCtx *)requestInfo->requestData;
   }
   else
   {
     postInfo = (VoltHttpRequestInfoPost *)requestInfo->requestData;
     transCtx = postInfo->transCtx;
     idObj = postInfo->idObj;
     libCtx = (VoltLibCtx *)(transCtx->voltObject.libraryCtx);
     postData = postInfo->postData;
   }

  /* Get the user specified values from the app data.
   * if appData is NULL use the default values.
   */
  if (appData != (void *)0)
    uiOwner = (HANDLE)appData;  

  /* First parse the URL to get the protocol, server and
   *  relative resource locations. Following determines what values
   *  are extracted from the URL. 
   */
  URLparts.dwStructSize = sizeof(URLparts);
  URLparts.dwSchemeLength    = 1;
  URLparts.dwHostNameLength  = 1;
  URLparts.dwUserNameLength  = 1;
  URLparts.dwPasswordLength  = 1;
  URLparts.dwUrlPathLength   = 1;
  URLparts.dwExtraInfoLength = 1;

  /* Initialize the values to NULL. These will be filled when 
   *  InternetCrackUrl function is called.
   */
  URLparts.lpszScheme     = NULL;
  URLparts.lpszHostName   = NULL;
  URLparts.lpszUserName   = NULL;
  URLparts.lpszPassword   = NULL;
  URLparts.lpszUrlPath    = NULL;
  URLparts.lpszExtraInfo  = NULL;

  sysRet = 0;  
  VOLT_SET_FNCT_LINE (fnctLine)
  status = VT_ERROR_MEMORY;
  reqData = (sendRequestDataT *)Z3Malloc (sizeof (sendRequestDataT));
  if (reqData == (sendRequestDataT *)0 )
    goto endWin32DistrictFunction;
  Z2Memset (reqData, 0, sizeof (sendRequestDataT));

  VOLT_SET_FNCT_LINE (fnctLine)
  readData = (doReadDataT *)Z3Malloc (sizeof (doReadDataT));
  if (readData == (doReadDataT *) 0 )
    goto endWin32DistrictFunction;
  Z2Memset (readData, 0, sizeof (doReadDataT));
  readData->libCtx = libCtx;

  status = 0;

  VOLT_SET_FNCT_LINE (fnctLine)
  if (!InternetCrackUrlA (url, 0, 0, &URLparts))
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  /* Allocate the memory to hold the parsed info
   */
  VOLT_SET_FNCT_LINE (fnctLine)
  status = VT_ERROR_MEMORY;
  parsedURL = (unsigned char *)Z2Malloc (
    URLparts.dwHostNameLength + URLparts.dwUrlPathLength + 2, 0);
  if (parsedURL == (unsigned char *)0 )
    goto endWin32DistrictFunction;
  status = 0;

  hostName = parsedURL ;
  relative_url = parsedURL + URLparts.dwHostNameLength + 1;

  Z2Memcpy (hostName, URLparts.lpszHostName, URLparts.dwHostNameLength);
  hostName [URLparts.dwHostNameLength] = 0 ;
  Z2Memcpy (relative_url , URLparts.lpszUrlPath, URLparts.dwUrlPathLength);
  relative_url[URLparts.dwUrlPathLength] = 0;

  /* Canonicalize the URLs just in case they have unsafe chars
   */
  VOLT_SET_FNCT_LINE (fnctLine)
  len = sizeof (safeHost);
  if (!InternetCanonicalizeUrlA (hostName, safeHost, &len, 0))
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  VOLT_SET_FNCT_LINE (fnctLine)
  len = sizeof (safeURL);
  if (!InternetCanonicalizeUrlA (relative_url, safeURL, &len, 0))
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  /* Set the type of connection and Escape both 
   *  hostname and relative path.  
   */
  if (URLparts.nPort == 80)
  {
    flags = INTERNET_FLAG_KEEP_CONNECTION ;
    serverPort = INTERNET_DEFAULT_HTTP_PORT;  
  }  

  VOLT_SET_FNCT_LINE (fnctLine)
  hInt = InternetOpenA (
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)",
    INTERNET_OPEN_TYPE_PRECONFIG, (void *) 0, (void *) 0, 0);
  if (!hInt)
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  VOLT_SET_FNCT_LINE (fnctLine)  
  hCon = InternetConnectA (
    hInt, safeHost, serverPort, (void *) 0, (void *) 0,
    INTERNET_SERVICE_HTTP, 0, 0);
  if (!hCon)
  {    
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  if (postData != (void *) 0)
  {
    sprintf (header, "Content-Type: application/x-www-form-urlencoded");
    headerPtr = header;
  }
  else
  {
    headerPtr = (void *)0;
  }

  tries = 0;

reopen:

  if (requestInfo->requestType == VOLT_REQUEST_TYPE_POST)
  {
    VOLT_SET_FNCT_LINE (fnctLine)
    hReq = HttpOpenRequestA (
      hCon, "POST", safeURL, (void *) 0, (void *) 0, (void *) 0, 
      flags, 0);
  }
  else
  {
    VOLT_SET_FNCT_LINE (fnctLine)
    hReq = HttpOpenRequestA (
      hCon, "GET", safeURL, (void *) 0, (void *) 0, (void *) 0, 
      flags, 0);
  }
  if (!hReq)
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;    
  }

resend:

  reqData->hReq = hReq;
  reqData->postData = postData;
  reqData->header = headerPtr;

  VOLT_SET_FNCT_LINE (fnctLine)
  hThread = (HANDLE)CreateThread (
    (void *) 0, 0, DoSendRequest, reqData, 0, &threadID);
  if (hThread == (void *) 0)
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;    
  }

  VOLT_SET_FNCT_LINE (fnctLine)
  if (WaitForSingleObject (hThread, timeOut) != WAIT_OBJECT_0)
  {
    TerminateThread (hThread, 0);
    CloseHandle (hThread);
    sysRet = ERROR_INTERNET_TIMEOUT;  
    goto endWin32DistrictFunction;
  }
  CloseHandle (hThread);

  err = reqData->err;  

  /* This part needs (a lot of) explanation:
   * There are two cases in which we need to call InternetErrorDlg : bad
   * auth and other (e.g. cert probs)
   * 1) In the bad auth case, if we try to just go back to the
   *    HttpSendRequest and use the same handle, wininet for some reason
   *    doesn't re-POST the data.  So we need to close the handle, and
   *    start again from HttpOpenRequest.  Fortunately, Windows caches the
   *    credentials on the machine, not in hReq, so this works.
   * 2) Unfortunately, for the other case, e.g. invalid CA, if the user
   *    hits OK, we still need to go retry, but wininet caches the user's
   *    OK selection in hReq, so if we close it and reopen, it keeps
   *    asking the user over and over again.
   * Fortunately for us, HttpSendRequest returns two different things in
   * case 1 and case 2.  In case 1, it returns TRUE, so for that case we
   * start over at HttpOpenRequest if InternetErrorDlg returns
   * ERROR_INTERNET_FORCE_RETRY (which basically means the user entered
   * their pass).  In case 2, it returns FALSE, so we just go back to
   * HttpSendRequest if InternetErrorDlg retursn ERROR_SUCCESS.
   *
   * Clearly, WinInet is very broken.  I believe all of the above to be
   * true, but it's very possible that there are cases I didn't account
   * for.  Time will tell.
   */

  if (tries < 3)
  {
    /* Last one is OCSP failure
     */
    if ( (err == ERROR_INTERNET_INVALID_CA) ||
         (err == ERROR_INTERNET_SEC_CERT_CN_INVALID) ||
         (err == ERROR_INTERNET_SEC_CERT_DATE_INVALID) || 
         (err == ERROR_INTERNET_SECURITY_CHANNEL_ERROR) )
    {
      if (allowBadCert == 1)
      {
        VOLT_SET_FNCT_LINE (fnctLine)
        sysRet = InternetErrorDlg (
          uiOwner, hReq, err,
          FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
          FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
          FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, (void *) 0);
        if (sysRet == ERROR_CANCELLED)
          goto endWin32DistrictFunction;

        goto resend;
      }
      else
      {
        sysRet = err;
        goto endWin32DistrictFunction;
      }
    }

    sysRet = InternetErrorDlg (
      uiOwner, hReq, err,
      FLAGS_ERROR_UI_FILTER_FOR_ERRORS |
      FLAGS_ERROR_UI_FLAGS_GENERATE_DATA |
      FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, (void *) 0);

    if (sysRet == ERROR_INTERNET_FORCE_RETRY)
    {
      tries++;
      InternetCloseHandle (hReq);
      goto reopen;
    }
    else if ( (sysRet == ERROR_SUCCESS) &&
              (err == ERROR_INTERNET_HTTP_TO_HTTPS_ON_REDIR) )
    {
      goto resend;
    }
  }

  VOLT_SET_FNCT_LINE (fnctLine)
  len = sizeof (int);
  if (!HttpQueryInfo (
    hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, responseCode,
    &len, (void*) 0))
  {
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  if (*responseCode == 0)
  {
    /* We get here on connection errors, and err will actually contain
     * the error we want.
     */
    sysRet = err;
    goto endWin32DistrictFunction;
  }

  readData->hReq = hReq;

  VOLT_SET_FNCT_LINE (fnctLine)
  hThread = (HANDLE)CreateThread (
    (void*) 0, 0, DoReadData, readData, 0, &threadID);
  if (hThread == (void*) 0)
  {    
    sysRet = GetLastError ();
    goto endWin32DistrictFunction;
  }

  VOLT_SET_FNCT_LINE (fnctLine)
  if (WaitForSingleObject (hThread, timeOut) != WAIT_OBJECT_0)
  {
    TerminateThread (hThread, 0);
    CloseHandle (hThread);    
    sysRet = ERROR_INTERNET_TIMEOUT;
    goto endWin32DistrictFunction;
  }

  CloseHandle (hThread);
  *response = readData->data;
  readData->data = (char *)0;

  sysRet = 0;

endWin32DistrictFunction:
  /* If status is 0, but sysRet is not, figure out what status should
   * be.
   */
  VOLT_SET_ERROR_TYPE (errorType, VT_ERROR_TYPE_PRIMARY)
  if (status == 0)
  {
    VOLT_SET_ERROR_TYPE (
      errorType, VT_ERROR_TYPE_PRIMARY | VT_ERROR_TYPE_OUTSIDE)
    switch (sysRet)
    {
      case 0:
        break;

      case ERROR_INTERNET_INVALID_CA:
      case ERROR_INTERNET_SEC_CERT_CN_INVALID:
      case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
      case ERROR_INTERNET_SECURITY_CHANNEL_ERROR:
        status = VT_ERROR_DISTRICT_NOT_VERIFIED;
        break;

      case ERROR_INTERNET_INVALID_URL:
      case ERROR_INTERNET_UNRECOGNIZED_SCHEME:
      case ERROR_INTERNET_NAME_NOT_RESOLVED:
        status = VT_ERROR_URL;
        break;

      case ERROR_INTERNET_CANNOT_CONNECT :
      case ERROR_INTERNET_CONNECTION_ABORTED :
      case ERROR_INTERNET_NO_DIRECT_ACCESS :
      case ERROR_INTERNET_CONNECTION_RESET :
        status = VT_ERROR_NETWORK_CONNECT;
        break;
      
      case ERROR_INTERNET_TIMEOUT :
        status = VT_ERROR_TIMEOUT;
        break;

      default:
        status = VT_ERROR_UNKNOWN_DISTRICT;
    }
  }
  else
  {
    /* If status is not 0, then sysRet is. Set sysRet to status so that
     * we can return log sysRet as the error.
     */
    sysRet = status;
  }

  if (reqData != (sendRequestDataT *)0 )
    Z2Free (reqData);
  if (parsedURL != (unsigned char *)0 )
    Z2Free (parsedURL);
  if (readData != (doReadDataT *)0 )
  {
    if (readData->data != (char *)0)
      Z2Free (readData->data);
    Z2Free (readData);
  }
  InternetCloseHandle (hReq);
  InternetCloseHandle (hCon);
  InternetCloseHandle (hInt);

  if (status == 0)
    return (0);

  /* If the error is a system error, it is in sysRet and errorType is
   * set to OUTSIDE. If the error is toolkit, sysRet was set to status,
   * so it does indeed contain the appropriate value for the call to
   * Log. And errorType is PRIMARY.
   */
  VOLT_LOG_ERROR (
    (VtLibCtx)libCtx, sysRet, errorType, fnctLine, "mDoHTTP", (char *)0)

  return (status);
}

#endif  /* VOLT_OS == VOLT_WINDOWS_32 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -