Blame tests/run-threaded.c

Packit Service 0ef63b
/* run-threaded.c  - Helper to put GPGME under multithread load.
Packit Service 0ef63b
 * Copyright (C) 2018 by Bundesamt für Sicherheit in der Informationstechnik
Packit Service 0ef63b
 *               Software engineering by Intevation GmbH
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * This file is part of GPGME.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 0ef63b
 * under the terms of the GNU Lesser General Public License as
Packit Service 0ef63b
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 0ef63b
 * the License, or (at your option) any later version.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 0ef63b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0ef63b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 0ef63b
 * Lesser General Public License for more details.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * You should have received a copy of the GNU Lesser General Public
Packit Service 0ef63b
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 0ef63b
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 0ef63b
 */
Packit Service 0ef63b
Packit Service 0ef63b
/* The idea of this test is not to be run as unit test but as part
Packit Service 0ef63b
 * of development to find threading issues and resource leaks. */
Packit Service 0ef63b
Packit Service 0ef63b
#ifdef HAVE_CONFIG_H
Packit Service 0ef63b
# include <config.h>
Packit Service 0ef63b
#endif
Packit Service 0ef63b
Packit Service 0ef63b
#include <gpgme.h>
Packit Service 0ef63b
#include <gpg-error.h>
Packit Service 0ef63b
Packit Service 0ef63b
#include <stdlib.h>
Packit Service 0ef63b
#include <stdio.h>
Packit Service 0ef63b
#include <string.h>
Packit Service 0ef63b
#include <sys/stat.h>
Packit Service 0ef63b
#include <sys/types.h>
Packit Service 0ef63b
#include <fcntl.h>
Packit Service 0ef63b
Packit Service 0ef63b
#include <unistd.h>
Packit Service 0ef63b
Packit Service 0ef63b
#define PGM "run-threaded"
Packit Service 0ef63b
Packit Service 0ef63b
#include "run-support.h"
Packit Service 0ef63b
Packit Service 0ef63b
static volatile int stop;
Packit Service 0ef63b
static volatile int thread_cnt;
Packit Service 0ef63b
static volatile int running_threads;
Packit Service 0ef63b
static int verbose;
Packit Service 0ef63b
static int data_type;
Packit Service 0ef63b
static int mem_only;
Packit Service 0ef63b
Packit Service 0ef63b
#ifdef HAVE_W32_SYSTEM
Packit Service 0ef63b
# include <windows.h>
Packit Service 0ef63b
# define THREAD_RET DWORD CALLBACK
Packit Service 0ef63b
Packit Service 0ef63b
static void
Packit Service 0ef63b
create_thread (THREAD_RET (*func) (void *), void *arg)
Packit Service 0ef63b
{
Packit Service 0ef63b
  HANDLE hd = CreateThread (NULL, 0, func, arg, 0, NULL);
Packit Service 0ef63b
  if (hd == INVALID_HANDLE_VALUE)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fprintf (stderr, "Failed to create thread!\n");
Packit Service 0ef63b
      exit (1);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  running_threads++;
Packit Service 0ef63b
  CloseHandle (hd);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
#else
Packit Service 0ef63b
# include <pthread.h>
Packit Service 0ef63b
# define THREAD_RET void *
Packit Service 0ef63b
Packit Service 0ef63b
static void
Packit Service 0ef63b
create_thread (THREAD_RET (func) (void *), void *arg)
Packit Service 0ef63b
{
Packit Service 0ef63b
  pthread_t handle;
Packit Service 0ef63b
  running_threads++;
Packit Service 0ef63b
  if (pthread_create (&handle, NULL, func, arg))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fprintf (stderr, "Failed to create thread!\n");
Packit Service 0ef63b
      exit (1);
Packit Service 0ef63b
    }
Packit Service 0ef63b
}
Packit Service 0ef63b
#endif
Packit Service 0ef63b
Packit Service 0ef63b
#include <gpg-error.h>
Packit Service 0ef63b
Packit Service 0ef63b
GPGRT_LOCK_DEFINE (out_lock);
Packit Service 0ef63b
Packit Service 0ef63b
#define out(format, ...) \
Packit Service 0ef63b
  { \
Packit Service 0ef63b
    gpgrt_lock_lock (&out_lock); \
Packit Service 0ef63b
    printf (format "\n", ##__VA_ARGS__); \
Packit Service 0ef63b
    gpgrt_lock_unlock (&out_lock); \
Packit Service 0ef63b
  }
Packit Service 0ef63b
Packit Service 0ef63b
#define errpoint \
Packit Service 0ef63b
{ \
Packit Service 0ef63b
  out ("Error on %i", __LINE__); \
Packit Service 0ef63b
  exit (1); \
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
#define log(format, ...) \
Packit Service 0ef63b
if (verbose) \
Packit Service 0ef63b
  { \
Packit Service 0ef63b
    gpgrt_lock_lock (&out_lock); \
Packit Service 0ef63b
    printf (format "\n", ##__VA_ARGS__); \
Packit Service 0ef63b
    gpgrt_lock_unlock (&out_lock); \
Packit Service 0ef63b
  }
Packit Service 0ef63b
Packit Service 0ef63b
/* Lazy mans signal */
Packit Service 0ef63b
GPGRT_LOCK_DEFINE (threads_lock);
Packit Service 0ef63b
Packit Service 0ef63b
void del_thread (void)
Packit Service 0ef63b
{
Packit Service 0ef63b
  if (--running_threads == 0)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      gpgrt_lock_unlock (&threads_lock);
Packit Service 0ef63b
    }
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
static int
Packit Service 0ef63b
show_usage (int ex)
Packit Service 0ef63b
{
Packit Service 0ef63b
  fputs ("usage: " PGM " [options] [messages]\n\n"
Packit Service 0ef63b
         "Options:\n"
Packit Service 0ef63b
         "  --verbose     run in verbose mode\n"
Packit Service 0ef63b
         "  --no-list     do not do keylistings\n"
Packit Service 0ef63b
         "  --allow-del   allow to delete keys after import\n"
Packit Service 0ef63b
         "  --data-type   mem function to use one of:\n"
Packit Service 0ef63b
         "                    1: fstream\n"
Packit Service 0ef63b
         "                    2: posix fd\n"
Packit Service 0ef63b
         "                    3: memory\n"
Packit Service 0ef63b
         "                    4: gpgrt_stream\n"
Packit Service 0ef63b
         "                    default: random\n"
Packit Service 0ef63b
/*         "  --mem-cache   read data only once and then work on memory\n"
Packit Service 0ef63b
           "                exlusive with data-type option\n" */
Packit Service 0ef63b
         "  --threads N   use 4+N threads (4 are used for keylisting"
Packit Service 0ef63b
" default 1)\n"
Packit Service 0ef63b
         "  --repeat  N   do N repeats on the messages (default 1)\n\n"
Packit Service 0ef63b
         "Note: The test does keylistings of both S/MIME and OpenPGP\n"
Packit Service 0ef63b
         "      in the background while running operations on the\n"
Packit Service 0ef63b
         "      messages, depending on their type.\n"
Packit Service 0ef63b
         "      (Currently decrypt / verify).\n\n"
Packit Service 0ef63b
         "      Without messages only keylistings will be done.\n"
Packit Service 0ef63b
         , stderr);
Packit Service 0ef63b
  exit (ex);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
struct msg_list_s
Packit Service 0ef63b
{
Packit Service 0ef63b
  const char *file_name;
Packit Service 0ef63b
  struct msg_list_s *next;
Packit Service 0ef63b
};
Packit Service 0ef63b
typedef struct msg_list_s *msg_list_t;
Packit Service 0ef63b
Packit Service 0ef63b
struct data_s
Packit Service 0ef63b
{
Packit Service 0ef63b
  int fd;
Packit Service 0ef63b
  FILE *file;
Packit Service 0ef63b
  gpgrt_stream_t stream;
Packit Service 0ef63b
  unsigned char *mem;
Packit Service 0ef63b
  gpgme_data_t dh;
Packit Service 0ef63b
};
Packit Service 0ef63b
typedef struct data_s *data_t;
Packit Service 0ef63b
Packit Service 0ef63b
struct keylist_args_s
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_protocol_t proto;
Packit Service 0ef63b
  int secret;
Packit Service 0ef63b
};
Packit Service 0ef63b
typedef struct keylist_args_s *keylist_args_t;
Packit Service 0ef63b
Packit Service 0ef63b
static volatile int keylists;
Packit Service 0ef63b
Packit Service 0ef63b
static int allow_del;
Packit Service 0ef63b
Packit Service 0ef63b
static THREAD_RET
Packit Service 0ef63b
do_keylist (void *keylist_args)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_key_t key;
Packit Service 0ef63b
Packit Service 0ef63b
  keylist_args_t args = (keylist_args_t) keylist_args;
Packit Service 0ef63b
Packit Service 0ef63b
  log ("Keylist %i, Protocol: %s, Secret %i",
Packit Service 0ef63b
       keylists++,
Packit Service 0ef63b
       args->proto == GPGME_PROTOCOL_CMS ? "CMS" : "OpenPGP",
Packit Service 0ef63b
       args->secret);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_set_protocol (ctx, args->proto);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_op_keylist_start (ctx, NULL, args->secret);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  while (!(err = gpgme_op_keylist_next (ctx, &key)))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      gpgme_key_unref (key);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpgme_err_code (err) != GPG_ERR_EOF)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fail_if_err (err);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
Packit Service 0ef63b
  if (!stop)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      create_thread (do_keylist, keylist_args);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  del_thread ();
Packit Service 0ef63b
  return 0;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
static unsigned char *
Packit Service 0ef63b
get_file (const char *fname, size_t *r_size)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpg_error_t err;
Packit Service 0ef63b
  gpgrt_stream_t fp;
Packit Service 0ef63b
  struct stat st;
Packit Service 0ef63b
  unsigned char *buf;
Packit Service 0ef63b
  size_t buflen;
Packit Service 0ef63b
Packit Service 0ef63b
  fp = gpgrt_fopen (fname, "r");
Packit Service 0ef63b
  if (!fp)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error_from_syserror ();
Packit Service 0ef63b
      fprintf (stderr, "Error: can't open '%s': %s\n", fname,
Packit Service 0ef63b
               gpg_strerror (err));
Packit Service 0ef63b
      return NULL;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (fstat (gpgrt_fileno(fp), &st))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error_from_syserror ();
Packit Service 0ef63b
      fprintf (stderr, "Error: can't stat '%s': %s\n", fname,
Packit Service 0ef63b
               gpg_strerror (err));
Packit Service 0ef63b
      gpgrt_fclose (fp);
Packit Service 0ef63b
      return NULL;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  buflen = st.st_size;
Packit Service 0ef63b
  buf = malloc (buflen+1);
Packit Service 0ef63b
  if (!buf)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fprintf (stderr, "Error: no mem\n");
Packit Service 0ef63b
      gpgrt_fclose (fp);
Packit Service 0ef63b
      return NULL;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpgrt_fread (buf, buflen, 1, fp) != 1)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error_from_syserror ();
Packit Service 0ef63b
      fprintf (stderr, "error reading '%s': %s\n", fname,
Packit Service 0ef63b
               gpg_strerror (err));
Packit Service 0ef63b
      gpgrt_fclose (fp);
Packit Service 0ef63b
      free (buf);
Packit Service 0ef63b
      return NULL;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  buf[buflen] = 0;
Packit Service 0ef63b
  gpgrt_fclose (fp);
Packit Service 0ef63b
Packit Service 0ef63b
  if (r_size)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      *r_size = buflen;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  return buf;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
/** Lets use random data. This should also introduce a bit
Packit Service 0ef63b
    of randomness into the system by changing the runtimes
Packit Service 0ef63b
    of various data functions. Esp. Mem against the file ops. */
Packit Service 0ef63b
data_t
Packit Service 0ef63b
random_data_new (const char *fname)
Packit Service 0ef63b
{
Packit Service 0ef63b
  data_t ret = calloc (1, sizeof (struct data_s));
Packit Service 0ef63b
  int data_rand;
Packit Service 0ef63b
Packit Service 0ef63b
  ret->fd = -1;
Packit Service 0ef63b
Packit Service 0ef63b
  if (data_type)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      data_rand = data_type;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else
Packit Service 0ef63b
    {
Packit Service 0ef63b
      data_rand = rand () % 3;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (data_rand == 0) /* stream */
Packit Service 0ef63b
    {
Packit Service 0ef63b
      FILE *f_stream = fopen (fname, "rb");
Packit Service 0ef63b
      if (!f_stream)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          errpoint;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      fail_if_err (gpgme_data_new_from_stream (&(ret->dh), f_stream));
Packit Service 0ef63b
      ret->file = f_stream;
Packit Service 0ef63b
      return ret;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  if (data_rand == 1) /* fd */
Packit Service 0ef63b
    {
Packit Service 0ef63b
      int fd = open (fname, O_RDONLY);
Packit Service 0ef63b
      gpgme_data_t dh;
Packit Service 0ef63b
      if (fd == -1)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          errpoint;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      fail_if_err (gpgme_data_new_from_fd (&dh, fd));
Packit Service 0ef63b
      ret->fd = fd;
Packit Service 0ef63b
      ret->dh = dh;
Packit Service 0ef63b
      return ret;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  if (data_rand == 2) /* mem */
Packit Service 0ef63b
    {
Packit Service 0ef63b
      unsigned char *mem;
Packit Service 0ef63b
      size_t size;
Packit Service 0ef63b
Packit Service 0ef63b
      mem = get_file (fname, &size);
Packit Service 0ef63b
      if (!mem)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          errpoint;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      fail_if_err (gpgme_data_new_from_mem (&(ret->dh),
Packit Service 0ef63b
                                            (const char *)mem,
Packit Service 0ef63b
                                            size, 0));
Packit Service 0ef63b
      ret->mem = mem;
Packit Service 0ef63b
      return ret;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  if (data_rand == 3) /* estream */
Packit Service 0ef63b
    {
Packit Service 0ef63b
      gpgrt_stream_t stream = gpgrt_fopen (fname, "rb");
Packit Service 0ef63b
Packit Service 0ef63b
      if (!stream)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          errpoint;
Packit Service 0ef63b
        }
Packit Service 0ef63b
Packit Service 0ef63b
      fail_if_err (gpgme_data_new_from_estream (&(ret->dh), stream));
Packit Service 0ef63b
      ret->stream = stream;
Packit Service 0ef63b
      return ret;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  /* notreached */
Packit Service 0ef63b
  return ret;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
random_data_close (data_t data)
Packit Service 0ef63b
{
Packit Service 0ef63b
  if (data->dh)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      gpgme_data_release (data->dh);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (data->fd != -1)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      close (data->fd);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else if (data->file)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fclose (data->file);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else if (data->stream)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      gpgrt_fclose (data->stream);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else if (data->mem)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      free (data->mem);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  free (data);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
verify (const char *fname, gpgme_protocol_t proto)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
  gpgme_data_t output;
Packit Service 0ef63b
  char *msg;
Packit Service 0ef63b
  size_t msg_len;
Packit Service 0ef63b
  data_t data = random_data_new (fname);
Packit Service 0ef63b
Packit Service 0ef63b
  log ("Starting verify on: %s with protocol %s", fname,
Packit Service 0ef63b
       proto == GPGME_PROTOCOL_CMS ? "CMS" : "OpenPGP");
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_data_new (&output);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_set_protocol (ctx, proto);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_op_verify (ctx, data->dh, NULL, output);
Packit Service 0ef63b
  out ("Data: %p, %i %p %p %p", data->dh,
Packit Service 0ef63b
       data->fd, data->file, data->stream,
Packit Service 0ef63b
       data->mem);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  msg = gpgme_data_release_and_get_mem (output, &msg_len);
Packit Service 0ef63b
Packit Service 0ef63b
  if (msg_len)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      log ("Verify result \n'%.*s'", (int)msg_len, msg);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
Packit Service 0ef63b
  random_data_close (data);
Packit Service 0ef63b
  free (msg);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
/* We randomize data access to put in a bit additional
Packit Service 0ef63b
   entropy in this test and also to check if maybe
Packit Service 0ef63b
   some data functions might not be properly thread
Packit Service 0ef63b
   safe. */
Packit Service 0ef63b
void
Packit Service 0ef63b
decrypt (const char *fname, gpgme_protocol_t proto)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
  gpgme_data_t output;
Packit Service 0ef63b
  char *msg;
Packit Service 0ef63b
  size_t msg_len;
Packit Service 0ef63b
  data_t data = random_data_new (fname);
Packit Service 0ef63b
Packit Service 0ef63b
  log ("Starting decrypt on: %s", fname);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_data_new (&output);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_set_protocol (ctx, proto);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_op_decrypt (ctx, data->dh, output);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
Packit Service 0ef63b
  msg = gpgme_data_release_and_get_mem (output, &msg_len);
Packit Service 0ef63b
Packit Service 0ef63b
  if (msg_len)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      log ("Decrypt result \n'%.*s'", (int)msg_len, msg);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  random_data_close (data);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
delete_key (gpgme_key_t key)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_set_protocol (ctx, key->protocol);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_op_delete (ctx, key, 0);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
/* Get the key for the fpr in protocol and call delete_key
Packit Service 0ef63b
   on it. */
Packit Service 0ef63b
void
Packit Service 0ef63b
delete_fpr (const char *fpr, gpgme_protocol_t proto)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
  gpgme_key_t key = NULL;
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_set_protocol (ctx, proto);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_get_key (ctx, fpr, &key, 0);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  if (!key)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      errpoint;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  delete_key (key);
Packit Service 0ef63b
Packit Service 0ef63b
  log ("deleted key %s", fpr);
Packit Service 0ef63b
  gpgme_key_unref (key);
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
delete_impres (gpgme_import_result_t r, gpgme_protocol_t proto)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_import_status_t st;
Packit Service 0ef63b
Packit Service 0ef63b
  if (!r)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      errpoint;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  for (st=r->imports; st; st = st->next)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      delete_fpr (st->fpr, proto);
Packit Service 0ef63b
    }
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
import (const char *fname, gpgme_protocol_t proto)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_ctx_t ctx;
Packit Service 0ef63b
  gpgme_error_t err;
Packit Service 0ef63b
  data_t data = random_data_new (fname);
Packit Service 0ef63b
Packit Service 0ef63b
  log ("Starting import on: %s", fname);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_new (&ctx;;
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_set_protocol (ctx, proto);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_set_offline (ctx, 1);
Packit Service 0ef63b
Packit Service 0ef63b
  err = gpgme_op_import (ctx, data->dh);
Packit Service 0ef63b
  fail_if_err (err);
Packit Service 0ef63b
Packit Service 0ef63b
  if (allow_del)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      delete_impres (gpgme_op_import_result (ctx), proto);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_release (ctx);
Packit Service 0ef63b
Packit Service 0ef63b
  log ("Import completed.");
Packit Service 0ef63b
Packit Service 0ef63b
  random_data_close (data);
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
static THREAD_RET
Packit Service 0ef63b
do_data_op (void *file_name)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpgme_data_t data;
Packit Service 0ef63b
  const char *fname = (const char *) file_name;
Packit Service 0ef63b
  FILE *f = fopen (fname, "rb");
Packit Service 0ef63b
  gpgme_data_type_t type;
Packit Service 0ef63b
Packit Service 0ef63b
  if (!f)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      fprintf (stderr, "Failed to open '%s'\n", fname);
Packit Service 0ef63b
      exit (1);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  fail_if_err (gpgme_data_new_from_stream (&data, f));
Packit Service 0ef63b
Packit Service 0ef63b
  type = gpgme_data_identify (data, 0);
Packit Service 0ef63b
  gpgme_data_release (data);
Packit Service 0ef63b
  fclose (f);
Packit Service 0ef63b
Packit Service 0ef63b
  switch (type)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      case GPGME_DATA_TYPE_INVALID:
Packit Service 0ef63b
      case GPGME_DATA_TYPE_UNKNOWN:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          fprintf (stderr, "Failed to identify '%s'", fname);
Packit Service 0ef63b
          exit(1);
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_PGP_SIGNED:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          verify (fname, GPGME_PROTOCOL_OpenPGP);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_CMS_SIGNED:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          verify (fname, GPGME_PROTOCOL_CMS);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_PGP_ENCRYPTED:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          decrypt (fname, GPGME_PROTOCOL_OpenPGP);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_CMS_ENCRYPTED:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          decrypt (fname, GPGME_PROTOCOL_CMS);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_PGP_KEY:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          import (fname, GPGME_PROTOCOL_OpenPGP);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      case GPGME_DATA_TYPE_X509_CERT:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          import (fname, GPGME_PROTOCOL_CMS);
Packit Service 0ef63b
          break;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      default:
Packit Service 0ef63b
        {
Packit Service 0ef63b
          out ("Unhandled data type 0x%x for '%s'\n", type, fname);
Packit Service 0ef63b
          errpoint;
Packit Service 0ef63b
        }
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  del_thread ();
Packit Service 0ef63b
  return 0;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
void
Packit Service 0ef63b
start_keylistings (void)
Packit Service 0ef63b
{
Packit Service 0ef63b
  static struct keylist_args_s args[4];
Packit Service 0ef63b
Packit Service 0ef63b
  args[0].proto = GPGME_PROTOCOL_OpenPGP;
Packit Service 0ef63b
  args[0].secret = 0;
Packit Service 0ef63b
Packit Service 0ef63b
  args[1].proto = GPGME_PROTOCOL_OpenPGP;
Packit Service 0ef63b
  args[1].secret = 1;
Packit Service 0ef63b
Packit Service 0ef63b
  args[2].proto = GPGME_PROTOCOL_CMS;
Packit Service 0ef63b
  args[2].secret = 0;
Packit Service 0ef63b
Packit Service 0ef63b
  args[3].proto = GPGME_PROTOCOL_CMS;
Packit Service 0ef63b
  args[3].secret = 1;
Packit Service 0ef63b
Packit Service 0ef63b
  for (int i = 0; i < 4; i++)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      thread_cnt--;
Packit Service 0ef63b
      create_thread (do_keylist, &args[i]);
Packit Service 0ef63b
    }
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
int
Packit Service 0ef63b
main (int argc, char **argv)
Packit Service 0ef63b
{
Packit Service 0ef63b
  int last_argc = -1;
Packit Service 0ef63b
  int repeats = 1;
Packit Service 0ef63b
  int threads = 0;
Packit Service 0ef63b
  int no_list = 0;
Packit Service 0ef63b
  msg_list_t msgs = NULL;
Packit Service 0ef63b
  msg_list_t msg_it = NULL;
Packit Service 0ef63b
  stop = 0;
Packit Service 0ef63b
Packit Service 0ef63b
  srand (1 /* Somewhat deterministic results */);
Packit Service 0ef63b
Packit Service 0ef63b
  if (argc)
Packit Service 0ef63b
    { argc--; argv++; }
Packit Service 0ef63b
Packit Service 0ef63b
  while (argc && last_argc != argc )
Packit Service 0ef63b
    {
Packit Service 0ef63b
      last_argc = argc;
Packit Service 0ef63b
      if (!strcmp (*argv, "--help"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          show_usage (0);
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--verbose"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          verbose = 1;
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--no-list"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          no_list = 1;
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--allow-del"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          allow_del = 1;
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--mem-only"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          if (data_type)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          mem_only = 1;
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--threads"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
          if (!argc)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          threads = atoi (*argv);
Packit Service 0ef63b
          if (!threads)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--data-type"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
          if (!argc || mem_only)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          data_type = atoi (*argv);
Packit Service 0ef63b
          if (data_type > 4)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!strcmp (*argv, "--repeat"))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
          if (!argc)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          repeats = atoi (*argv);
Packit Service 0ef63b
          if (!repeats)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              show_usage (1);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          argc--; argv++;
Packit Service 0ef63b
        }
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  init_gpgme_basic ();
Packit Service 0ef63b
Packit Service 0ef63b
  if (threads < argc)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      /* Make sure we run once on each arg */
Packit Service 0ef63b
      threads += argc;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  while (argc)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (!msgs)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          msgs = calloc (1, sizeof *msgs);
Packit Service 0ef63b
          msg_it = msgs;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else
Packit Service 0ef63b
        {
Packit Service 0ef63b
          msg_it->next = calloc (1, sizeof *msgs);
Packit Service 0ef63b
          msg_it = msg_it->next;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      msg_it->file_name = *argv;
Packit Service 0ef63b
      argc--; argv++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpgrt_lock_lock (&threads_lock);
Packit Service 0ef63b
  do
Packit Service 0ef63b
    {
Packit Service 0ef63b
      stop = 0;
Packit Service 0ef63b
      thread_cnt = threads + 4;
Packit Service 0ef63b
      out ("Repeats left: %i", repeats);
Packit Service 0ef63b
Packit Service 0ef63b
      if (!no_list)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          start_keylistings ();
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else
Packit Service 0ef63b
        {
Packit Service 0ef63b
          thread_cnt -= 4;
Packit Service 0ef63b
        }
Packit Service 0ef63b
Packit Service 0ef63b
      while (thread_cnt)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          log ("Thread %i", thread_cnt);
Packit Service 0ef63b
          for (msg_it = msgs; msg_it && thread_cnt; msg_it = msg_it->next)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              thread_cnt--;
Packit Service 0ef63b
              create_thread (do_data_op, (void *)msg_it->file_name);
Packit Service 0ef63b
            }
Packit Service 0ef63b
        }
Packit Service 0ef63b
Packit Service 0ef63b
      stop = 1;
Packit Service 0ef63b
      gpgrt_lock_lock (&threads_lock);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  while (--repeats != 0);
Packit Service 0ef63b
Packit Service 0ef63b
  return 0;
Packit Service 0ef63b
}