Blame src/engine-gpg.c

Packit Service 672cf4
/* engine-gpg.c - Gpg Engine.
Packit Service 0ef63b
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 0ef63b
 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
Packit Service 0ef63b
 *               2009, 2010, 2012, 2013 g10 Code 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 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <stdio.h>
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#ifdef HAVE_UNISTD_H
Packit Service 672cf4
# include <unistd.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef HAVE_LOCALE_H
Packit Service 672cf4
#include <locale.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "wait.h"
Packit Service 672cf4
#include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
Packit Service 672cf4
#include "priv-io.h"
Packit Service 672cf4
#include "sema.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
#include "data.h"
Packit Service 0ef63b
#include "mbox-util.h"
Packit Service 672cf4
Packit Service 672cf4
#include "engine-backend.h"
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This type is used to build a list of gpg arguments and data
Packit Service 672cf4
   sources/sinks.  */
Packit Service 672cf4
struct arg_and_data_s
Packit Service 672cf4
{
Packit Service 672cf4
  struct arg_and_data_s *next;
Packit Service 672cf4
  gpgme_data_t data;  /* If this is not NULL, use arg below.  */
Packit Service 672cf4
  int inbound;     /* True if this is used for reading from gpg.  */
Packit Service 672cf4
  int dup_to;
Packit Service 672cf4
  int print_fd;    /* Print the fd number and not the special form of it.  */
Packit Service 672cf4
  int *arg_locp;   /* Write back the argv idx of this argument when
Packit Service 672cf4
		      building command line to this location.  */
Packit Service 672cf4
  char arg[1];     /* Used if data above is not used.  */
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct fd_data_map_s
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_data_t data;
Packit Service 672cf4
  int inbound;  /* true if this is used for reading from gpg */
Packit Service 672cf4
  int dup_to;
Packit Service 672cf4
  int fd;       /* the fd to use */
Packit Service 672cf4
  int peer_fd;  /* the other side of the pipe */
Packit Service 672cf4
  int arg_loc;  /* The index into the argv for translation purposes.  */
Packit Service 672cf4
  void *tag;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* NB.: R_LINE is allocated an gpgrt function and thus gpgrt_free
Packit Service 672cf4
 * shall be used to release it.  This takes care of custom memory
Packit Service 672cf4
 * allocators and avoids problems on Windows with different runtimes
Packit Service 672cf4
 * used for libgpg-error/gpgrt and gpgme.  */
Packit Service 672cf4
typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
Packit Service 672cf4
Packit Service 672cf4
struct engine_gpg
Packit Service 672cf4
{
Packit Service 672cf4
  char *file_name;
Packit Service 672cf4
  char *version;
Packit Service 672cf4
Packit Service 672cf4
  char *lc_messages;
Packit Service 672cf4
  char *lc_ctype;
Packit Service 672cf4
Packit Service 672cf4
  struct arg_and_data_s *arglist;
Packit Service 672cf4
  struct arg_and_data_s **argtail;
Packit Service 672cf4
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    int fd[2];
Packit Service 672cf4
    int arg_loc;
Packit Service 672cf4
    size_t bufsize;
Packit Service 672cf4
    char *buffer;
Packit Service 672cf4
    size_t readpos;
Packit Service 672cf4
    int eof;
Packit Service 672cf4
    engine_status_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    gpgme_status_cb_t mon_cb;
Packit Service 672cf4
    void *mon_cb_value;
Packit Service 672cf4
    void *tag;
Packit Service 672cf4
  } status;
Packit Service 672cf4
Packit Service 672cf4
  /* This is a kludge - see the comment at colon_line_handler.  */
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    int fd[2];
Packit Service 672cf4
    int arg_loc;
Packit Service 672cf4
    size_t bufsize;
Packit Service 672cf4
    char *buffer;
Packit Service 672cf4
    size_t readpos;
Packit Service 672cf4
    int eof;
Packit Service 672cf4
    engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    void *tag;
Packit Service 672cf4
    colon_preprocessor_t preprocess_fnc;
Packit Service 672cf4
  } colon;
Packit Service 672cf4
Packit Service 672cf4
  char **argv;
Packit Service 672cf4
  struct fd_data_map_s *fd_data_map;
Packit Service 672cf4
Packit Service 672cf4
  /* stuff needed for interactive (command) mode */
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    int used;
Packit Service 672cf4
    int fd;
Packit Service 672cf4
    void *cb_data;
Packit Service 672cf4
    int idx;		/* Index in fd_data_map */
Packit Service 672cf4
    gpgme_status_code_t code;  /* last code */
Packit Service 672cf4
    char *keyword;       /* what has been requested (malloced) */
Packit Service 672cf4
    engine_command_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
  } cmd;
Packit Service 672cf4
Packit Service 672cf4
  struct gpgme_io_cbs io_cbs;
Packit Service 672cf4
  gpgme_pinentry_mode_t pinentry_mode;
Packit Service 0ef63b
  char request_origin[10];
Packit Service 0ef63b
  char *auto_key_locate;
Packit Service 0ef63b
  char *trust_model;
Packit Service 0ef63b
Packit Service 0ef63b
  struct {
Packit Service 0ef63b
    unsigned int no_symkey_cache : 1;
Packit Service 0ef63b
    unsigned int offline : 1;
Packit Service 0ef63b
    unsigned int ignore_mdc_error : 1;
Packit Service 0ef63b
  } flags;
Packit Service 672cf4
Packit Service 672cf4
  /* NULL or the data object fed to --override_session_key-fd.  */
Packit Service 672cf4
  gpgme_data_t override_session_key;
Packit Service 0ef63b
Packit Service 0ef63b
  /* Memory data containing diagnostics (--logger-fd) of gpg */
Packit Service 0ef63b
  gpgme_data_t diagnostics;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
typedef struct engine_gpg *engine_gpg_t;
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static void
Packit Service 672cf4
gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 0ef63b
  TRACE (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg,
Packit Service 672cf4
          "event %p, type %d, type_data %p",
Packit Service 672cf4
          gpg->io_cbs.event, type, type_data);
Packit Service 672cf4
  if (gpg->io_cbs.event)
Packit Service 672cf4
    (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
close_notify_handler (int fd, void *opaque)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = opaque;
Packit Service 672cf4
  assert (fd != -1);
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->status.fd[0] == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->status.tag)
Packit Service 672cf4
	(*gpg->io_cbs.remove) (gpg->status.tag);
Packit Service 672cf4
      gpg->status.fd[0] = -1;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpg->status.fd[1] == fd)
Packit Service 672cf4
    gpg->status.fd[1] = -1;
Packit Service 672cf4
  else if (gpg->colon.fd[0] == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->colon.tag)
Packit Service 672cf4
	(*gpg->io_cbs.remove) (gpg->colon.tag);
Packit Service 672cf4
      gpg->colon.fd[0] = -1;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpg->colon.fd[1] == fd)
Packit Service 672cf4
    gpg->colon.fd[1] = -1;
Packit Service 672cf4
  else if (gpg->cmd.fd == fd)
Packit Service 672cf4
    gpg->cmd.fd = -1;
Packit Service 672cf4
  else if (gpg->fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      int i;
Packit Service 672cf4
Packit Service 672cf4
      for (i = 0; gpg->fd_data_map[i].data; i++)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (gpg->fd_data_map[i].fd == fd)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (gpg->fd_data_map[i].tag)
Packit Service 672cf4
		(*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
Packit Service 672cf4
	      gpg->fd_data_map[i].fd = -1;
Packit Service 672cf4
	      break;
Packit Service 672cf4
            }
Packit Service 672cf4
	  if (gpg->fd_data_map[i].peer_fd == fd)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      gpg->fd_data_map[i].peer_fd = -1;
Packit Service 672cf4
	      break;
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
/* If FRONT is true, push at the front of the list.  Use this for
Packit Service 672cf4
   options added late in the process.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
_add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen,
Packit Service 672cf4
          int front, int *arg_locp)
Packit Service 672cf4
{
Packit Service 672cf4
  struct arg_and_data_s *a;
Packit Service 672cf4
  size_t prefixlen = prefix? strlen (prefix) : 0;
Packit Service 672cf4
Packit Service 672cf4
  assert (gpg);
Packit Service 672cf4
  assert (arg);
Packit Service 672cf4
Packit Service 672cf4
  a = malloc (sizeof *a + prefixlen + arglen);
Packit Service 672cf4
  if (!a)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  a->data = NULL;
Packit Service 672cf4
  a->dup_to = -1;
Packit Service 672cf4
  a->arg_locp = arg_locp;
Packit Service 672cf4
Packit Service 672cf4
  if (prefixlen)
Packit Service 672cf4
    memcpy (a->arg, prefix, prefixlen);
Packit Service 672cf4
  memcpy (a->arg + prefixlen, arg, arglen);
Packit Service 672cf4
  a->arg[prefixlen + arglen] = 0;
Packit Service 672cf4
  if (front)
Packit Service 672cf4
    {
Packit Service 672cf4
      a->next = gpg->arglist;
Packit Service 672cf4
      if (!gpg->arglist)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* If this is the first argument, we need to update the tail
Packit Service 672cf4
	     pointer.  */
Packit Service 672cf4
	  gpg->argtail = &a->next;
Packit Service 672cf4
	}
Packit Service 672cf4
      gpg->arglist = a;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      a->next = NULL;
Packit Service 672cf4
      *gpg->argtail = a;
Packit Service 672cf4
      gpg->argtail = &a->next;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
