Ejemplo n.º 1
0
/* Return the certificate matching SUBJECT_DN.  SEQ should initially be
   set to 0 and bumped up to get the next subject with that DN. */
ksba_cert_t
get_cert_bysubject (const char *subject_dn, unsigned int seq)
{
  /* Simple and very inefficient implementation and API.  fixme! */
  cert_item_t ci;
  int i;

  if (!subject_dn)
    return NULL;

  acquire_cache_read_lock ();
  for (i=0; i < 256; i++)
    {
      for (ci=cert_cache[i]; ci; ci = ci->next)
        if (ci->cert && ci->subject_dn
            && !strcmp (ci->subject_dn, subject_dn))
          if (!seq--)
            {
              ksba_cert_ref (ci->cert);
              release_cache_lock ();
              return ci->cert;
            }
    }

  release_cache_lock ();
  return NULL;
}
Ejemplo n.º 2
0
/* Deinitialize the certificate cache.  With FULL set to true even the
   unused certificate slots are released. */
void
cert_cache_deinit (int full)
{
  cert_item_t ci, ci2;
  int i;

  if (!initialization_done)
    return;

  acquire_cache_write_lock ();

  for (i=0; i < 256; i++)
    for (ci=cert_cache[i]; ci; ci = ci->next)
      clean_cache_slot (ci);

  if (full)
    {
      for (i=0; i < 256; i++)
        {
          for (ci=cert_cache[i]; ci; ci = ci2)
            {
              ci2 = ci->next;
              xfree (ci);
            }
          cert_cache[i] = NULL;
        }
    }

  total_loaded_certificates = 0;
  total_extra_certificates = 0;
  initialization_done = 0;
  release_cache_lock ();
}
Ejemplo n.º 3
0
/* Return a certificate object for the given fingerprint.  FPR is
   expected to be a 20 byte binary SHA-1 fingerprint.  If no matching
   certificate is available in the cache NULL is returned.  The caller
   must release a returned certificate.  Note that although we are
   using reference counting the caller should not just compare the
   pointers to check for identical certificates. */
ksba_cert_t
get_cert_byfpr (const unsigned char *fpr)
{
  cert_item_t ci;

  acquire_cache_read_lock ();
  for (ci=cert_cache[*fpr]; ci; ci = ci->next)
    if (ci->cert && !memcmp (ci->fpr, fpr, 20))
      {
        ksba_cert_ref (ci->cert);
        release_cache_lock ();
        return ci->cert;
      }

  release_cache_lock ();
  return NULL;
}
Ejemplo n.º 4
0
/* Return the certificate matching ISSUER_DN and SERIALNO.  */
ksba_cert_t
get_cert_bysn (const char *issuer_dn, ksba_sexp_t serialno)
{
  /* Simple and inefficient implementation.   fixme! */
  cert_item_t ci;
  int i;

  acquire_cache_read_lock ();
  for (i=0; i < 256; i++)
    {
      for (ci=cert_cache[i]; ci; ci = ci->next)
        if (ci->cert && !strcmp (ci->issuer_dn, issuer_dn)
            && !compare_serialno (ci->sn, serialno))
          {
            ksba_cert_ref (ci->cert);
            release_cache_lock ();
            return ci->cert;
          }
    }

  release_cache_lock ();
  return NULL;
}
Ejemplo n.º 5
0
/* Put CERT into the certificate cache and store the fingerprint of
   the certificate into FPR_BUFFER.  If the certificate is already in
   the cache do not print a warning; just store the
   fingerprint. FPR_BUFFER needs to be at least 20 bytes. */
gpg_error_t
cache_cert_silent (ksba_cert_t cert, void *fpr_buffer)
{
  gpg_error_t err;

  acquire_cache_write_lock ();
  err = put_cert (cert, 0, 0, fpr_buffer);
  release_cache_lock ();
  if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
    err = 0;
  if (err)
    log_error (_("error caching certificate: %s\n"), gpg_strerror (err));
  return err;
}
Ejemplo n.º 6
0
/* Return 0 if the certificate is a trusted certificate. Returns
   GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
   case of systems errors. */
