view cinst/windowsstore.c @ 285:f23e0ccd5d14

Fix call to windows process. This now uses the correct parameters, emits the signals correctly as errors and waits for the process to finish instead of relying on NOASYNC which did not work for runas and also made it impossible to get the return code
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 02 Apr 2014 13:45:57 +0000
parents 759a898990d1
children 824ef90a6721
line wrap: on
line source
#ifdef WIN32

#include <stdio.h>

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

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)
    {
      char *error = getLastErrorMsg();
      if (error)
        {
          printf ("Failed to create cert context: %s \n", error);
          free (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)
        {
          char *error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to create cert context: %s \n", error);
              free (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. */
          char *error = getLastErrorMsg();
          printf ("Error deleting certificate. %s", error);
          free (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)
        {
          char *error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to add certificate: %s \n", error);
              free (error);
            }
        }
    }
  return;
}

static bool is_elevated() {
    HANDLE hToken = NULL;
    bool ret = false;
    if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
      {
        DWORD elevation;
        DWORD cbSize = sizeof (DWORD);
        if (GetTokenInformation (hToken, TokenElevation, &elevation,
                                 sizeof (TokenElevation), &cbSize))
          {
            ret = elevation;
          }
      }
    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/