Packit Service 672cf4
{
Packit Service 672cf4
  return _add_arg (gpg, NULL, arg, strlen (arg), front, NULL);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
Packit Service 672cf4
{
Packit Service 672cf4
  return _add_arg (gpg, NULL, arg, strlen (arg), 0, locp);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_arg (engine_gpg_t gpg, const char *arg)
Packit Service 672cf4
{
Packit Service 672cf4
  return _add_arg (gpg, NULL, arg, strlen (arg), 0, NULL);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_arg_pfx (engine_gpg_t gpg, const char *prefix, const char *arg)
Packit Service 672cf4
{
Packit Service 672cf4
  return _add_arg (gpg, prefix, arg, strlen (arg), 0, NULL);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_arg_len (engine_gpg_t gpg, const char *prefix,
Packit Service 672cf4
             const char *arg, size_t arglen)
Packit Service 672cf4
{
Packit Service 672cf4
  return _add_arg (gpg, prefix, arg, arglen, 0, NULL);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
Packit Service 672cf4
{
Packit Service 672cf4
  struct arg_and_data_s *a;
Packit Service 672cf4
Packit Service 672cf4
  assert (gpg);
Packit Service 672cf4
  assert (data);
Packit Service 672cf4
Packit Service 672cf4
  a = malloc (sizeof *a - 1);
Packit Service 672cf4
  if (!a)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  a->next = NULL;
Packit Service 672cf4
  a->data = data;
Packit Service 672cf4
  a->inbound = inbound;
Packit Service 672cf4
  a->arg_locp = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (dup_to == -2)
Packit Service 672cf4
    {
Packit Service 672cf4
      a->print_fd = 1;
Packit Service 672cf4
      a->dup_to = -1;
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      a->print_fd = 0;
Packit Service 672cf4
      a->dup_to = dup_to;
Packit Service 672cf4
    }
Packit Service 672cf4
  *gpg->argtail = a;
Packit Service 672cf4
  gpg->argtail = &a->next;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Return true if the engine's version is at least VERSION.  */
Packit Service 672cf4
static int
Packit Service 672cf4
have_gpg_version (engine_gpg_t gpg, const char *version)
Packit Service 672cf4
{
Packit Service 672cf4
  return _gpgme_compare_versions (gpg->version, version);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static char *
Packit Service 672cf4
gpg_get_version (const char *file_name)
Packit Service 672cf4
{
Packit Service 672cf4
  return _gpgme_get_program_version (file_name ? file_name
Packit Service 672cf4
				     : _gpgme_get_default_gpg_name ());
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
gpg_get_req_version (void)
Packit Service 672cf4
{
Packit Service 672cf4
  return "1.4.0";
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
free_argv (char **argv)
Packit Service 672cf4
{
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; argv[i]; i++)
Packit Service 672cf4
    free (argv[i]);
Packit Service 672cf4
  free (argv);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
free_fd_data_map (struct fd_data_map_s *fd_data_map)
Packit Service 672cf4
{
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  if (!fd_data_map)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (fd_data_map[i].fd != -1)
Packit Service 672cf4
	_gpgme_io_close (fd_data_map[i].fd);
Packit Service 672cf4
      if (fd_data_map[i].peer_fd != -1)
Packit Service 672cf4
	_gpgme_io_close (fd_data_map[i].peer_fd);
Packit Service 672cf4
      /* Don't release data because this is only a reference.  */
Packit Service 672cf4
    }
Packit Service 672cf4
  free (fd_data_map);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_cancel (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  /* If gpg may be waiting for a cmd, close the cmd fd first.  On
Packit Service 672cf4
     Windows, close operations block on the reader/writer thread.  */
Packit Service 672cf4
  if (gpg->cmd.used)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->cmd.fd != -1)
Packit Service 672cf4
	_gpgme_io_close (gpg->cmd.fd);
Packit Service 672cf4
      else if (gpg->fd_data_map
Packit Service 672cf4
	       && gpg->fd_data_map[gpg->cmd.idx].fd != -1)
Packit Service 672cf4
	_gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->status.fd[0] != -1)
Packit Service 672cf4
    _gpgme_io_close (gpg->status.fd[0]);
Packit Service 672cf4
  if (gpg->status.fd[1] != -1)
Packit Service 672cf4
    _gpgme_io_close (gpg->status.fd[1]);
Packit Service 672cf4
  if (gpg->colon.fd[0] != -1)
Packit Service 672cf4
    _gpgme_io_close (gpg->colon.fd[0]);
Packit Service 672cf4
  if (gpg->colon.fd[1] != -1)
Packit Service 672cf4
    _gpgme_io_close (gpg->colon.fd[1]);
Packit Service 672cf4
  if (gpg->fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      free_fd_data_map (gpg->fd_data_map);
Packit Service 672cf4
      gpg->fd_data_map = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpg_release (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  gpg_cancel (engine);
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->file_name)
Packit Service 672cf4
    free (gpg->file_name);
Packit Service 672cf4
  if (gpg->version)
Packit Service 672cf4
    free (gpg->version);
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->lc_messages)
Packit Service 672cf4
    free (gpg->lc_messages);
Packit Service 672cf4
  if (gpg->lc_ctype)
Packit Service 672cf4
    free (gpg->lc_ctype);
Packit Service 672cf4
Packit Service 672cf4
  while (gpg->arglist)
Packit Service 672cf4
    {
Packit Service 672cf4
      struct arg_and_data_s *next = gpg->arglist->next;
Packit Service 672cf4
Packit Service 672cf4
      free (gpg->arglist);
Packit Service 672cf4
      gpg->arglist = next;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->status.buffer)
Packit Service 672cf4
    free (gpg->status.buffer);
Packit Service 672cf4
  if (gpg->colon.buffer)
Packit Service 672cf4
    free (gpg->colon.buffer);
Packit Service 672cf4
  if (gpg->argv)
Packit Service 672cf4
    free_argv (gpg->argv);
Packit Service 672cf4
  if (gpg->cmd.keyword)
Packit Service 672cf4
    free (gpg->cmd.keyword);
Packit Service 0ef63b
  free (gpg->auto_key_locate);
Packit Service 0ef63b
  free (gpg->trust_model);
Packit Service 672cf4
Packit Service 672cf4
  gpgme_data_release (gpg->override_session_key);
Packit Service 0ef63b
  gpgme_data_release (gpg->diagnostics);
Packit Service 672cf4
Packit Service 672cf4
  free (gpg);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_new (void **engine, const char *file_name, const char *home_dir,
Packit Service 672cf4
         const char *version)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg;
Packit Service 672cf4
  gpgme_error_t rc = 0;
Packit Service 672cf4
  char *dft_display = NULL;
Packit Service 672cf4
  char dft_ttyname[64];
Packit Service 672cf4
  char *dft_ttytype = NULL;
Packit Service 672cf4
  char *env_tty = NULL;
Packit Service 672cf4
Packit Service 672cf4
  gpg = calloc (1, sizeof *gpg);
Packit Service 672cf4
  if (!gpg)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (file_name)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg->file_name = strdup (file_name);
Packit Service 672cf4
      if (!gpg->file_name)
Packit Service 672cf4
	{
Packit Service 672cf4
	  rc = gpg_error_from_syserror ();
Packit Service 672cf4
	  goto leave;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (version)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg->version = strdup (version);
Packit Service 672cf4
      if (!gpg->version)
Packit Service 672cf4
	{
Packit Service 672cf4
	  rc = gpg_error_from_syserror ();
Packit Service 672cf4
	  goto leave;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpg->argtail = &gpg->arglist;
Packit Service 672cf4
  gpg->status.fd[0] = -1;
Packit Service 672cf4
  gpg->status.fd[1] = -1;
Packit Service 672cf4
  gpg->colon.fd[0] = -1;
Packit Service 672cf4
  gpg->colon.fd[1] = -1;
Packit Service 672cf4
  gpg->cmd.fd = -1;
Packit Service 672cf4
  gpg->cmd.idx = -1;
Packit Service 672cf4
Packit Service 672cf4
  /* Allocate the read buffer for the status pipe.  */
Packit Service 672cf4
  gpg->status.bufsize = 1024;
Packit Service 672cf4
  gpg->status.readpos = 0;
Packit Service 672cf4
  gpg->status.buffer = malloc (gpg->status.bufsize);
Packit Service 672cf4
  if (!gpg->status.buffer)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  /* In any case we need a status pipe - create it right here and
Packit Service 672cf4
     don't handle it with our generic gpgme_data_t mechanism.  */
Packit Service 672cf4
  if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (_gpgme_io_set_close_notify (gpg->status.fd[0],
Packit Service 672cf4
				  close_notify_handler, gpg)
Packit Service 672cf4
      || _gpgme_io_set_close_notify (gpg->status.fd[1],
Packit Service 672cf4
				     close_notify_handler, gpg))
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  gpg->status.eof = 0;
Packit Service 672cf4
Packit Service 672cf4
  if (home_dir)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = add_arg (gpg, "--homedir");
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	rc = add_arg (gpg, home_dir);
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
	goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  rc = add_arg (gpg, "--status-fd");
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  {
Packit Service 672cf4
    char buf[25];
Packit Service 672cf4
    _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
Packit Service 672cf4
    rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
Packit Service 672cf4
    if (rc)
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
  }
Packit Service 672cf4
Packit Service 672cf4
  rc = add_arg (gpg, "--no-tty");
Packit Service 672cf4
  if (!rc)
Packit Service 672cf4
    rc = add_arg (gpg, "--charset");
Packit Service 672cf4
  if (!rc)
Packit Service 672cf4
    rc = add_arg (gpg, "utf8");
Packit Service 672cf4
  if (!rc)
Packit Service 672cf4
    rc = add_arg (gpg, "--enable-progress-filter");
Packit Service 672cf4
  if (!rc && have_gpg_version (gpg, "2.1.11"))
Packit Service 672cf4
    rc = add_arg (gpg, "--exit-on-status-write-error");
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  rc = _gpgme_getenv ("DISPLAY", &dft_display);
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
  if (dft_display)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = add_arg (gpg, "--display");
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	rc = add_arg (gpg, dft_display);
Packit Service 672cf4
Packit Service 672cf4
      free (dft_display);
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
	goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  rc = _gpgme_getenv ("GPG_TTY", &env_tty);
Packit Service 672cf4
  if (isatty (1) || env_tty || rc)
Packit Service 672cf4
    {
Packit Service 672cf4
      int err = 0;
Packit Service 672cf4
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
        goto leave;
Packit Service 672cf4
      else if (env_tty)
Packit Service 672cf4
        {
Packit Service 672cf4
          snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
Packit Service 672cf4
          free (env_tty);
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
Packit Service 672cf4
Packit Service 672cf4
      /* Even though isatty() returns 1, ttyname_r() may fail in many
Packit Service 672cf4
	 ways, e.g., when /dev/pts is not accessible under chroot.  */
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	{
Packit Service 672cf4
          if (*dft_ttyname)
Packit Service 672cf4
            {
Packit Service 672cf4
              rc = add_arg (gpg, "--ttyname");
Packit Service 672cf4
              if (!rc)
Packit Service 672cf4
                rc = add_arg (gpg, dft_ttyname);
Packit Service 672cf4
            }
Packit Service 672cf4
          else
Packit Service 672cf4
            rc = 0;
Packit Service 672cf4
          if (!rc)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      rc = _gpgme_getenv ("TERM", &dft_ttytype);
Packit Service 672cf4
	      if (rc)
Packit Service 672cf4
		goto leave;
Packit Service 672cf4
Packit Service 672cf4
              if (dft_ttytype)
Packit Service 672cf4
                {
Packit Service 672cf4
                  rc = add_arg (gpg, "--ttytype");
Packit Service 672cf4
                  if (!rc)
Packit Service 672cf4
                    rc = add_arg (gpg, dft_ttytype);
Packit Service 672cf4
                }
Packit Service 672cf4
Packit Service 672cf4
	      free (dft_ttytype);
Packit Service 672cf4
	    }
Packit Service 672cf4
	  if (rc)
Packit Service 672cf4
	    goto leave;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 0ef63b
  rc = gpgme_data_new (&gpg->diagnostics);
Packit Service 0ef63b
  if (rc)
Packit Service 0ef63b
    goto leave;
Packit Service 0ef63b
Packit Service 0ef63b
  rc = add_arg (gpg, "--logger-fd");
Packit Service 0ef63b
  if (rc)
Packit Service 0ef63b
    goto leave;
Packit Service 0ef63b
Packit Service 0ef63b
  rc = add_data (gpg, gpg->diagnostics, -2, 1);
Packit Service 0ef63b
Packit Service 672cf4
 leave:
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    gpg_release (gpg);
Packit Service 672cf4
  else
Packit Service 672cf4
    *engine = gpg;
Packit Service 672cf4
  return rc;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Copy flags from CTX into the engine object.  */
Packit Service 0ef63b
static void
Packit Service 0ef63b
gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
Packit Service 0ef63b
{
Packit Service 0ef63b
  engine_gpg_t gpg = engine;
Packit Service 0ef63b
Packit Service 0ef63b
  if (ctx->request_origin && have_gpg_version (gpg, "2.2.6"))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (strlen (ctx->request_origin) + 1 > sizeof gpg->request_origin)
Packit Service 0ef63b
        strcpy (gpg->request_origin, "xxx"); /* Too long  - force error */
Packit Service 0ef63b
      else
Packit Service 0ef63b
        strcpy (gpg->request_origin, ctx->request_origin);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else
Packit Service 0ef63b
    *gpg->request_origin = 0;
Packit Service 0ef63b
Packit Service 0ef63b
  if (ctx->auto_key_locate && have_gpg_version (gpg, "2.1.18"))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (gpg->auto_key_locate)
Packit Service 0ef63b
        free (gpg->auto_key_locate);
Packit Service 0ef63b
      gpg->auto_key_locate = _gpgme_strconcat ("--auto-key-locate=",
Packit Service 0ef63b
                                               ctx->auto_key_locate, NULL);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (ctx->trust_model && strlen (ctx->trust_model))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (gpg->trust_model)
Packit Service 0ef63b
        free (gpg->trust_model);
Packit Service 0ef63b
      gpg->trust_model = _gpgme_strconcat ("--trust-model=",
Packit Service 0ef63b
                                           ctx->trust_model, NULL);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpg->flags.no_symkey_cache = (ctx->no_symkey_cache
Packit Service 0ef63b
                                && have_gpg_version (gpg, "2.2.7"));
Packit Service 0ef63b
  gpg->flags.offline = (ctx->offline && have_gpg_version (gpg, "2.1.23"));
Packit Service 0ef63b
Packit Service 0ef63b
  gpg->flags.ignore_mdc_error = !!ctx->ignore_mdc_error;
Packit Service 0ef63b
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_set_locale (void *engine, int category, const char *value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (0)
Packit Service 672cf4
    ;
Packit Service 672cf4
#ifdef LC_CTYPE
Packit Service 672cf4
  else if (category == LC_CTYPE)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->lc_ctype)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (gpg->lc_ctype);
Packit Service 672cf4
          gpg->lc_ctype = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpg->lc_ctype = strdup (value);
Packit Service 672cf4
	  if (!gpg->lc_ctype)
Packit Service 672cf4
	    return gpg_error_from_syserror ();
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef LC_MESSAGES
Packit Service 672cf4
  else if (category == LC_MESSAGES)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->lc_messages)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (gpg->lc_messages);
Packit Service 672cf4
          gpg->lc_messages = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpg->lc_messages = strdup (value);
Packit Service 672cf4
	  if (!gpg->lc_messages)
Packit Service 672cf4
	    return gpg_error_from_syserror ();
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
#endif /* LC_MESSAGES */
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
/* This sets a status callback for monitoring status lines before they
Packit Service 672cf4
 * are passed to a caller set handler.  */
Packit Service 672cf4
static void
Packit Service 672cf4
gpg_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpg->status.mon_cb = cb;
Packit Service 672cf4
  gpg->status.mon_cb_value = cb_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Note, that the status_handler is allowed to modify the args
Packit Service 672cf4
   value.  */
Packit Service 672cf4
static void
Packit Service 672cf4
gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
Packit Service 672cf4
			void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpg->status.fnc = fnc;
Packit Service 672cf4
  gpg->status.fnc_value = fnc_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
/* Kludge to process --with-colon output.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
Packit Service 672cf4
			    void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpg->colon.bufsize = 1024;
Packit Service 672cf4
  gpg->colon.readpos = 0;
Packit Service 672cf4
  gpg->colon.buffer = malloc (gpg->colon.bufsize);
Packit Service 672cf4
  if (!gpg->colon.buffer)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
Packit Service 672cf4
    {
Packit Service 672cf4
      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
      free (gpg->colon.buffer);
Packit Service 672cf4
      gpg->colon.buffer = NULL;
Packit Service 672cf4
      return saved_err;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
Packit Service 672cf4
      || _gpgme_io_set_close_notify (gpg->colon.fd[1],
Packit Service 672cf4
				     close_notify_handler, gpg))
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
  gpg->colon.eof = 0;
Packit Service 672cf4
  gpg->colon.fnc = fnc;
Packit Service 672cf4
  gpg->colon.fnc_value = fnc_value;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
command_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  int processed = 0;
Packit Service 672cf4
  assert (gpg->cmd.used);
Packit Service 672cf4
  assert (gpg->cmd.code);
Packit Service 672cf4
  assert (gpg->cmd.fnc);
Packit Service 672cf4
Packit Service 672cf4
  err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd,
Packit Service 672cf4
		      &processed);
Packit Service 672cf4
Packit Service 672cf4
  gpg->cmd.code = 0;
Packit Service 672cf4
  /* And sleep again until read_status will wake us up again.  */
Packit Service 672cf4
  /* XXX We must check if there are any more fds active after removing
Packit Service 672cf4
     this one.  */
Packit Service 672cf4
  (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
Packit Service 672cf4
  gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
Packit Service 672cf4
  gpg->fd_data_map[gpg->cmd.idx].fd = -1;
Packit Service 672cf4
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  /* We always need to send at least a newline character.  */
Packit Service 672cf4
  if (!processed)
Packit Service 672cf4
    _gpgme_io_write (fd, "\n", 1);
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* The FNC will be called to get a value for one of the commands with
Packit Service 0ef63b
 * a key KEY.  If the code passed to FNC is 0, the function may
Packit Service 0ef63b
 * release resources associated with the returned value from another
Packit Service 0ef63b
 * call.  To match such a second call to a first call, the returned
Packit Service 0ef63b
 * value from the first call is passed as keyword.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
Packit Service 0ef63b
			 void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t rc;
Packit Service 672cf4
Packit Service 672cf4
  rc = add_arg (gpg, "--command-fd");
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    return rc;
Packit Service 672cf4
Packit Service 672cf4
  /* This is a hack.  We don't have a real data object.  The only
Packit Service 672cf4
     thing that matters is that we use something unique, so we use the
Packit Service 672cf4
     address of the cmd structure in the gpg object.  */
Packit Service 672cf4
  rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    return rc;
Packit Service 672cf4
Packit Service 672cf4
  gpg->cmd.fnc = fnc;
Packit Service 672cf4
  gpg->cmd.cb_data = (void *) &gpg->cmd;
Packit Service 672cf4
  gpg->cmd.fnc_value = fnc_value;
Packit Service 672cf4
  gpg->cmd.used = 1;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
build_argv (engine_gpg_t gpg, const char *pgmname)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  struct arg_and_data_s *a;
Packit Service 672cf4
  struct fd_data_map_s *fd_data_map;
Packit Service 672cf4
  size_t datac=0, argc=0;
Packit Service 672cf4
  char **argv;
Packit Service 672cf4
  int need_special = 0;
Packit Service 672cf4
  int use_agent = 0;
Packit Service 672cf4
  char *p;
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_in_gpg_one_mode ())
Packit Service 672cf4
    {
Packit Service 672cf4
      /* In GnuPG-1 mode we don't want to use the agent with a
Packit Service 672cf4
         malformed environment variable.  This is only a very basic
Packit Service 672cf4
         test but sufficient to make our life in the regression tests
Packit Service 672cf4
         easier.  With GnuPG-2 the agent is anyway required and on
Packit Service 672cf4
         modern installations GPG_AGENT_INFO is optional.  */
Packit Service 672cf4
      err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
      use_agent = (p && strchr (p, ':'));
Packit Service 672cf4
      if (p)
Packit Service 672cf4
        free (p);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->argv)
Packit Service 672cf4
    {
Packit Service 672cf4
      free_argv (gpg->argv);
Packit Service 672cf4
      gpg->argv = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (gpg->fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      free_fd_data_map (gpg->fd_data_map);
Packit Service 672cf4
      gpg->fd_data_map = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  argc++;	/* For argv[0].  */
Packit Service 672cf4
  for (a = gpg->arglist; a; a = a->next)
Packit Service 672cf4
    {
Packit Service 672cf4
      argc++;
Packit Service 672cf4
      if (a->data)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /*fprintf (stderr, "build_argv: data\n" );*/
Packit Service 672cf4
	  datac++;
Packit Service 672cf4
	  if (a->dup_to == -1 && !a->print_fd)
Packit Service 672cf4
	    need_special = 1;
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  if (need_special)
Packit Service 672cf4
    argc++;
Packit Service 672cf4
  if (use_agent)
Packit Service 672cf4
    argc++;
Packit Service 672cf4
  if (gpg->pinentry_mode)
Packit Service 672cf4
    argc++;
Packit Service 672cf4
  if (!gpg->cmd.used)
Packit Service 672cf4
    argc++;	/* --batch */
Packit Service 0ef63b
  argc += 4;	/* --no-sk-comments, --request-origin, --no-symkey-cache */
Packit Service 0ef63b
                /* --disable-dirmngr  */
Packit Service 672cf4
Packit Service 672cf4
  argv = calloc (argc + 1, sizeof *argv);
Packit Service 672cf4
  if (!argv)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
Packit Service 672cf4
  if (!fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
      free_argv (argv);
Packit Service 672cf4
      return saved_err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  argc = datac = 0;
Packit Service 672cf4
  argv[argc] = strdup (_gpgme_get_basename (pgmname)); /* argv[0] */
Packit Service 672cf4
  if (!argv[argc])
Packit Service 672cf4
    {
Packit Service 672cf4
      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
      free (fd_data_map);
Packit Service 672cf4
      free_argv (argv);
Packit Service 672cf4
      return saved_err;
Packit Service 672cf4
    }
Packit Service 672cf4
  argc++;
Packit Service 672cf4
  if (need_special)
Packit Service 672cf4
    {
Packit Service 672cf4
      argv[argc] = strdup ("--enable-special-filenames");
Packit Service 672cf4
      if (!argv[argc])
Packit Service 672cf4
	{
Packit Service 672cf4
          int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	  free (fd_data_map);
Packit Service 672cf4
	  free_argv (argv);
Packit Service 672cf4
	  return saved_err;
Packit Service 672cf4
        }
Packit Service 672cf4
      argc++;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (use_agent)
Packit Service 672cf4
    {
Packit Service 672cf4
      argv[argc] = strdup ("--use-agent");
Packit Service 672cf4
      if (!argv[argc])
Packit Service 672cf4
	{
Packit Service 672cf4
          int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	  free (fd_data_map);
Packit Service 672cf4
	  free_argv (argv);
Packit Service 672cf4
	  return saved_err;
Packit Service 672cf4
        }
Packit Service 672cf4
      argc++;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 0ef63b
  if (*gpg->request_origin)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = _gpgme_strconcat ("--request-origin=",
Packit Service 0ef63b
                                     gpg->request_origin, NULL);
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
	{
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
	  free (fd_data_map);
Packit Service 0ef63b
	  free_argv (argv);
Packit Service 0ef63b
	  return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpg->auto_key_locate)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = strdup (gpg->auto_key_locate);
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
        {
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
          free (fd_data_map);
Packit Service 0ef63b
          free_argv (argv);
Packit Service 0ef63b
          return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpg->trust_model)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = strdup (gpg->trust_model);
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
        {
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
          free (fd_data_map);
Packit Service 0ef63b
          free_argv (argv);
Packit Service 0ef63b
          return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpg->flags.no_symkey_cache)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = strdup ("--no-symkey-cache");
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
	{
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
	  free (fd_data_map);
Packit Service 0ef63b
	  free_argv (argv);
Packit Service 0ef63b
	  return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpg->flags.ignore_mdc_error)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = strdup ("--ignore-mdc-error");
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
	{
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
	  free (fd_data_map);
Packit Service 0ef63b
	  free_argv (argv);
Packit Service 0ef63b
	  return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (gpg->flags.offline)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      argv[argc] = strdup ("--disable-dirmngr");
Packit Service 0ef63b
      if (!argv[argc])
Packit Service 0ef63b
	{
Packit Service 0ef63b
          int saved_err = gpg_error_from_syserror ();
Packit Service 0ef63b
	  free (fd_data_map);
Packit Service 0ef63b
	  free_argv (argv);
Packit Service 0ef63b
	  return saved_err;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      argc++;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 672cf4
  if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
Packit Service 672cf4
    {
Packit Service 672cf4
      const char *s = NULL;
Packit Service 672cf4
      switch (gpg->pinentry_mode)
Packit Service 672cf4
        {
Packit Service 672cf4
        case GPGME_PINENTRY_MODE_DEFAULT: break;
Packit Service 672cf4
        case GPGME_PINENTRY_MODE_ASK:     s = "--pinentry-mode=ask"; break;
Packit Service 672cf4
        case GPGME_PINENTRY_MODE_CANCEL:  s = "--pinentry-mode=cancel"; break;
Packit Service 672cf4
        case GPGME_PINENTRY_MODE_ERROR:   s = "--pinentry-mode=error"; break;
Packit Service 672cf4
        case GPGME_PINENTRY_MODE_LOOPBACK:s = "--pinentry-mode=loopback"; break;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (s)
Packit Service 672cf4
        {
Packit Service 672cf4
          argv[argc] = strdup (s);
Packit Service 672cf4
          if (!argv[argc])
Packit Service 672cf4
            {
Packit Service 672cf4
              int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
              free (fd_data_map);
Packit Service 672cf4
              free_argv (argv);
Packit Service 672cf4
              return saved_err;
Packit Service 672cf4
            }
Packit Service 672cf4
          argc++;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg->cmd.used)
Packit Service 672cf4
    {
Packit Service 672cf4
      argv[argc] = strdup ("--batch");
Packit Service 672cf4
      if (!argv[argc])
Packit Service 672cf4
	{
Packit Service 672cf4
          int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	  free (fd_data_map);
Packit Service 672cf4
	  free_argv (argv);
Packit Service 672cf4
	  return saved_err;
Packit Service 672cf4
        }
Packit Service 672cf4
      argc++;
Packit Service 672cf4
    }
Packit Service 672cf4
  argv[argc] = strdup ("--no-sk-comments");
Packit Service 672cf4
  if (!argv[argc])
Packit Service 672cf4
    {
Packit Service 672cf4
      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
      free (fd_data_map);
Packit Service 672cf4
      free_argv (argv);
Packit Service 672cf4
      return saved_err;
Packit Service 672cf4
    }
Packit Service 672cf4
  argc++;
Packit Service 672cf4
  for (a = gpg->arglist; a; a = a->next)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (a->arg_locp)
Packit Service 672cf4
	*(a->arg_locp) = argc;
Packit Service 672cf4
Packit Service 672cf4
      if (a->data)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* Create a pipe to pass it down to gpg.  */
Packit Service 672cf4
	  fd_data_map[datac].inbound = a->inbound;
Packit Service 672cf4
Packit Service 672cf4
	  /* Create a pipe.  */
Packit Service 672cf4
	  {
Packit Service 672cf4
	    int fds[2];
Packit Service 672cf4
Packit Service 672cf4
	    if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
Packit Service 672cf4
		== -1)
Packit Service 672cf4
	      {
Packit Service 0ef63b
		int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
		free (fd_data_map);
Packit Service 672cf4
		free_argv (argv);
Packit Service 0ef63b
		return saved_err;
Packit Service 672cf4
	      }
Packit Service 672cf4
	    if (_gpgme_io_set_close_notify (fds[0],
Packit Service 672cf4
					    close_notify_handler, gpg)
Packit Service 672cf4
		|| _gpgme_io_set_close_notify (fds[1],
Packit Service 672cf4
					       close_notify_handler,
Packit Service 672cf4
					       gpg))
Packit Service 672cf4
	      {
Packit Service 672cf4
                /* We leak fd_data_map and the fds.  This is not easy
Packit Service 672cf4
                   to avoid and given that we reach this here only
Packit Service 672cf4
                   after a malloc failure for a small object, it is
Packit Service 672cf4
                   probably better not to do anything.  */
Packit Service 672cf4
		return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
	      }
Packit Service 672cf4
	    /* If the data_type is FD, we have to do a dup2 here.  */
Packit Service 672cf4
	    if (fd_data_map[datac].inbound)
Packit Service 672cf4
	      {
Packit Service 672cf4
		fd_data_map[datac].fd       = fds[0];
Packit Service 672cf4
		fd_data_map[datac].peer_fd  = fds[1];
Packit Service 672cf4
	      }
Packit Service 672cf4
	    else
Packit Service 672cf4
	      {
Packit Service 672cf4
		fd_data_map[datac].fd       = fds[1];
Packit Service 672cf4
		fd_data_map[datac].peer_fd  = fds[0];
Packit Service 672cf4
	      }
Packit Service 672cf4
	  }
Packit Service 672cf4
Packit Service 672cf4
	  /* Hack to get hands on the fd later.  */
Packit Service 672cf4
	  if (gpg->cmd.used)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (gpg->cmd.cb_data == a->data)
Packit Service 672cf4
		{
Packit Service 672cf4
		  assert (gpg->cmd.idx == -1);
Packit Service 672cf4
		  gpg->cmd.idx = datac;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 672cf4
Packit Service 672cf4
	  fd_data_map[datac].data = a->data;
Packit Service 672cf4
	  fd_data_map[datac].dup_to = a->dup_to;
Packit Service 672cf4
Packit Service 672cf4
	  if (a->dup_to == -1)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      char *ptr;
Packit Service 672cf4
	      int buflen = 25;
Packit Service 672cf4
Packit Service 672cf4
	      argv[argc] = malloc (buflen);
Packit Service 672cf4
	      if (!argv[argc])
Packit Service 672cf4
		{
Packit Service 672cf4
                  int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
		  free (fd_data_map);
Packit Service 672cf4
		  free_argv (argv);
Packit Service 672cf4
		  return saved_err;
Packit Service 672cf4
                }
Packit Service 672cf4
Packit Service 672cf4
	      ptr = argv[argc];
Packit Service 672cf4
	      if (!a->print_fd)
Packit Service 672cf4
		{
Packit Service 672cf4
		  *(ptr++) = '-';
Packit Service 672cf4
		  *(ptr++) = '&';
Packit Service 672cf4
		  buflen -= 2;
Packit Service 672cf4
		}
Packit Service 672cf4
Packit Service 672cf4
	      _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
Packit Service 672cf4
	      fd_data_map[datac].arg_loc = argc;
Packit Service 672cf4
	      argc++;
Packit Service 672cf4
            }
Packit Service 672cf4
	  datac++;
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  argv[argc] = strdup (a->arg);
Packit Service 672cf4
	  if (!argv[argc])
Packit Service 672cf4
	    {
Packit Service 672cf4
              int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	      free (fd_data_map);
Packit Service 672cf4
	      free_argv (argv);
Packit Service 672cf4
	      return saved_err;
Packit Service 672cf4
            }
Packit Service 672cf4
            argc++;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpg->argv = argv;
Packit Service 672cf4
  gpg->fd_data_map = fd_data_map;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
Packit Service 672cf4
	   void **tag)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  if (!dir)
Packit Service 672cf4
    /* FIXME Kludge around poll() problem.  */
Packit Service 672cf4
    err = _gpgme_io_set_nonblocking (fd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Handle the status output of GnuPG.  This function does read entire
Packit Service 672cf4
   lines and passes them as C strings to the callback function (we can
Packit Service 672cf4
   use C Strings because the status output is always UTF-8 encoded).
Packit Service 672cf4
   Of course we have to buffer the lines to cope with long lines
Packit Service 672cf4
   e.g. with a large user ID.  Note: We can optimize this to only cope
Packit Service 672cf4
   with status line code we know about and skip all other stuff
Packit Service 672cf4
   without buffering (i.e. without extending the buffer).  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
read_status (engine_gpg_t gpg)
Packit Service 672cf4
{
Packit Service 672cf4
  char *p;
Packit Service 672cf4
  int nread;
Packit Service 672cf4
  size_t bufsize = gpg->status.bufsize;
Packit Service 672cf4
  char *buffer = gpg->status.buffer;
Packit Service 672cf4
  size_t readpos = gpg->status.readpos;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  assert (buffer);
Packit Service 672cf4
  if (bufsize - readpos < 256)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Need more room for the read.  */
Packit Service 672cf4
      bufsize += 1024;
Packit Service 672cf4
      buffer = realloc (buffer, bufsize);
Packit Service 672cf4
      if (!buffer)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  nread = _gpgme_io_read (gpg->status.fd[0],
Packit Service 672cf4
			  buffer + readpos, bufsize-readpos);
Packit Service 672cf4
  if (nread == -1)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (!nread)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = 0;
Packit Service 672cf4
      gpg->status.eof = 1;
Packit Service 672cf4
      if (gpg->status.mon_cb)
Packit Service 672cf4
        err = gpg->status.mon_cb (gpg->status.mon_cb_value, "", "");
Packit Service 672cf4
      if (gpg->status.fnc)
Packit Service 672cf4
        {
Packit Service 672cf4
          char emptystring[1] = {0};
Packit Service 672cf4
          err = gpg->status.fnc (gpg->status.fnc_value,
Packit Service 672cf4
                                 GPGME_STATUS_EOF, emptystring);
Packit Service 672cf4
          if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
            err = 0; /* Drop special error code.  */
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  while (nread > 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      for (p = buffer + readpos; nread; nread--, p++)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (*p == '\n')
Packit Service 672cf4
	    {
Packit Service 672cf4
	      /* (we require that the last line is terminated by a LF) */
Packit Service 672cf4
	      if (p > buffer && p[-1] == '\r')
Packit Service 672cf4
		p[-1] = 0;
Packit Service 672cf4
	      *p = 0;
Packit Service 672cf4
	      if (!strncmp (buffer, "[GNUPG:] ", 9)
Packit Service 672cf4
		  && buffer[9] >= 'A' && buffer[9] <= 'Z')
Packit Service 672cf4
		{
Packit Service 672cf4
		  char *rest;
Packit Service 672cf4
		  gpgme_status_code_t r;
Packit Service 672cf4
Packit Service 672cf4
		  rest = strchr (buffer + 9, ' ');
Packit Service 672cf4
		  if (!rest)
Packit Service 672cf4
		    rest = p; /* Set to an empty string.  */
Packit Service 672cf4
		  else
Packit Service 672cf4
		    *rest++ = 0;
Packit Service 672cf4
Packit Service 672cf4
		  r = _gpgme_parse_status (buffer + 9);
Packit Service 672cf4
                  if (gpg->status.mon_cb && r != GPGME_STATUS_PROGRESS)
Packit Service 672cf4
                    {
Packit Service 672cf4
                      /* Note that we call the monitor even if we do
Packit Service 672cf4
                       * not know the status code (r < 0).  */
Packit Service 672cf4
                      err = gpg->status.mon_cb (gpg->status.mon_cb_value,
Packit Service 672cf4
                                                buffer + 9, rest);
Packit Service 672cf4
                      if (err)
Packit Service 672cf4
                        return err;
Packit Service 672cf4
                    }
Packit Service 672cf4
		  if (r >= 0)
Packit Service 672cf4
		    {
Packit Service 672cf4
		      if (gpg->cmd.used
Packit Service 672cf4
			  && (r == GPGME_STATUS_GET_BOOL
Packit Service 672cf4
			      || r == GPGME_STATUS_GET_LINE
Packit Service 672cf4
			      || r == GPGME_STATUS_GET_HIDDEN))
Packit Service 672cf4
			{
Packit Service 672cf4
			  gpg->cmd.code = r;
Packit Service 672cf4
			  if (gpg->cmd.keyword)
Packit Service 672cf4
			    free (gpg->cmd.keyword);
Packit Service 672cf4
			  gpg->cmd.keyword = strdup (rest);
Packit Service 672cf4
			  if (!gpg->cmd.keyword)
Packit Service 672cf4
			    return gpg_error_from_syserror ();
Packit Service 672cf4
			  /* This should be the last thing we have
Packit Service 672cf4
			     received and the next thing will be that
Packit Service 672cf4
			     the command handler does its action.  */
Packit Service 672cf4
			  if (nread > 1)
Packit Service 0ef63b
			    TRACE (DEBUG_CTX, "gpgme:read_status", 0,
Packit Service 672cf4
				    "error: unexpected data");
Packit Service 672cf4
Packit Service 672cf4
			  add_io_cb (gpg, gpg->cmd.fd, 0,
Packit Service 672cf4
				     command_handler, gpg,
Packit Service 672cf4
				     &gpg->fd_data_map[gpg->cmd.idx].tag);
Packit Service 672cf4
			  gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
Packit Service 672cf4
			  gpg->cmd.fd = -1;
Packit Service 672cf4
                        }
Packit Service 672cf4
		      else if (gpg->status.fnc)
Packit Service 672cf4
			{
Packit Service 672cf4
			  err = gpg->status.fnc (gpg->status.fnc_value,
Packit Service 672cf4
						 r, rest);
Packit Service 672cf4
                          if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
                            err = 0; /* Drop special error code.  */
Packit Service 672cf4
			  if (err)
Packit Service 672cf4
			    return err;
Packit Service 672cf4
                        }
Packit Service 672cf4
                    }
Packit Service 672cf4
                }
Packit Service 672cf4
	      /* To reuse the buffer for the next line we have to
Packit Service 672cf4
		 shift the remaining data to the buffer start and
Packit Service 672cf4
		 restart the loop Hmmm: We can optimize this function
Packit Service 672cf4
		 by looking forward in the buffer to see whether a
Packit Service 672cf4
		 second complete line is available and in this case
Packit Service 672cf4
		 avoid the memmove for this line.  */
Packit Service 672cf4
	      nread--; p++;
Packit Service 672cf4
	      if (nread)
Packit Service 672cf4
		memmove (buffer, p, nread);
Packit Service 672cf4
	      readpos = 0;
Packit Service 672cf4
	      break; /* the for loop */
Packit Service 672cf4
            }
Packit Service 672cf4
	  else
Packit Service 672cf4
	    readpos++;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Update the gpg object.  */
Packit Service 61ff77
  gpg->status.bufsize = bufsize;
Packit Service 61ff77
  gpg->status.buffer = buffer;
Packit Service 672cf4
  gpg->status.readpos = readpos;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
status_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
Packit Service 672cf4
  int err;
Packit Service 672cf4
Packit Service 672cf4
  assert (fd == gpg->status.fd[0]);
Packit Service 672cf4
  err = read_status (gpg);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  if (gpg->status.eof)
Packit Service 672cf4
    _gpgme_io_close (fd);
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
read_colon_line (engine_gpg_t gpg)
Packit Service 672cf4
{
Packit Service 672cf4
  char *p;
Packit Service 672cf4
  int nread;
Packit Service 672cf4
  size_t bufsize = gpg->colon.bufsize;
Packit Service 672cf4
  char *buffer = gpg->colon.buffer;
Packit Service 672cf4
  size_t readpos = gpg->colon.readpos;
Packit Service 672cf4
Packit Service 672cf4
  assert (buffer);
Packit Service 672cf4
  if (bufsize - readpos < 256)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Need more room for the read.  */
Packit Service 672cf4
      bufsize += 1024;
Packit Service 672cf4
      buffer = realloc (buffer, bufsize);
Packit Service 672cf4
      if (!buffer)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
Packit Service 672cf4
  if (nread == -1)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (!nread)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpg->colon.eof = 1;
Packit Service 672cf4
      assert (gpg->colon.fnc);
Packit Service 672cf4
      gpg->colon.fnc (gpg->colon.fnc_value, NULL);
Packit Service 672cf4
      return 0;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  while (nread > 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      for (p = buffer + readpos; nread; nread--, p++)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if ( *p == '\n' )
Packit Service 672cf4
	    {
Packit Service 672cf4
	      /* (we require that the last line is terminated by a LF)
Packit Service 672cf4
		 and we skip empty lines.  Note: we use UTF8 encoding
Packit Service 672cf4
		 and escaping of special characters.  We require at
Packit Service 672cf4
		 least one colon to cope with some other printed
Packit Service 672cf4
		 information.  */
Packit Service 672cf4
	      *p = 0;
Packit Service 672cf4
	      if (*buffer && strchr (buffer, ':'))
Packit Service 672cf4
		{
Packit Service 672cf4
		  char *line = NULL;
Packit Service 672cf4
Packit Service 672cf4
		  if (gpg->colon.preprocess_fnc)
Packit Service 672cf4
		    {
Packit Service 672cf4
		      gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
		      err = gpg->colon.preprocess_fnc (buffer, &line);
Packit Service 672cf4
		      if (err)
Packit Service 672cf4
			return err;
Packit Service 672cf4
		    }
Packit Service 672cf4
Packit Service 672cf4
		  assert (gpg->colon.fnc);
Packit Service 672cf4
                  if (line)
Packit Service 672cf4
                    {
Packit Service 672cf4
                      char *linep = line;
Packit Service 672cf4
                      char *endp;
Packit Service 672cf4
Packit Service 672cf4
                      do
Packit Service 672cf4
                        {
Packit Service 672cf4
                          endp = strchr (linep, '\n');
Packit Service 672cf4
                          if (endp)
Packit Service 672cf4
                            *endp++ = 0;
Packit Service 672cf4
                          gpg->colon.fnc (gpg->colon.fnc_value, linep);
Packit Service 672cf4
                          linep = endp;
Packit Service 672cf4
                        }
Packit Service 672cf4
                      while (linep && *linep);
Packit Service 672cf4
Packit Service 672cf4
                      gpgrt_free (line);
Packit Service 672cf4
                    }
Packit Service 672cf4
                  else
Packit Service 672cf4
                    gpg->colon.fnc (gpg->colon.fnc_value, buffer);
Packit Service 672cf4
                }
Packit Service 672cf4
Packit Service 672cf4
	      /* To reuse the buffer for the next line we have to
Packit Service 672cf4
		 shift the remaining data to the buffer start and
Packit Service 672cf4
		 restart the loop Hmmm: We can optimize this function
Packit Service 672cf4
		 by looking forward in the buffer to see whether a
Packit Service 672cf4
		 second complete line is available and in this case
Packit Service 672cf4
		 avoid the memmove for this line.  */
Packit Service 672cf4
	      nread--; p++;
Packit Service 672cf4
	      if (nread)
Packit Service 672cf4
		memmove (buffer, p, nread);
Packit Service 672cf4
	      readpos = 0;
Packit Service 672cf4
	      break; /* The for loop.  */
Packit Service 672cf4
            }
Packit Service 672cf4
	  else
Packit Service 672cf4
	    readpos++;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Update the gpg object.  */
Packit Service 61ff77
  gpg->colon.bufsize = bufsize;
Packit Service 61ff77
  gpg->colon.buffer  = buffer;
Packit Service 672cf4
  gpg->colon.readpos = readpos;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This colonline handler thing is not the clean way to do it.  It
Packit Service 672cf4
   might be better to enhance the gpgme_data_t object to act as a wrapper
Packit Service 672cf4
   for a callback.  Same goes for the status thing.  For now we use
Packit Service 672cf4
   this thing here because it is easier to implement.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
colon_line_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
Packit Service 672cf4
  gpgme_error_t rc = 0;
Packit Service 672cf4
Packit Service 672cf4
  assert (fd == gpg->colon.fd[0]);
Packit Service 672cf4
  rc = read_colon_line (gpg);
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    return rc;
Packit Service 672cf4
  if (gpg->colon.eof)
Packit Service 672cf4
    _gpgme_io_close (fd);
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
start (engine_gpg_t gpg)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t rc;
Packit Service 672cf4
  int i, n;
Packit Service 672cf4
  int status;
Packit Service 672cf4
  struct spawn_fd_item_s *fd_list;
Packit Service 672cf4
  pid_t pid;
Packit Service 672cf4
  const char *pgmname;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg->file_name && !_gpgme_get_default_gpg_name ())
Packit Service 672cf4
    return trace_gpg_error (GPG_ERR_INV_ENGINE);
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->lc_ctype)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	rc = add_arg_ext (gpg, "--lc-ctype", 1);
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
	return rc;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->lc_messages)
Packit Service 672cf4
    {
Packit Service 672cf4
      rc = add_arg_ext (gpg, gpg->lc_messages, 1);
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	rc = add_arg_ext (gpg, "--lc-messages", 1);
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
	return rc;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  pgmname = gpg->file_name ? gpg->file_name : _gpgme_get_default_gpg_name ();
Packit Service 672cf4
  rc = build_argv (gpg, pgmname);
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    return rc;
Packit Service 672cf4
Packit Service 672cf4
  /* status_fd, colon_fd and end of list.  */
Packit Service 672cf4
  n = 3;
Packit Service 672cf4
  for (i = 0; gpg->fd_data_map[i].data; i++)
Packit Service 672cf4
    n++;
Packit Service 672cf4
  fd_list = calloc (n, sizeof *fd_list);
Packit Service 672cf4
  if (! fd_list)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  /* Build the fd list for the child.  */
Packit Service 672cf4
  n = 0;
Packit Service 672cf4
  fd_list[n].fd = gpg->status.fd[1];
Packit Service 672cf4
  fd_list[n].dup_to = -1;
Packit Service 672cf4
  fd_list[n].arg_loc = gpg->status.arg_loc;
Packit Service 672cf4
  n++;
Packit Service 672cf4
  if (gpg->colon.fnc)
Packit Service 672cf4
    {
Packit Service 672cf4
      fd_list[n].fd = gpg->colon.fd[1];
Packit Service 672cf4
      fd_list[n].dup_to = 1;
Packit Service 672cf4
      n++;
Packit Service 672cf4
    }
Packit Service 672cf4
  for (i = 0; gpg->fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
Packit Service 672cf4
      fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
Packit Service 672cf4
      fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
Packit Service 672cf4
      n++;
Packit Service 672cf4
    }
Packit Service 672cf4
  fd_list[n].fd = -1;
Packit Service 672cf4
  fd_list[n].dup_to = -1;
Packit Service 672cf4
Packit Service 672cf4
  status = _gpgme_io_spawn (pgmname, gpg->argv,
Packit Service 672cf4
                            (IOSPAWN_FLAG_DETACHED |IOSPAWN_FLAG_ALLOW_SET_FG),
Packit Service 672cf4
                            fd_list, NULL, NULL, &pid;;
Packit Service 672cf4
  {
Packit Service 672cf4
    int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
    free (fd_list);
Packit Service 672cf4
    if (status == -1)
Packit Service 672cf4
      return saved_err;
Packit Service 672cf4
  }
Packit Service 672cf4
Packit Service 672cf4
  /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
Packit Service 672cf4
Packit Service 672cf4
  rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
Packit Service 672cf4
		  &gpg->status.tag);
Packit Service 672cf4
  if (rc)
Packit Service 672cf4
    /* FIXME: kill the child */
Packit Service 672cf4
    return rc;
Packit Service 672cf4
Packit Service 672cf4
  if (gpg->colon.fnc)
Packit Service 672cf4
    {
Packit Service 672cf4
      assert (gpg->colon.fd[0] != -1);
Packit Service 672cf4
      rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
Packit Service 672cf4
		      &gpg->colon.tag);
Packit Service 672cf4
      if (rc)
Packit Service 672cf4
	/* FIXME: kill the child */
Packit Service 672cf4
	return rc;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; gpg->fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpg->cmd.used && i == gpg->cmd.idx)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* Park the cmd fd.  */
Packit Service 672cf4
	  gpg->cmd.fd = gpg->fd_data_map[i].fd;
Packit Service 672cf4
	  gpg->fd_data_map[i].fd = -1;
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
Packit Service 672cf4
			  gpg->fd_data_map[i].inbound,
Packit Service 672cf4
			  gpg->fd_data_map[i].inbound
Packit Service 672cf4
			  ? _gpgme_data_inbound_handler
Packit Service 672cf4
			  : _gpgme_data_outbound_handler,
Packit Service 672cf4
			  gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
Packit Service 672cf4
Packit Service 672cf4
	  if (rc)
Packit Service 672cf4
	    /* FIXME: kill the child */
Packit Service 672cf4
	    return rc;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpg_io_event (gpg, GPGME_EVENT_START, NULL);
Packit Service 672cf4
Packit Service 672cf4
  /* fixme: check what data we can release here */
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Add the --input-size-hint option if requested.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_off_t value = _gpgme_data_get_size_hint (data);
Packit Service 672cf4
  char numbuf[50];  /* Large enough for even 2^128 in base-10.  */
Packit Service 672cf4
  char *p;
Packit Service 672cf4
Packit Service 672cf4
  if (!value || !have_gpg_version (gpg, "2.1.15"))
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--input-size-hint");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      p = numbuf + sizeof numbuf;
Packit Service 672cf4
      *--p = 0;
Packit Service 672cf4
      do
Packit Service 672cf4
        {
Packit Service 672cf4
          *--p = '0' + (value % 10);
Packit Service 672cf4
          value /= 10;
Packit Service 672cf4
        }
Packit Service 672cf4
      while (value);
Packit Service 672cf4
      err = add_arg (gpg, p);
Packit Service 672cf4
    }
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_decrypt (void *engine,
Packit Service 672cf4
             gpgme_decrypt_flags_t flags,
Packit Service 672cf4
             gpgme_data_t ciph, gpgme_data_t plain,
Packit Service 672cf4
             int export_session_key, const char *override_session_key,
Packit Service 672cf4
             int auto_key_retrieve)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--decrypt");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_DECRYPT_UNWRAP))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!have_gpg_version (gpg, "2.1.12"))
Packit Service 672cf4
        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
      else
Packit Service 672cf4
        err = add_arg (gpg, "--unwrap");
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err && export_session_key)
Packit Service 672cf4
    err = add_arg (gpg, "--show-session-key");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && auto_key_retrieve)
Packit Service 672cf4
    err = add_arg (gpg, "--auto-key-retrieve");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && override_session_key && *override_session_key)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (have_gpg_version (gpg, "2.1.16"))
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgme_data_release (gpg->override_session_key);
Packit Service 0ef63b
          TRACE (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n",
Packit Service 672cf4
                  override_session_key,
Packit Service 672cf4
                  strlen (override_session_key));
Packit Service 672cf4
Packit Service 672cf4
          err = gpgme_data_new_from_mem (&gpg->override_session_key,
Packit Service 672cf4
                                         override_session_key,
Packit Service 672cf4
                                         strlen (override_session_key), 1);
Packit Service 672cf4
          if (!err)
Packit Service 672cf4
            {
Packit Service 0ef63b
              /* We add --no-keyring because a keyring is not required
Packit Service 0ef63b
               * when we are overriding the session key.  It would
Packit Service 0ef63b
               * work without that option but --no-keyring avoids that
Packit Service 0ef63b
               * gpg return a failure due to a missing key log_error()
Packit Service 0ef63b
               * diagnostic.  --no-keyring is supported since 2.1.14. */
Packit Service 0ef63b
              err = add_arg (gpg, "--no-keyring");
Packit Service 0ef63b
              if (!err)
Packit Service 0ef63b
                err = add_arg (gpg, "--override-session-key-fd");
Packit Service 672cf4
              if (!err)
Packit Service 672cf4
                err = add_data (gpg, gpg->override_session_key, -2, 0);
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        {
Packit Service 672cf4
          /* Using that option may leak the session key via ps(1).  */
Packit Service 672cf4
          err = add_arg (gpg, "--override-session-key");
Packit Service 672cf4
          if (!err)
Packit Service 672cf4
            err = add_arg (gpg, override_session_key);
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Tell the gpg object about the data.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--output");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "-");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, plain, 1, 1);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_input_size_hint (gpg, ciph);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, ciph, -1, 0);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_delete (void *engine, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  int allow_secret = flags & GPGME_DELETE_ALLOW_SECRET;
Packit Service 672cf4
  int force = flags & GPGME_DELETE_FORCE;
Packit Service 672cf4
Packit Service 672cf4
  if (force)
Packit Service 672cf4
    err = add_arg (gpg, "--yes");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
Packit Service 672cf4
		   : "--delete-key");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!key->subkeys || !key->subkeys->fpr)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      else
Packit Service 672cf4
	err = add_arg (gpg, key->subkeys->fpr);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)flags;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->subkeys || !key->subkeys->fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_CERT_OBJ);
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--passwd");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, key->subkeys->fpr);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  int i;
Packit Service 672cf4
  gpgme_key_t key;
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char *s = key->subkeys ? key->subkeys->keyid : NULL;
Packit Service 672cf4
      if (s)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, "-u");
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, s);
Packit Service 672cf4
	}
Packit Service 672cf4
      gpgme_key_unref (key);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  if (ctx->sender && have_gpg_version (gpg, "2.1.15"))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--sender");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, ctx->sender);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    err = 0;
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  gpgme_sig_notation_t notation;
Packit Service 672cf4
Packit Service 672cf4
  notation = gpgme_sig_notation_get (ctx);
Packit Service 672cf4
Packit Service 672cf4
  while (!err && notation)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (notation->name
Packit Service 672cf4
	  && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
Packit Service 672cf4
	err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      else if (notation->name)
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *arg;
Packit Service 672cf4
Packit Service 672cf4
	  /* Maximum space needed is one byte for the "critical" flag,
Packit Service 672cf4
	     the name, one byte for '=', the value, and a terminating
Packit Service 672cf4
	     '\0'.  */
Packit Service 672cf4
Packit Service 672cf4
	  arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
Packit Service 672cf4
	  if (!arg)
Packit Service 672cf4
	    err = gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      char *argp = arg;
Packit Service 672cf4
Packit Service 672cf4
	      if (notation->critical)
Packit Service 672cf4
		*(argp++) = '!';
Packit Service 672cf4
Packit Service 672cf4
	      memcpy (argp, notation->name, notation->name_len);
Packit Service 672cf4
	      argp += notation->name_len;
Packit Service 672cf4
Packit Service 672cf4
	      *(argp++) = '=';
Packit Service 672cf4
Packit Service 672cf4
	      /* We know that notation->name is '\0' terminated.  */
Packit Service 672cf4
	      strcpy (argp, notation->value);
Packit Service 672cf4
	    }
Packit Service 672cf4
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, "--sig-notation");
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, arg);
Packit Service 672cf4
Packit Service 672cf4
	  if (arg)
Packit Service 672cf4
	    free (arg);
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* This is a policy URL.  */
Packit Service 672cf4
Packit Service 672cf4
	  char *value;
Packit Service 672cf4
Packit Service 672cf4
	  if (notation->critical)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      value = malloc (1 + notation->value_len + 1);
Packit Service 672cf4
	      if (!value)
Packit Service 672cf4
		err = gpg_error_from_syserror ();
Packit Service 672cf4
	      else
Packit Service 672cf4
		{
Packit Service 672cf4
		  value[0] = '!';
Packit Service 672cf4
		  /* We know that notation->value is '\0' terminated.  */
Packit Service 672cf4
		  strcpy (&value[1], notation->value);
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 672cf4
	  else
Packit Service 672cf4
	    value = notation->value;
Packit Service 672cf4
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, "--sig-policy-url");
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    err = add_arg (gpg, value);
Packit Service 672cf4
Packit Service 672cf4
	  if (value != notation->value)
Packit Service 672cf4
	    free (value);
Packit Service 672cf4
      	}
Packit Service 672cf4
Packit Service 672cf4
      notation = notation->next;
Packit Service 672cf4
    }
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
Packit Service 672cf4
	  gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--with-colons");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_signers (gpg, ctx);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
  err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, out, 1, 1);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err && type == 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char *s = key->subkeys ? key->subkeys->fpr : NULL;
Packit Service 672cf4
      if (!s)
Packit Service 672cf4
	err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      else
Packit Service 672cf4
	err = add_arg (gpg, s);
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Add a single argument from a key to an -r option.  */
Packit Service 0ef63b
static gpg_error_t
Packit Service 0ef63b
add_arg_recipient (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
Packit Service 0ef63b
                   gpgme_key_t key)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpg_error_t err;
Packit Service 0ef63b
Packit Service 0ef63b
  if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      /* We have no way to figure out which mail address was
Packit Service 0ef63b
       * requested.  FIXME: It would be possible to figure this out by
Packit Service 0ef63b
       * consulting the SENDER property of the context.  */
Packit Service 0ef63b
      err = gpg_error (GPG_ERR_INV_USER_ID);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else
Packit Service 0ef63b
    err = add_arg (gpg, key->subkeys->fpr);
Packit Service 0ef63b
Packit Service 0ef63b
  return err;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
/* Add a single argument from a USERID string to an -r option.  */
Packit Service 0ef63b
static gpg_error_t
Packit Service 0ef63b
add_arg_recipient_string (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
Packit Service 0ef63b
                          const char *userid, int useridlen)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpg_error_t err;
Packit Service 0ef63b
Packit Service 0ef63b
  if ((flags & GPGME_ENCRYPT_WANT_ADDRESS))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      char *tmpstr, *mbox;
Packit Service 0ef63b
Packit Service 0ef63b
      tmpstr = malloc (useridlen + 1);
Packit Service 0ef63b
      if (!tmpstr)
Packit Service 0ef63b
        err = gpg_error_from_syserror ();
Packit Service 0ef63b
      else
Packit Service 0ef63b
        {
Packit Service 0ef63b
          memcpy (tmpstr, userid, useridlen);
Packit Service 0ef63b
          tmpstr[useridlen] = 0;
Packit Service 0ef63b
Packit Service 0ef63b
          mbox = _gpgme_mailbox_from_userid (tmpstr);
Packit Service 0ef63b
          if (!mbox)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              err = gpg_error_from_syserror ();
Packit Service 0ef63b
              if (gpg_err_code (err) == GPG_ERR_EINVAL)
Packit Service 0ef63b
                err = gpg_error (GPG_ERR_INV_USER_ID);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          else
Packit Service 0ef63b
            err = add_arg (gpg, mbox);
Packit Service 0ef63b
Packit Service 0ef63b
          free (mbox);
Packit Service 0ef63b
          free (tmpstr);
Packit Service 0ef63b
        }
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else
Packit Service 0ef63b
    err = add_arg_len (gpg, NULL, userid, useridlen);
Packit Service 0ef63b
Packit Service 0ef63b
  return err;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 672cf4
static gpgme_error_t
Packit Service 0ef63b
append_args_from_recipients (engine_gpg_t gpg, gpgme_encrypt_flags_t flags,
Packit Service 0ef63b
                             gpgme_key_t recp[])
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  int i = 0;
Packit Service 672cf4
Packit Service 672cf4
  while (recp[i])
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
Packit Service 672cf4
	err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "-r");
Packit Service 672cf4
      if (!err)
Packit Service 0ef63b
	err = add_arg_recipient (gpg, flags, recp[i]);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	break;
Packit Service 672cf4
      i++;
Packit Service 672cf4
    }
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Take recipients from the LF delimited STRING and add -r args.  */
Packit Service 0ef63b
static gpg_error_t
Packit Service 0ef63b
append_args_from_recipients_string (engine_gpg_t gpg,
Packit Service 0ef63b
                                    gpgme_encrypt_flags_t flags,
Packit Service 0ef63b
                                    const char *string)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpg_error_t err = 0;
Packit Service 0ef63b
  gpgme_encrypt_flags_t orig_flags = flags;
Packit Service 0ef63b
  int any = 0;
Packit Service 0ef63b
  int ignore = 0;
Packit Service 0ef63b
  int hidden = 0;
Packit Service 0ef63b
  int file = 0;
Packit Service 0ef63b
  const char *s;
Packit Service 0ef63b
  int n;
Packit Service 0ef63b
Packit Service 0ef63b
  do
Packit Service 0ef63b
    {
Packit Service 0ef63b
      /* Skip leading white space */
Packit Service 0ef63b
      while (*string == ' ' || *string == '\t')
Packit Service 0ef63b
        string++;
Packit Service 0ef63b
      if (!*string)
Packit Service 0ef63b
        break;
Packit Service 0ef63b
Packit Service 0ef63b
      /* Look for the LF. */
Packit Service 0ef63b
      s = strchr (string, '\n');
Packit Service 0ef63b
      if (s)
Packit Service 0ef63b
        n = s - string;
Packit Service 0ef63b
      else
Packit Service 0ef63b
        n = strlen (string);
Packit Service 0ef63b
      while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
Packit Service 0ef63b
        n--;
Packit Service 0ef63b
Packit Service 0ef63b
      if (!ignore && n == 2 && !memcmp (string, "--", 2))
Packit Service 0ef63b
        ignore = 1;
Packit Service 0ef63b
      else if (!ignore && n == 8 && !memcmp (string, "--hidden", 8))
Packit Service 0ef63b
        hidden = 1;
Packit Service 0ef63b
      else if (!ignore && n == 11 && !memcmp (string, "--no-hidden", 11))
Packit Service 0ef63b
        hidden = 0;
Packit Service 0ef63b
      else if (!ignore && n == 6 && !memcmp (string, "--file", 6))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          file = 1;
Packit Service 0ef63b
          /* Because the key is used as is we need to ignore this flag:  */
Packit Service 0ef63b
          flags &= ~GPGME_ENCRYPT_WANT_ADDRESS;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!ignore && n == 9 && !memcmp (string, "--no-file", 9))
Packit Service 0ef63b
        {
Packit Service 0ef63b
          file = 0;
Packit Service 0ef63b
          flags = orig_flags;
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else if (!ignore && n > 2 && !memcmp (string, "--", 2))
Packit Service 0ef63b
        err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
Packit Service 0ef63b
      else if (n) /* Not empty - use it.  */
Packit Service 0ef63b
        {
Packit Service 0ef63b
          err = add_arg (gpg, file? (hidden? "-F":"-f") : (hidden? "-R":"-r"));
Packit Service 0ef63b
          if (!err)
Packit Service 0ef63b
            err = add_arg_recipient_string (gpg, flags, string, n);
Packit Service 0ef63b
          if (!err)
Packit Service 0ef63b
            any = 1;
Packit Service 0ef63b
        }
Packit Service 0ef63b
Packit Service 0ef63b
      string += n + !!s;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  while (!err);
Packit Service 0ef63b
Packit Service 0ef63b
  if (!err && !any)
Packit Service 0ef63b
    err = gpg_error (GPG_ERR_MISSING_KEY);
Packit Service 0ef63b
  return err;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 672cf4
static gpgme_error_t
Packit Service 0ef63b
gpg_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
Packit Service 0ef63b
             gpgme_encrypt_flags_t flags,
Packit Service 672cf4
	     gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
Packit Service 0ef63b
  if (recp || recpstring)
Packit Service 672cf4
    err = add_arg (gpg, "--encrypt");
Packit Service 672cf4
Packit Service 0ef63b
  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
Packit Service 672cf4
    err = add_arg (gpg, "--symmetric");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && use_armor)
Packit Service 672cf4
    err = add_arg (gpg, "--armor");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_ENCRYPT_WRAP))
Packit Service 672cf4
    {
Packit Service 672cf4
      /* gpg is current not able to detect already compressed
Packit Service 672cf4
       * packets.  Thus when using
Packit Service 672cf4
       *   gpg --unwrap -d | gpg --no-literal -e
Packit Service 672cf4
       * the encryption would add an additional compression layer.
Packit Service 672cf4
       * We better suppress that.  */
Packit Service 672cf4
      flags |= GPGME_ENCRYPT_NO_COMPRESS;
Packit Service 672cf4
      err = add_arg (gpg, "--no-literal");
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
Packit Service 672cf4
    err = add_arg (gpg, "--compress-algo=none");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
Packit Service 672cf4
    err = add_arg (gpg, "--throw-keyids");
Packit Service 672cf4
Packit Service 672cf4
  if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
Packit Service 672cf4
      && have_gpg_version (gpg, "2.1.14"))
Packit Service 672cf4
    err = add_arg (gpg, "--mimemode");
Packit Service 672cf4
Packit Service 0ef63b
  if (recp || recpstring)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* If we know that all recipients are valid (full or ultimate trust)
Packit Service 672cf4
	 we can suppress further checks.  */
Packit Service 672cf4
      if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
Packit Service 672cf4
	err = add_arg (gpg, "--always-trust");
Packit Service 672cf4
Packit Service 672cf4
      if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
Packit Service 672cf4
	err = add_arg (gpg, "--no-encrypt-to");
Packit Service 672cf4
Packit Service 0ef63b
      if (!err && !recp && recpstring)
Packit Service 0ef63b
	err = append_args_from_recipients_string (gpg, flags, recpstring);
Packit Service 0ef63b
      else if (!err)
Packit Service 0ef63b
	err = append_args_from_recipients (gpg, flags, recp);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Tell the gpg object about the data.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--output");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "-");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, ciph, 1, 1);
Packit Service 672cf4
  if (gpgme_data_get_file_name (plain))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "--set-filename");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, gpgme_data_get_file_name (plain));
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_input_size_hint (gpg, plain);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, plain, -1, 0);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
Packit Service 0ef63b
                  const char *recpstring,
Packit Service 672cf4
		  gpgme_encrypt_flags_t flags, gpgme_data_t plain,
Packit Service 672cf4
		  gpgme_data_t ciph, int use_armor,
Packit Service 672cf4
		  gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
Packit Service 0ef63b
  if (recp || recpstring)
Packit Service 672cf4
    err = add_arg (gpg, "--encrypt");
Packit Service 672cf4
Packit Service 0ef63b
  if (!err && ((flags & GPGME_ENCRYPT_SYMMETRIC) || (!recp && !recpstring)))
Packit Service 672cf4
    err = add_arg (gpg, "--symmetric");
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--sign");
Packit Service 672cf4
  if (!err && use_armor)
Packit Service 672cf4
    err = add_arg (gpg, "--armor");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
Packit Service 672cf4
    err = add_arg (gpg, "--compress-algo=none");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
Packit Service 672cf4
    err = add_arg (gpg, "--throw-keyids");
Packit Service 672cf4
Packit Service 672cf4
  if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
Packit Service 672cf4
      && have_gpg_version (gpg, "2.1.14"))
Packit Service 672cf4
    err = add_arg (gpg, "--mimemode");
Packit Service 672cf4
Packit Service 0ef63b
  if (recp || recpstring)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* If we know that all recipients are valid (full or ultimate trust)
Packit Service 672cf4
	 we can suppress further checks.  */
Packit Service 672cf4
      if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
Packit Service 672cf4
	err = add_arg (gpg, "--always-trust");
Packit Service 672cf4
Packit Service 672cf4
      if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
Packit Service 672cf4
	err = add_arg (gpg, "--no-encrypt-to");
Packit Service 672cf4
Packit Service 0ef63b
      if (!err && !recp && recpstring)
Packit Service 0ef63b
	err = append_args_from_recipients_string (gpg, flags, recpstring);
Packit Service 0ef63b
      else if (!err)
Packit Service 0ef63b
	err = append_args_from_recipients (gpg, flags, recp);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_signers (gpg, ctx);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_sender (gpg, ctx);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_sig_notations (gpg, ctx);
Packit Service 672cf4
Packit Service 672cf4
  /* Tell the gpg object about the data.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--output");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "-");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, ciph, 1, 1);
Packit Service 672cf4
  if (gpgme_data_get_file_name (plain))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "--set-filename");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, gpgme_data_get_file_name (plain));
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_input_size_hint (gpg, plain);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, plain, -1, 0);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
Packit Service 672cf4
               gpgme_data_t keydata, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
Packit Service 672cf4
  if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
Packit Service 672cf4
                |GPGME_EXPORT_MODE_MINIMAL
Packit Service 672cf4
                |GPGME_EXPORT_MODE_SECRET)))
Packit Service 672cf4
    return gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
Packit Service 672cf4
  if ((mode & GPGME_EXPORT_MODE_MINIMAL))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if ((mode & GPGME_EXPORT_MODE_NOUID))
Packit Service 0ef63b
        err = add_arg (gpg, "--export-options=export-minimal,export-drop-uids");
Packit Service 0ef63b
      else
Packit Service 0ef63b
        err = add_arg (gpg, "--export-options=export-minimal");
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else if ((mode & GPGME_EXPORT_MODE_NOUID))
Packit Service 0ef63b
    err = add_arg (gpg, "--export-options=export-drop-uids");
Packit Service 672cf4
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    ;
Packit Service 672cf4
  else if ((mode & GPGME_EXPORT_MODE_EXTERN))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--send-keys");
Packit Service 0ef63b
      if (!err && (mode & GPGME_EXPORT_MODE_NOUID))
Packit Service 0ef63b
        err = add_arg (gpg, "--keyserver-options=export-drop-uids");
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      if ((mode & GPGME_EXPORT_MODE_SECRET))
Packit Service 672cf4
        err = add_arg (gpg, "--export-secret-keys");
Packit Service 672cf4
      else
Packit Service 672cf4
        err = add_arg (gpg, "--export");
Packit Service 672cf4
      if (!err && use_armor)
Packit Service 672cf4
        err = add_arg (gpg, "--armor");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_data (gpg, keydata, 1, 1);
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
Packit Service 672cf4
	    gpgme_data_t keydata, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = export_common (gpg, mode, keydata, use_armor);
Packit Service 672cf4
Packit Service 672cf4
  if (!err && pattern && *pattern)
Packit Service 672cf4
    err = add_arg (gpg, pattern);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
Packit Service 672cf4
		gpgme_data_t keydata, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = export_common (gpg, mode, keydata, use_armor);
Packit Service 672cf4
Packit Service 672cf4
  if (pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      while (!err && *pattern && **pattern)
Packit Service 672cf4
	err = add_arg (gpg, *(pattern++));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/* Helper to add algo, usage, and expire to the list of args.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_add_algo_usage_expire (engine_gpg_t gpg,
Packit Service 672cf4
                           const char *algo,
Packit Service 672cf4
                           unsigned long expires,
Packit Service 672cf4
                           unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  /* This condition is only required to allow the use of gpg < 2.1.16 */
Packit Service 672cf4
  if (algo
Packit Service 672cf4
      || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
Packit Service 672cf4
                   | GPGME_CREATE_CERT | GPGME_CREATE_AUTH
Packit Service 672cf4
                   | GPGME_CREATE_NOEXPIRE))
