view cinst/windowsstore.c @ 217:83a015f2e078

Remove leftover incrementation of i from former loop style. Fixes a crash when adding only one certificate.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 26 Mar 2014 20:14:22 +0100
parents 292e2cb60ef0
children 8fb12af98960
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 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++)
    {
      char *asn1_data = NULL;
      size_t asn1_size = 0;
      int ret = -1;
      PCCERT_CONTEXT pc_to_remove = NULL;

      ret = str_base64_decode (&asn1_data, &asn1_size, to_remove[i],
                               strnlen(to_remove[i], MAX_LINE_LENGTH));
      /* Decoding / parsing errors in here should not happen at all.
         The only errors which are not a bug would be out of memory or
         if the signed certificate list contained an invalid certificate. */
      if (ret != 0)
        {
          printf ("Error base64 certificate.\n");
          continue;
        }

      pc_to_remove = CertCreateContext (CERT_STORE_CERTIFICATE_CONTEXT,
                                        X509_ASN_ENCODING,
                                        (const PBYTE) asn1_data,
                                        (DWORD) asn1_size,
                                        0,
                                        NULL);
      free (asn1_data); /* Windows has a copy */
      if (pc_to_remove == NULL)
        {
          LPWSTR error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to add certificate: %S \n", error);
              LocalFree (error);
            }
          continue;
        }

      pCert = CertFindCertificateInStore (hStore,
                                          X509_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;
}

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

  if (!to_install)
    {
      return;
    }

  for (i = 0; to_install[i]; i++)
    {
      size_t cert_len = strnlen (to_install[i], MAX_LINE_LENGTH),
             buf_size = 0;
      char *buf = NULL;

      ret = str_base64_decode (&buf, &buf_size, to_install[i], cert_len);

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

      printf ("Adding cert %s\n", to_install[i]);

      ret = CertAddEncodedCertificateToStore (hStore,
                                              X509_ASN_ENCODING,
                                              (PBYTE) buf,
                                              buf_size,
                                              CERT_STORE_ADD_ALWAYS,
                                              NULL);

      if (!ret)
        {
          LPWSTR error = getLastErrorMsg();
          if (error)
            {
              printf ("Failed to add certificate: %S \n", error);
              LocalFree (error);
            }
        }
      free (buf);
    }
  return;
}

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

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

  if (user_store)
    {
      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/