gpg_error_t
is_trusted_cert (ksba_cert_t cert)
{
  unsigned char fpr[20];
  cert_item_t ci;

  cert_compute_fpr (cert, fpr);

  acquire_cache_read_lock ();
  for (ci=cert_cache[*fpr]; ci; ci = ci->next)
    if (ci->cert && !memcmp (ci->fpr, fpr, 20))
      {
        if (ci->flags.trusted)
          {
            release_cache_lock ();
            return 0; /* Yes, it is trusted. */
          }
        break;
      }

  release_cache_lock ();
  return gpg_error (GPG_ERR_NOT_TRUSTED);
}
Ejemplo n.º 7
0
/* Put CERT into the certificate cache.  */
gpg_error_t
cache_cert (ksba_cert_t cert)
{
  gpg_error_t err;

  acquire_cache_write_lock ();
  err = put_cert (cert, 0, 0, NULL);
  release_cache_lock ();
  if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
    log_info (_("certificate already cached\n"));
  else if (!err)
    log_info (_("certificate cached\n"));
  else
    log_error (_("error caching certificate: %s\n"), gpg_strerror (err));
  return err;
}
Ejemplo n.º 8
0
/* Initialize the certificate cache if not yet done.  */
void
cert_cache_init (void)
{
  char *dname;

  if (initialization_done)
    return;
  init_cache_lock ();
  acquire_cache_write_lock ();

  dname = make_filename (gnupg_sysconfdir (), "trusted-certs", NULL);
  load_certs_from_dir (dname, 1);
  xfree (dname);

  dname = make_filename (gnupg_sysconfdir (), "extra-certs", NULL);
  load_certs_from_dir (dname, 0);
  xfree (dname);

  initialization_done = 1;
  release_cache_lock ();

  cert_cache_print_stats ();
}
Ejemplo n.º 9
0
/* Return the certificate matching SUBJECT_DN and (if not NULL)
   KEYID. If it is not already in the cache, try to find it from other
   resources.  Note, that the external search does not work for user
   certificates because the LDAP lookup is on the caCertificate
   attribute. For our purposes this is just fine.  */