Packit Service 672cf4
      || expires)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, algo? algo : "default");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        {
Packit Service 672cf4
          char tmpbuf[5*4+1];
Packit Service 672cf4
          snprintf (tmpbuf, sizeof tmpbuf, "%s%s%s%s",
Packit Service 672cf4
                    (flags & GPGME_CREATE_SIGN)? " sign":"",
Packit Service 672cf4
                    (flags & GPGME_CREATE_ENCR)? " encr":"",
Packit Service 672cf4
                    (flags & GPGME_CREATE_CERT)? " cert":"",
Packit Service 672cf4
                    (flags & GPGME_CREATE_AUTH)? " auth":"");
Packit Service 672cf4
          err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
Packit Service 672cf4
        }
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        {
Packit Service 672cf4
          if ((flags & GPGME_CREATE_NOEXPIRE))
Packit Service 672cf4
            err = add_arg (gpg, "never");
Packit Service 672cf4
          else if (expires == 0)
Packit Service 672cf4
            err = add_arg (gpg, "-");
Packit Service 672cf4
          else
Packit Service 672cf4
            {
Packit Service 672cf4
              char tmpbuf[8+20];
Packit Service 672cf4
              snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
Packit Service 672cf4
              err = add_arg (gpg, tmpbuf);
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    err = 0;
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_createkey_from_param (engine_gpg_t gpg,
Packit Service 672cf4
                          gpgme_data_t help_data, unsigned int extraflags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--gen-key");
Packit Service 672cf4
  if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
Packit Service 672cf4
    err = add_arg (gpg, "--armor");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, help_data, -1, 0);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_createkey (engine_gpg_t gpg,
Packit Service 672cf4
               const char *userid, const char *algo,
Packit Service 672cf4
               unsigned long expires,
Packit Service 672cf4
               unsigned int flags,
Packit Service 672cf4
               unsigned int extraflags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--quick-gen-key");
Packit Service 672cf4
  if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
Packit Service 672cf4
    err = add_arg (gpg, "--armor");
Packit Service 672cf4
  if (!err && (flags & GPGME_CREATE_NOPASSWD))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--passphrase");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--batch");
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err && (flags & GPGME_CREATE_FORCE))
Packit Service 672cf4
    err = add_arg (gpg, "--yes");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, userid);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_addkey (engine_gpg_t gpg,
Packit Service 672cf4
            const char *algo,
Packit Service 672cf4
            unsigned long expires,
Packit Service 672cf4
            gpgme_key_t key,
Packit Service 672cf4
            unsigned int flags,
Packit Service 672cf4
            unsigned int extraflags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_ARG);
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--quick-addkey");
Packit Service 672cf4
  if (!err && (extraflags & GENKEY_EXTRAFLAG_ARMOR))
