view cinst/windowsstore.c @ 247:4de97f74d038

Check for process elevation and write into system store accordingly
author Andre Heinecke <aheinecke@intevation.de>
date Mon, 31 Mar 2014 08:02:46 +0000
parents 53ea9b975d1c
children 3595ea4fd3fb
line wrap: on
line source
#ifdef WIN32

#include <stdio.h>

#include "windowsstore.h"
#include "errorcodes.h"
#include "listutil.h"
#include "strhelp.h"

static LPWSTR
getLastErrorMsg()
{
  LPWSTR bufPtr = NULL;
  DWORD err = GetLastError();
  FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
                  FORMAT_MESSAGE_FROM_SYSTEM |
                  FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL, err, 0, (LPWSTR) &bufPtr, 0, NULL);
  if (!bufPtr)
    {
      HMODULE hWinhttp = GetModuleHandleW (L"crypt32");
      if (hWinhttp)
        {
          FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_HMODULE |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
                          hWinhttp, HRESULT_CODE (err), 0,
                          (LPWSTR) &bufPtr, 0, NULL);
        }
    }
  if (!bufPtr)
    printf ("Error getting last error for code: %lx \n", err);
  return bufPtr;
}

static PCCERT_CONTEXT
b64_to_cert_context(char *b64_data, size_t b64_size)
{
  size_t buf_size = 0;
  char *buf = NULL;
  PCCERT_CONTEXT pCert = NULL;
  int ret = -1;

  ret = str_base64_decode (&buf, &buf_size, b64_data, b64_size);

  if (ret != 0)
    {
      printf ("decoding certificate failed\n");
      return NULL;
    }

  pCert = CertCreateContext (CERT_STORE_CERTIFICATE_CONTEXT,
                             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                             (const PBYTE) buf,
                             (DWORD) buf_size,
                             0,
                             NULL);
  free (buf); /* Windows has a copy */

  if (pCert == NULL)
    {
      LPWSTR error = getLastErrorMsg();
      if (error)
        {
          printf ("Failed to create cert context: %S \n", error);
          LocalFree (error);
        }
      return NULL;
    }
  return pCert;
}

void
do_remove(HCERTSTORE hStore, char **to_remove)
{
  PCCERT_CONTEXT pCert = NULL;
  unsigned int i = 0;

  if (!to_remove)
    {
      return;
    }

  for (i=0; to_remove[i]; i++)
    {
      PCCERT_CONTEXT pc_to_remove = NULL;

      pc_to_remove = b64_to_cert_context(to_remove[i],
                                         strnlen(to_remove[i], MAX_LINE_LENGTH));

      if (pc_to_remove == NULL)
        {
          LPWSTR error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to create cert context: %S \n", error);
              LocalFree (error);
            }
          continue;
        }

      pCert = CertFindCertificateInStore (hStore,
                                          X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                          0,
                                          CERT_FIND_EXISTING,
                                          pc_to_remove,
                                          NULL);

      CertFreeCertificateContext (pc_to_remove);

      if (pCert == NULL)
        {
          printf ("Did not find certificate\n");
          continue;
        }

      if (!CertDeleteCertificateFromStore (pCert))
        {
          /* From MSDN:
             The CertDeleteCertificateFromStore function always frees
             pCertContext by calling the CertFreeCertificateContext
             function, even if an error is encountered. */
          LPWSTR error = getLastErrorMsg();
          printf ("Error deleting certificate. %S", error);
          LocalFree (error);
          continue;
        }
    }
  return;
}

void
do_install(HCERTSTORE hStore, char **to_install)
{
  int i = 0,
      ret = -1;

  if (!to_install)
    {
      return;
    }

  for (i = 0; to_install[i]; i++)
    {
      PCCERT_CONTEXT pc_to_add = NULL;
      PCCERT_CONTEXT found_cert = NULL;

      pc_to_add = b64_to_cert_context(to_install[i],
                                      strnlen(to_install[i], MAX_LINE_LENGTH));

      if (pc_to_add == NULL)
        {
          continue;
        }

      found_cert = CertFindCertificateInStore (hStore,
                                               X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                               0,
                                               CERT_FIND_EXISTING,
                                               pc_to_add,
                                               NULL);
      if (found_cert != NULL)
        {
          printf ("Certificate already in store\n");
          CertFreeCertificateContext (found_cert);
          CertFreeCertificateContext (pc_to_add);
          continue;
        }

      ret = CertAddCertificateContextToStore (hStore,
                                              pc_to_add,
                                              CERT_STORE_ADD_ALWAYS,
                                              NULL);
      CertFreeCertificateContext (pc_to_add);
      if (!ret)
        {
          LPWSTR error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to add certificate: %S \n", error);
              LocalFree (error);
            }
        }
    }
  return;
}

static bool is_elevated() {
    HANDLE hToken = NULL;
    bool ret = false;
    if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
      {
        TOKEN_ELEVATION elevation;
        DWORD cbSize = sizeof (TOKEN_ELEVATION);
        if (GetTokenInformation (hToken, TokenElevation, &elevation,
                                 sizeof (TokenElevation), &cbSize))
          {
            ret = elevation.TokenIsElevated;
          }
      }
    if (hToken)
      CloseHandle (hToken);

    return ret;
}

int
write_stores_win (char **to_install, char **to_remove)
{
  HCERTSTORE hStore = NULL;

  if (!to_install && !to_remove)
    {
      /* Nothing to do */
      return 0;
    }

  if (!is_elevated())
    {
      hStore = CertOpenStore (CERT_STORE_PROV_SYSTEM, 0,
                              0, CERT_SYSTEM_STORE_CURRENT_USER, L"Root");
    }
  else
    {
      hStore = CertOpenStore (CERT_STORE_PROV_SYSTEM, 0,
                              0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root");
    }

  if (!hStore)
    {
      return ERR_STORE_ACCESS_DENIED;
    }

  /* Do the actual work */
  do_install (hStore, to_install);

  do_remove (hStore, to_remove);

  if (hStore)
    {
      CertCloseStore (hStore, 0);
    }
  return 0;
}
#endif // WIN32

http://wald.intevation.org/projects/trustbridge/