view cinst/windowsstore.c @ 1227:a1e990947172

(issue38) Add long time error handling. A Long Time Error is an error that will be shown to the user if it happened at least seven times with an interval of at least a day between occurances. After one success a long time error will be reset.
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 24 Sep 2014 15:12:40 +0200
parents 698b6a9bd75e
children 265583011f24
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU GPL (v>=2)
 * and comes with ABSOLUTELY NO WARRANTY!
 * See LICENSE.txt for details.
 */
#ifdef WIN32

#include <stdio.h>

#include "windowsstore.h"
#include "errorcodes.h"
#include "listutil.h"
#include "strhelp.h"
#include "logging.h"
#include "util.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)
    {
      ERRORPRINTF ("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)
        {
          ERRORPRINTF ("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;
  bool elevated = is_elevated();

  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)
            {
              ERRORPRINTF ("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)
        {
          ERRORPRINTF ("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();
          ERRORPRINTF ("Error deleting certificate. %s", error);
          free (error);
          continue;
        }
      log_certificate (elevated ? "Local Machine" : "Current User",
                       to_remove[i], false);
    }
  return;
}

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

  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)
        {
          DEBUGPRINTF ("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)
            {
              ERRORPRINTF ("Failed to add certificate: %s \n", error);
              free (error);
            }
        }
      log_certificate (elevated ? "Local Machine" : "Current User",
                       to_install[i], true);
    }
  return;
}

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)
    {
      ERRORPRINTF ("Failed to access store.\n");
      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/