Packit Service 672cf4
    err = add_arg (gpg, "--armor");
Packit Service 672cf4
  if (!err && (flags & GPGME_CREATE_NOPASSWD))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--passphrase");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--batch");
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, key->fpr);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = gpg_add_algo_usage_expire (gpg, algo, expires, flags);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_adduid (engine_gpg_t gpg,
Packit Service 672cf4
            gpgme_key_t key,
Packit Service 672cf4
            const char *userid,
Packit Service 672cf4
            unsigned int extraflags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->fpr || !userid)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_ARG);
Packit Service 672cf4
Packit Service 672cf4
  if ((extraflags & GENKEY_EXTRAFLAG_SETPRIMARY))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!have_gpg_version (gpg, "2.1.20"))
Packit Service 672cf4
        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
      else
Packit Service 672cf4
        err = add_arg (gpg, "--quick-set-primary-uid");
Packit Service 672cf4
    }
Packit Service 672cf4
  else if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
Packit Service 672cf4
    err = add_arg (gpg, "--quick-revuid");
Packit Service 672cf4
  else
Packit Service 672cf4
    err = add_arg (gpg, "--quick-adduid");
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, key->fpr);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, userid);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_genkey (void *engine,
Packit Service 672cf4
            const char *userid, const char *algo,
Packit Service 672cf4
            unsigned long reserved, unsigned long expires,
Packit Service 672cf4
            gpgme_key_t key, unsigned int flags,
Packit Service 672cf4
            gpgme_data_t help_data, unsigned int extraflags,
Packit Service 672cf4
	    gpgme_data_t pubkey, gpgme_data_t seckey)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)reserved;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpg)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  /* If HELP_DATA is given the use of the old interface
Packit Service 672cf4
   * (gpgme_op_genkey) has been requested.  The other modes are:
Packit Service 672cf4
   *
Packit Service 672cf4
   *  USERID && !KEY          - Create a new keyblock.
Packit Service 672cf4
   * !USERID &&  KEY          - Add a new subkey to KEY (gpg >= 2.1.14)
Packit Service 672cf4
   *  USERID &&  KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
Packit Service 672cf4
   *                            or set a flag on a user id.
Packit Service 672cf4
   */