ksba_cert_t
find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
{
  gpg_error_t err;
  int seq;
  ksba_cert_t cert = NULL;
  cert_fetch_context_t context = NULL;
  ksba_sexp_t subj;

  /* If we have certificates from an OCSP request we first try to use
     them.  This is because these certificates will really be the
     required ones and thus even in the case that they can't be
     uniquely located by the following code we can use them.  This is
     for example required by Telesec certificates where a keyId is
     used but the issuer certificate comes without a subject keyId! */
  if (ctrl->ocsp_certs && subject_dn)
    {
      cert_item_t ci;
      cert_ref_t cr;
      int i;

      /* For efficiency reasons we won't use get_cert_bysubject here. */
      acquire_cache_read_lock ();
      for (i=0; i < 256; i++)
        for (ci=cert_cache[i]; ci; ci = ci->next)
          if (ci->cert && ci->subject_dn
              && !strcmp (ci->subject_dn, subject_dn))
            for (cr=ctrl->ocsp_certs; cr; cr = cr->next)
              if (!memcmp (ci->fpr, cr->fpr, 20))
                {
                  ksba_cert_ref (ci->cert);
                  release_cache_lock ();
                  return ci->cert; /* We use this certificate. */
                }
      release_cache_lock ();
      if (DBG_LOOKUP)
        log_debug ("find_cert_bysubject: certificate not in ocsp_certs\n");
    }


  /* First we check whether the certificate is cached.  */
  for (seq=0; (cert = get_cert_bysubject (subject_dn, seq)); seq++)
    {
      if (!keyid)
        break; /* No keyid requested, so return the first one found. */
      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj)
          && !cmp_simple_canon_sexp (keyid, subj))
        {
          xfree (subj);
          break; /* Found matching cert. */
        }
      xfree (subj);
      ksba_cert_release (cert);
    }
  if (cert)
    return cert; /* Done.  */

  if (DBG_LOOKUP)
    log_debug ("find_cert_bysubject: certificate not in cache\n");

  /* Ask back to the service requester to return the certificate.
     This is because we can assume that he already used the
     certificate while checking for the CRL. */
  if (keyid)
    cert = get_cert_local_ski (ctrl, subject_dn, keyid);
  else
    {
      /* In contrast to get_cert_local_ski, get_cert_local uses any
         passed pattern, so we need to make sure that an exact subject
         search is done. */
      char *buf;

      buf = xtrymalloc (1 + strlen (subject_dn) + 1);
      if (!buf)
        {
          log_error ("can't allocate enough memory: %s\n", strerror (errno));
          return NULL;
        }
      strcpy (stpcpy (buf, "/"), subject_dn);
      cert = get_cert_local (ctrl, buf);
      xfree (buf);
    }
  if (cert)
    {
      cache_cert (cert);
      return cert; /* Done. */
    }

  if (DBG_LOOKUP)
    log_debug ("find_cert_bysubject: certificate not returned by caller"
               " - doing lookup\n");

  /* Locate the certificate using external resources. */
  while (!cert)
    {
      char *subjdn;

      if (!context)
        {
          err = ca_cert_fetch (ctrl, &context, subject_dn);
          if (err)
            {
              log_error (_("error fetching certificate by subject: %s\n"),
                         gpg_strerror (err));
              break;
            }
        }

      err = fetch_next_ksba_cert (context, &cert);
      if (err)
        {
          log_error (_("error fetching certificate by subject: %s\n"),
                     gpg_strerror (err) );
          break;
        }

      subjdn = ksba_cert_get_subject (cert, 0);
      if (strcmp (subject_dn, subjdn))
        {
          log_info ("find_cert_bysubject: subject DN does not match\n");
          ksba_cert_release (cert);
          cert = NULL;
          ksba_free (subjdn);
          continue;
        }


      if (DBG_LOOKUP)
        {
          log_debug ("   considering certificate (/");
          dump_string (subjdn);
          log_printf (")\n");
        }
      ksba_free (subjdn);

      /* If no key ID has been provided, we return the first match.  */
      if (!keyid)
        {
          cache_cert (cert);
          if (DBG_LOOKUP)
            log_debug ("   found\n");
          break; /* Ready.  */
        }

      /* With the key ID given we need to compare it.  */
      if (!ksba_cert_get_subj_key_id (cert, NULL, &subj))
        {
          if (!cmp_simple_canon_sexp (keyid, subj))
            {
              ksba_free (subj);
              cache_cert (cert);
              if (DBG_LOOKUP)
                log_debug ("   found\n");
              break; /* Ready.  */
            }
        }

      ksba_free (subj);
      ksba_cert_release (cert);
      cert = NULL;
    }

  end_cert_fetch (context);
  return cert;
}
int main(int argc, char *argv[])
{
	int retc = 0;
	int ret;

	char *hostfile = NULL;
	char *cachefile = NULL;
	char *xml = NULL;
	char *xmlfile = NULL;

	int cachefd = -1;

	char value[64];
	char units[64];

	int retry_count = 0, ret2;

	if (get_config(argc, argv) < 0) {
		retc = 2;
		goto cleanup;
	}

	if (config.heartbeat > 0) {
		debug("Checking heartbeat for %s with threshold %d\n",
		      config.host, config.heartbeat);
	} else {
		debug("Checking %s for %s metric\n",
		      config.host, config.metric);
	}

	hostfile = get_full_cache_path(config.cachepath, config.host);
	cachefile = get_full_cache_path(config.cachepath, config.cachename);

retry:
	debug("Checking cache at %s\n", cachefile);
	ret = check_cache_age(cachefile);
	if (ret < 0) {
		printf("ERROR: Unable to check cache age.\n");
		retc = 2;
		goto cleanup;
	}

	if (ret < config.max_age) {
		debug("Cache age is %d\n", ret);
	} else {
		debug("Cache age greater than configured max (%d >= %d)\n", ret, config.max_age);
		debug("Connecting to %s on port %d\n", config.gmetad_host, config.gmetad_port);
		ret = fetch_xml(config.gmetad_host, config.gmetad_port, &xml);
		if (ret < 0) {
			printf("ERROR: Unable to get XML data: %d.\n", ret);
			retc = 2;
			goto cleanup;
		}

		debug("Read %d bytes from %s\n", ret, config.gmetad_host);
		if (config.dump) {
			xmlfile = calloc((strlen(config.cachepath) + 9), sizeof(char));
			sprintf(xmlfile, "%s/dump.xml", config.cachepath);

			debug("Dumping XML to %s\n", xmlfile);
			if (write_xml(xml, ret, xmlfile) < 0) {
				printf("ERROR: Unable to dump XML.\n");
				retc = 2;
				goto cleanup;
			}
		}

		ret2 = get_cache_lock(cachefile, &cachefd);
		if (ret2 < 0) {
			if (retry_count == MAX_RETRY) {
				printf("ERROR: Unable to get cache lock after retrying %d times. Stale lock?", retry_count);
				retc = 2;
				goto cleanup;
			} else {
				backoff(retry_count / 2.0);
			}

			retry_count++;
			goto retry;
		}

		debug("Parsing XML into %s\n", config.cachepath);
		ret = parse_xml_to_cache(xml, ret, config.cachepath, cachefile);
		if (ret < 0) {
			printf("ERROR: Unable to parse XML.\n");
			retc = 2;
			goto cleanup;
		}

		touch_cache_lock(cachefile);
		release_cache_lock(cachefile, &cachefd);
	}

	if (config.heartbeat > 0) {
		strcpy(config.metric, "#REPORTED");
	}

	if (locate_hostfile(hostfile) < 0) {
		printf("CRITICAL - Unable to locate cache file for %s\n", config.host);
		retc = 2;
		goto cleanup;
	}

	debug("Fetching %s metric from cache at %s\n", config.metric, hostfile);

	ret = fetch_value_from_cache(hostfile, config.metric, value, units);
	if (ret < 0) {
		printf("CRITICAL - Unable to read cache at %s\n", hostfile);
		retc = 2;
		goto cleanup;
	} else if (ret == 0) {
		printf("CRITICAL - Metric %s not found\n", config.metric);
		retc = 2;
		goto cleanup;
	}

	debug("Checking...\n");

	if (config.heartbeat > 0) {
		int diff = time(NULL) - strtol(value, NULL, 10);
		if (diff > config.heartbeat) {
			printf("CRITICAL - %d over threshold %d\n", diff, config.heartbeat);
			retc = 2;
			goto cleanup;
		} else {
			printf("OK - %d\n", diff);
			goto cleanup;
		}
	}

	if (threshold_check(config.critical, value)) {
		printf("CRITICAL - %s %s\n", value, units);
		retc = 2;
	} else {
		if (threshold_check(config.warning, value)) {
			printf("WARNING - %s %s\n", value, units);
			retc = 1;
		} else {
			printf("OK - %s %s\n", value, units);
		}
	}

cleanup:
	if (cachefd >= 0) {
		release_cache_lock(cachefile, &cachefd);
	}

	if (xml != NULL)
		free(xml);

	if (xmlfile != NULL)
		free(xmlfile);

	if (hostfile != NULL)
		free(hostfile);

	if (cachefile != NULL)
		free(cachefile);

	exit(retc);
}