Packit Service 672cf4
  if (help_data)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* We need a special mechanism to get the fd of a pipe here, so
Packit Service 672cf4
         that we can use this for the %pubring and %secring
Packit Service 672cf4
         parameters.  We don't have this yet, so we implement only the
Packit Service 672cf4
         adding to the standard keyrings.  */
Packit Service 672cf4
      if (pubkey || seckey)
Packit Service 672cf4
        err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 672cf4
      else
Packit Service 672cf4
        err = gpg_createkey_from_param (gpg, help_data, extraflags);
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (!have_gpg_version (gpg, "2.1.13"))
Packit Service 672cf4
    err = gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
  else if (userid && !key)
Packit Service 672cf4
    err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
Packit Service 672cf4
  else if (!userid && key)
Packit Service 672cf4
    err = gpg_addkey (gpg, algo, expires, key, flags, extraflags);
Packit Service 672cf4
  else if (userid && key && !algo)
Packit Service 672cf4
    err = gpg_adduid (gpg, key, userid, extraflags);
Packit Service 672cf4
  else
Packit Service 672cf4
    err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
/* Return the next DELIM delimited string from DATA as a C-string.
Packit Service 672cf4
   The caller needs to provide the address of a pointer variable which
Packit Service 672cf4
   he has to set to NULL before the first call.  After the last call
Packit Service 672cf4
   to this function, this function needs to be called once more with
Packit Service 672cf4
   DATA set to NULL so that the function can release its internal
Packit Service 672cf4
   state.  After that the pointer variable is free for use again.
Packit Service 672cf4
   Note that we use a delimiter and thus a trailing delimiter is not
Packit Service 672cf4
   required.  DELIM may not be changed after the first call. */
Packit Service 672cf4
static const char *
Packit Service 672cf4
string_from_data (gpgme_data_t data, int delim,
Packit Service 672cf4
                  void **helpptr, gpgme_error_t *r_err)
Packit Service 672cf4
{
Packit Service 672cf4
#define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that.  */
Packit Service 672cf4
  struct {
Packit Service 672cf4
    int  eof_seen;
Packit Service 672cf4
    int  nbytes;      /* Length of the last returned string including
Packit Service 672cf4
                         the delimiter. */
Packit Service 672cf4
    int  buflen;      /* Valid length of BUF.  */
Packit Service 672cf4
    char buf[MYBUFLEN+1];  /* Buffer with one byte extra space.  */
Packit Service 672cf4
  } *self;
Packit Service 672cf4
  char *p;
Packit Service 672cf4
  int nread;
Packit Service 672cf4
Packit Service 672cf4
  *r_err = 0;
Packit Service 672cf4
  if (!data)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (*helpptr)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (*helpptr);
Packit Service 672cf4
          *helpptr = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      return NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (*helpptr)
Packit Service 672cf4
    self = *helpptr;
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      self = malloc (sizeof *self);
Packit Service 672cf4
      if (!self)
Packit Service 672cf4
        {
Packit Service 672cf4
          *r_err = gpg_error_from_syserror ();
Packit Service 672cf4
          return NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      *helpptr = self;
Packit Service 672cf4
      self->eof_seen = 0;
Packit Service 672cf4
      self->nbytes = 0;
Packit Service 672cf4
      self->buflen = 0;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (self->eof_seen)
Packit Service 672cf4
    return NULL;
Packit Service 672cf4
Packit Service 672cf4
  assert (self->nbytes <= self->buflen);
Packit Service 672cf4
  memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
Packit Service 672cf4
  self->buflen -= self->nbytes;
Packit Service 672cf4
  self->nbytes = 0;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Fixme: This is fairly infective scanning because we may scan
Packit Service 672cf4
         the buffer several times.  */
Packit Service 672cf4
      p = memchr (self->buf, delim, self->buflen);
Packit Service 672cf4
      if (p)
Packit Service 672cf4
        {
Packit Service 672cf4
          *p = 0;
Packit Service 672cf4
          self->nbytes = p - self->buf + 1;
Packit Service 672cf4
          return self->buf;
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      if ( !(MYBUFLEN - self->buflen) )
Packit Service 672cf4
        {
Packit Service 672cf4
          /* Not enough space - URL too long.  */
Packit Service 672cf4
          *r_err = gpg_error (GPG_ERR_TOO_LARGE);
Packit Service 672cf4
          return NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      nread = gpgme_data_read (data, self->buf + self->buflen,
Packit Service 672cf4
                               MYBUFLEN - self->buflen);
Packit Service 672cf4
      if (nread < 0)
Packit Service 672cf4
        {
Packit Service 672cf4
          *r_err = gpg_error_from_syserror ();
Packit Service 672cf4
          return NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      self->buflen += nread;
Packit Service 672cf4
    }
Packit Service 672cf4
  while (nread);
Packit Service 672cf4
Packit Service 672cf4
  /* EOF reached.  If we have anything in the buffer, append a Nul and
Packit Service 672cf4
     return it. */
Packit Service 672cf4
  self->eof_seen = 1;
Packit Service 672cf4
  if (self->buflen)
Packit Service 672cf4
    {
Packit Service 672cf4
      self->buf[self->buflen] = 0;  /* (we allocated one extra byte)  */
Packit Service 672cf4
      return self->buf;
Packit Service 672cf4
    }
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
#undef MYBUFLEN
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  int idx;
Packit Service 672cf4
  gpgme_data_encoding_t dataenc;
Packit Service 672cf4
Packit Service 672cf4
  if (keydata && keyarray)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
Packit Service 672cf4
Packit Service 672cf4
  dataenc = gpgme_data_get_encoding (keydata);
Packit Service 672cf4
Packit Service 672cf4
  if (keyarray)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--recv-keys");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--");
Packit Service 672cf4
      for (idx=0; !err && keyarray[idx]; idx++)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
Packit Service 672cf4
            ;
Packit Service 672cf4
          else if (!keyarray[idx]->subkeys)
Packit Service 672cf4
            ;
Packit Service 672cf4
          else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
Packit Service 672cf4
            err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
Packit Service 672cf4
          else if (*keyarray[idx]->subkeys->keyid)
Packit Service 672cf4
            err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (dataenc == GPGME_DATA_ENCODING_URL
Packit Service 672cf4
           || dataenc == GPGME_DATA_ENCODING_URL0)
Packit Service 672cf4
    {
Packit Service 672cf4
      void *helpptr;
Packit Service 672cf4
      const char *string;
Packit Service 672cf4
      gpgme_error_t xerr;
Packit Service 672cf4
      int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
Packit Service 672cf4
Packit Service 672cf4
      /* FIXME: --fetch-keys is probably not correct because it can't
Packit Service 672cf4
         grok all kinds of URLs.  On Unix it should just work but on
Packit Service 672cf4
         Windows we will build the command line and that may fail for
Packit Service 672cf4
         some embedded control characters.  It is anyway limited to
Packit Service 672cf4
         the maximum size of the command line.  We need another
Packit Service 672cf4
         command which can take its input from a file.  Maybe we
Packit Service 672cf4
         should use an option to gpg to modify such commands (ala
Packit Service 672cf4
         --multifile).  */
Packit Service 672cf4
      err = add_arg (gpg, "--fetch-keys");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--");
Packit Service 672cf4
      helpptr = NULL;
Packit Service 672cf4
      while (!err
Packit Service 672cf4
             && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
Packit Service 672cf4
        err = add_arg (gpg, string);
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = xerr;
Packit Service 672cf4
      string_from_data (NULL, delim, &helpptr, &xerr);
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (dataenc == GPGME_DATA_ENCODING_URLESC)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Already escaped URLs are not yet supported.  */
Packit Service 672cf4
      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--import");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_data (gpg, keydata, -1, 0);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* The output for external keylistings in GnuPG is different from all
Packit Service 672cf4
   the other key listings.  We catch this here with a special
Packit Service 672cf4
   preprocessor that reformats the colon handler lines.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_keylist_preprocess (char *line, char **r_line)
Packit Service 672cf4
{
Packit Service 672cf4
  enum
Packit Service 672cf4
    {
Packit Service 672cf4
      RT_NONE, RT_INFO, RT_PUB, RT_UID
Packit Service 672cf4
    }
Packit Service 672cf4
  rectype = RT_NONE;
Packit Service 672cf4
#define NR_FIELDS 16
Packit Service 672cf4
  char *field[NR_FIELDS];
Packit Service 672cf4
  int fields = 0;
Packit Service 672cf4
  size_t n;
Packit Service 672cf4
Packit Service 672cf4
  *r_line = NULL;
Packit Service 672cf4
Packit Service 672cf4
  while (line && fields < NR_FIELDS)
Packit Service 672cf4
    {
Packit Service 672cf4
      field[fields++] = line;
Packit Service 672cf4
      line = strchr (line, ':');
Packit Service 672cf4
      if (line)
Packit Service 672cf4
	*(line++) = '\0';
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!strcmp (field[0], "info"))
Packit Service 672cf4
    rectype = RT_INFO;
Packit Service 672cf4
  else if (!strcmp (field[0], "pub"))
Packit Service 672cf4
    rectype = RT_PUB;
Packit Service 672cf4
  else if (!strcmp (field[0], "uid"))
Packit Service 672cf4
    rectype = RT_UID;
Packit Service 672cf4
  else
Packit Service 672cf4
    rectype = RT_NONE;
Packit Service 672cf4
Packit Service 672cf4
  switch (rectype)
Packit Service 672cf4
    {
Packit Service 672cf4
    case RT_INFO:
Packit Service 672cf4
      /* FIXME: Eventually, check the version number at least.  */
Packit Service 672cf4
      return 0;
Packit Service 672cf4
Packit Service 672cf4
    case RT_PUB:
Packit Service 672cf4
      if (fields < 7)
Packit Service 672cf4
	return 0;
Packit Service 672cf4
Packit Service 672cf4
      /* The format is:
Packit Service 672cf4
Packit Service 672cf4
	 pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
Packit Service 672cf4
Packit Service 672cf4
	 as defined in 5.2. Machine Readable Indexes of the OpenPGP
Packit Service 672cf4
	 HTTP Keyserver Protocol (draft).  Modern versions of the SKS
Packit Service 672cf4
	 keyserver return the fingerprint instead of the keyid.  We
Packit Service 672cf4
	 detect this here and use the v4 fingerprint format to convert
Packit Service 672cf4
	 it to a key id.
Packit Service 672cf4
Packit Service 672cf4
	 We want:
Packit Service 672cf4
	 pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
Packit Service 672cf4
      */
Packit Service 672cf4
Packit Service 672cf4
      n = strlen (field[1]);
Packit Service 672cf4
      if (n > 16)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (gpgrt_asprintf (r_line,
Packit Service 672cf4
                        "pub:o%s:%s:%s:%s:%s:%s::::::::\n"
Packit Service 672cf4
                        "fpr:::::::::%s:",
Packit Service 672cf4
                        field[6], field[3], field[2], field[1] + n - 16,
Packit Service 672cf4
                        field[4], field[5], field[1]) < 0)
Packit Service 672cf4
            return gpg_error_from_syserror ();
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        {
Packit Service 672cf4
          if (gpgrt_asprintf (r_line,
Packit Service 672cf4
                        "pub:o%s:%s:%s:%s:%s:%s::::::::",
Packit Service 672cf4
                        field[6], field[3], field[2], field[1],
Packit Service 672cf4
                        field[4], field[5]) < 0)
Packit Service 672cf4
            return gpg_error_from_syserror ();
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      return 0;
Packit Service 672cf4
Packit Service 672cf4
    case RT_UID:
Packit Service 672cf4
      /* The format is:
Packit Service 672cf4
Packit Service 672cf4
         uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
Packit Service 672cf4
Packit Service 672cf4
	 as defined in 5.2. Machine Readable Indexes of the OpenPGP
Packit Service 672cf4
	 HTTP Keyserver Protocol (draft).
Packit Service 672cf4
Packit Service 672cf4
         For an ldap keyserver the format is:
Packit Service 672cf4
         uid:<escaped uid string>
Packit Service 672cf4
Packit Service 672cf4
	 We want:
Packit Service 672cf4
	 uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
Packit Service 672cf4
      */
Packit Service 672cf4
Packit Service 672cf4
      {
Packit Service 672cf4
	/* The user ID is percent escaped, but we want c-coded.
Packit Service 672cf4
	   Because we have to replace each '%HL' by '\xHL', we need at
Packit Service 672cf4
	   most 4/3 th the number of bytes.  But because we also need
Packit Service 672cf4
	   to escape the backslashes we allocate twice as much.  */
Packit Service 672cf4
	char *uid = malloc (2 * strlen (field[1]) + 1);
Packit Service 672cf4
	char *src;
Packit Service 672cf4
	char *dst;
Packit Service 672cf4
Packit Service 672cf4
	if (! uid)
Packit Service 672cf4
	  return gpg_error_from_syserror ();
Packit Service 672cf4
	src = field[1];
Packit Service 672cf4
	dst = uid;
Packit Service 672cf4
	while (*src)
Packit Service 672cf4
	  {
Packit Service 672cf4
	    if (*src == '%')
Packit Service 672cf4
	      {
Packit Service 672cf4
		*(dst++) = '\\';
Packit Service 672cf4
		*(dst++) = 'x';
Packit Service 672cf4
		src++;
Packit Service 672cf4
		/* Copy the next two bytes unconditionally.  */
Packit Service 672cf4
		if (*src)
Packit Service 672cf4
		  *(dst++) = *(src++);
Packit Service 672cf4
		if (*src)
Packit Service 672cf4
		  *(dst++) = *(src++);
Packit Service 672cf4
	      }
Packit Service 672cf4
	    else if (*src == '\\')
Packit Service 672cf4
              {
Packit Service 672cf4
                *dst++ = '\\';
Packit Service 672cf4
                *dst++ = '\\';
Packit Service 672cf4
                src++;
Packit Service 672cf4
              }
Packit Service 672cf4
	    else
Packit Service 672cf4
	      *(dst++) = *(src++);
Packit Service 672cf4
	  }
Packit Service 672cf4
	*dst = '\0';
Packit Service 672cf4
Packit Service 672cf4
        if (fields < 4)
Packit Service 672cf4
          {
Packit Service 672cf4
            if (gpgrt_asprintf (r_line, "uid:o::::::::%s:", uid) < 0)
Packit Service 672cf4
              return gpg_error_from_syserror ();
Packit Service 672cf4
          }
Packit Service 672cf4
        else
Packit Service 672cf4
          {
Packit Service 672cf4
            if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
Packit Service 672cf4
                                field[4], field[2], field[3], uid) < 0)
Packit Service 672cf4
              return gpg_error_from_syserror ();
Packit Service 672cf4
          }
Packit Service 672cf4
      }
Packit Service 672cf4
      return 0;
Packit Service 672cf4
Packit Service 672cf4
    case RT_NONE:
Packit Service 672cf4
      /* Unknown record.  */
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return 0;
Packit Service 672cf4
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpg_error_t
Packit Service 672cf4
gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
Packit Service 672cf4
                           gpgme_keylist_mode_t mode)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--with-colons");
Packit Service 672cf4
Packit Service 672cf4
  /* Since gpg 2.1.15 fingerprints are always printed, thus there is
Packit Service 672cf4
   * no more need to explicitly request them.  */
Packit Service 672cf4
  if (!have_gpg_version (gpg, "2.1.15"))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--fixed-list-mode");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--with-fingerprint");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, "--with-fingerprint");
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
Packit Service 672cf4
      && have_gpg_version (gpg, "2.1.16"))
Packit Service 672cf4
    err = add_arg (gpg, "--with-tofu-info");
Packit Service 672cf4
Packit Service 672cf4
  if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
Packit Service 672cf4
    err = add_arg (gpg, "--with-secret");
Packit Service 672cf4
Packit Service 672cf4
  if (!err
Packit Service 672cf4
      && (mode & GPGME_KEYLIST_MODE_SIGS)
Packit Service 672cf4
      && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--list-options");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
Packit Service 672cf4
	{
Packit Service 672cf4
          if (secret_only)
Packit Service 672cf4
            err = gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
          else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
Packit Service 672cf4
            {
Packit Service 672cf4
              /* The local+extern mode is special.  It works only with
Packit Service 672cf4
                 gpg >= 2.0.10.  FIXME: We should check that we have
Packit Service 672cf4
                 such a version to that we can return a proper error
Packit Service 672cf4
                 code.  The problem is that we don't know the context
Packit Service 672cf4
                 here and thus can't access the cached version number
Packit Service 672cf4
                 for the engine info structure.  */
Packit Service 672cf4
              err = add_arg (gpg, "--locate-keys");
Packit Service 672cf4
              if ((mode & GPGME_KEYLIST_MODE_SIGS))
Packit Service 672cf4
                err = add_arg (gpg, "--with-sig-check");
Packit Service 672cf4
            }
Packit Service 672cf4
          else
Packit Service 672cf4
            {
Packit Service 672cf4
              err = add_arg (gpg, "--search-keys");
Packit Service 672cf4
              gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
Packit Service 672cf4
            }
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
        {
Packit Service 672cf4
          err = add_arg (gpg, secret_only ? "--list-secret-keys"
Packit Service 672cf4
                         : ((mode & GPGME_KEYLIST_MODE_SIGS)
Packit Service 672cf4
                            ? "--check-sigs" : "--list-keys"));
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_keylist (void *engine, const char *pattern, int secret_only,
Packit Service 672cf4
	     gpgme_keylist_mode_t mode, int engine_flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)engine_flags;
Packit Service 672cf4
Packit Service 672cf4
  err = gpg_keylist_build_options (gpg, secret_only, mode);
Packit Service 672cf4
Packit Service 672cf4
  if (!err && pattern && *pattern)
Packit Service 672cf4
    err = add_arg (gpg, pattern);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
Packit Service 672cf4
		 int reserved, gpgme_keylist_mode_t mode, int engine_flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)engine_flags;
Packit Service 672cf4
Packit Service 672cf4
  if (reserved)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  err = gpg_keylist_build_options (gpg, secret_only, mode);
Packit Service 672cf4
Packit Service 672cf4
  if (pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      while (!err && *pattern && **pattern)
Packit Service 672cf4
	err = add_arg (gpg, *(pattern++));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_keylist_data (void *engine, gpgme_data_t data)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  if (!have_gpg_version (gpg, "2.1.14"))
Packit Service 672cf4
    return gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--with-colons");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--with-fingerprint");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--import-options");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "import-show");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--dry-run");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--import");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, data, -1, 0);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
Packit Service 672cf4
             unsigned long expire, unsigned int flags,
Packit Service 672cf4
             gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  const char *s;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_ARG);
Packit Service 672cf4
Packit Service 672cf4
  if (!have_gpg_version (gpg, "2.1.12"))
Packit Service 672cf4
    return gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
Packit Service 672cf4
  if ((flags & GPGME_KEYSIGN_LOCAL))
Packit Service 672cf4
    err = add_arg (gpg, "--quick-lsign-key");
Packit Service 672cf4
  else
Packit Service 672cf4
    err = add_arg (gpg, "--quick-sign-key");
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_signers (gpg, ctx);
Packit Service 672cf4
Packit Service 672cf4
  /* If an expiration time has been given use that.  If none has been
Packit Service 672cf4
   * given the default from gpg.conf is used.  To make sure not to set
Packit Service 672cf4
   * an expiration time at all the flag GPGME_KEYSIGN_NOEXPIRE can be
Packit Service 672cf4
   * used.  */
Packit Service 672cf4
  if (!err && (expire || (flags & GPGME_KEYSIGN_NOEXPIRE)))
Packit Service 672cf4
    {
Packit Service 672cf4
      char tmpbuf[8+20];
Packit Service 672cf4
Packit Service 672cf4
      if ((flags & GPGME_KEYSIGN_NOEXPIRE))
Packit Service 672cf4
        expire = 0;
Packit Service 672cf4
      snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire);
Packit Service 672cf4
      err = add_arg (gpg, "--default-cert-expire");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_arg (gpg, tmpbuf);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, key->fpr);
Packit Service 672cf4
  if (!err && userid)
Packit Service 672cf4
    {
Packit Service 672cf4
      if ((flags & GPGME_KEYSIGN_LFSEP))
Packit Service 672cf4
        {
Packit Service 672cf4
          for (; !err && (s = strchr (userid, '\n')); userid = s + 1)
Packit Service 672cf4
            if ((s - userid))
Packit Service 672cf4
              err = add_arg_len (gpg, "=", userid, s - userid);
Packit Service 672cf4
          if (!err && *userid)
Packit Service 672cf4
            err = add_arg_pfx (gpg, "=", userid);
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        err = add_arg_pfx (gpg, "=", userid);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  const char *policystr = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_ARG);
Packit Service 672cf4
Packit Service 672cf4
  switch (policy)
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_TOFU_POLICY_NONE:                           break;
Packit Service 672cf4
    case GPGME_TOFU_POLICY_AUTO:    policystr = "auto";    break;
Packit Service 672cf4
    case GPGME_TOFU_POLICY_GOOD:    policystr = "good";    break;
Packit Service 672cf4
    case GPGME_TOFU_POLICY_BAD:     policystr = "bad";     break;
Packit Service 672cf4
    case GPGME_TOFU_POLICY_ASK:     policystr = "ask";     break;
Packit Service 672cf4
    case GPGME_TOFU_POLICY_UNKNOWN: policystr = "unknown"; break;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (!policystr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (!have_gpg_version (gpg, "2.1.10"))
Packit Service 672cf4
    return gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--tofu-policy");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, policystr);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, key->fpr);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
Packit Service 672cf4
	  gpgme_sig_mode_t mode, int use_armor, int use_textmode,
Packit Service 672cf4
	  int include_certs, gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)include_certs;
Packit Service 672cf4
Packit Service 672cf4
  if (mode == GPGME_SIG_MODE_CLEAR)
Packit Service 672cf4
    err = add_arg (gpg, "--clearsign");
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--sign");
Packit Service 672cf4
      if (!err && mode == GPGME_SIG_MODE_DETACH)
Packit Service 672cf4
	err = add_arg (gpg, "--detach");
Packit Service 672cf4
      if (!err && use_armor)
Packit Service 672cf4
	err = add_arg (gpg, "--armor");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (gpgme_data_get_encoding (in) == GPGME_DATA_ENCODING_MIME
Packit Service 672cf4
              && have_gpg_version (gpg, "2.1.14"))
Packit Service 672cf4
            err = add_arg (gpg, "--mimemode");
Packit Service 672cf4
          else if (use_textmode)
Packit Service 672cf4
            err = add_arg (gpg, "--textmode");
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_signers (gpg, ctx);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_sender (gpg, ctx);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = append_args_from_sig_notations (gpg, ctx);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgme_data_get_file_name (in))
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "--set-filename");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, gpgme_data_get_file_name (in));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Tell the gpg object about the data.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_input_size_hint (gpg, in);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, in, -1, 0);
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_data (gpg, out, 1, 1);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_trustlist (void *engine, const char *pattern)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = add_arg (gpg, "--with-colons");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--list-trust-path");
Packit Service 672cf4
Packit Service 672cf4
  /* Tell the gpg object about the data.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, "--");
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = add_arg (gpg, pattern);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
Packit Service 672cf4
	    gpgme_data_t plaintext, gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = append_args_from_sender (gpg, ctx);
Packit Service 672cf4
  if (!err && ctx->auto_key_retrieve)
Packit Service 672cf4
    err = add_arg (gpg, "--auto-key-retrieve");
Packit Service 672cf4
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    ;
Packit Service 672cf4
  else if (plaintext)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Normal or cleartext signature.  */
Packit Service 672cf4
      err = add_arg (gpg, "--output");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "-");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_input_size_hint (gpg, sig);
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "--");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_data (gpg, sig, -1, 0);
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_data (gpg, plaintext, 1, 1);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_arg (gpg, "--verify");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
        err = add_input_size_hint (gpg, signed_text);
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_arg (gpg, "--");
Packit Service 672cf4
      if (!err)
Packit Service 672cf4
	err = add_data (gpg, sig, -1, 0);
Packit Service 672cf4
      if (!err && signed_text)
Packit Service 672cf4
	err = add_data (gpg, signed_text, -1, 0);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpg);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpg->io_cbs = *io_cbs;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpg_t gpg = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpg->pinentry_mode = mode;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
static gpgme_error_t
Packit Service 0ef63b
gpg_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
Packit Service 0ef63b
{
Packit Service 0ef63b
  engine_gpg_t gpg = engine;
Packit Service 0ef63b
#define MYBUFLEN 4096
Packit Service 0ef63b
  char buf[MYBUFLEN];
Packit Service 0ef63b
  int nread;
Packit Service 0ef63b
  int any_written = 0;
Packit Service 0ef63b
Packit Service 0ef63b
  if (!(flags & GPGME_AUDITLOG_DIAG))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (!gpg || !output)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (!gpg->diagnostics)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      return gpg_error (GPG_ERR_GENERAL);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_data_rewind (gpg->diagnostics);
Packit Service 0ef63b
Packit Service 0ef63b
  while ((nread = gpgme_data_read (gpg->diagnostics, buf, MYBUFLEN)) > 0)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      any_written = 1;
Packit Service 0ef63b
      if (gpgme_data_write (output, buf, nread) == -1)
Packit Service 0ef63b
        return gpg_error_from_syserror ();
Packit Service 0ef63b
    }
Packit Service 0ef63b
  if (!any_written)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      return gpg_error (GPG_ERR_NO_DATA);
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (nread == -1)
Packit Service 0ef63b
    return gpg_error_from_syserror ();
Packit Service 0ef63b
Packit Service 0ef63b
  gpgme_data_rewind (output);
Packit Service 0ef63b
  return 0;
Packit Service 0ef63b
#undef MYBUFLEN
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 672cf4

Packit Service 672cf4
struct engine_ops _gpgme_engine_ops_gpg =
Packit Service 672cf4
  {
Packit Service 672cf4
    /* Static functions.  */
Packit Service 672cf4
    _gpgme_get_default_gpg_name,
Packit Service 672cf4
    NULL,
Packit Service 672cf4
    gpg_get_version,
Packit Service 672cf4
    gpg_get_req_version,
Packit Service 672cf4
    gpg_new,
Packit Service 672cf4
Packit Service 672cf4
    /* Member functions.  */
Packit Service 672cf4
    gpg_release,
Packit Service 672cf4
    NULL,				/* reset */
Packit Service 672cf4
    gpg_set_status_cb,
Packit Service 672cf4
    gpg_set_status_handler,
Packit Service 672cf4
    gpg_set_command_handler,
Packit Service 672cf4
    gpg_set_colon_line_handler,
Packit Service 672cf4
    gpg_set_locale,
Packit Service 672cf4
    NULL,				/* set_protocol */
Packit Service 0ef63b
    gpg_set_engine_flags,               /* set_engine_flags */
Packit Service 672cf4
    gpg_decrypt,
Packit Service 672cf4
    gpg_delete,
Packit Service 672cf4
    gpg_edit,
Packit Service 672cf4
    gpg_encrypt,
Packit Service 672cf4
    gpg_encrypt_sign,
Packit Service 672cf4
    gpg_export,
Packit Service 672cf4
    gpg_export_ext,
Packit Service 672cf4
    gpg_genkey,
Packit Service 672cf4
    gpg_import,
Packit Service 672cf4
    gpg_keylist,
Packit Service 672cf4
    gpg_keylist_ext,
Packit Service 672cf4
    gpg_keylist_data,
Packit Service 672cf4
    gpg_keysign,
Packit Service 672cf4
    gpg_tofu_policy,    /* tofu_policy */
Packit Service 672cf4
    gpg_sign,
Packit Service 672cf4
    gpg_trustlist,
Packit Service 672cf4
    gpg_verify,
Packit Service 0ef63b
    gpg_getauditlog,
Packit Service 672cf4
    NULL,               /* opassuan_transact */
Packit Service 672cf4
    NULL,		/* conf_load */
Packit Service 672cf4
    NULL,		/* conf_save */
Packit Service 672cf4
    NULL,		/* conf_dir */
Packit Service 672cf4
    NULL,               /* query_swdb */
Packit Service 672cf4
    gpg_set_io_cbs,
Packit Service 672cf4
    gpg_io_event,
Packit Service 672cf4
    gpg_cancel,
Packit Service 672cf4
    NULL,		/* cancel_op */
Packit Service 672cf4
    gpg_passwd,
Packit Service 672cf4
    gpg_set_pinentry_mode,
Packit Service 672cf4
    NULL                /* opspawn */
Packit Service 672cf4
  };