Blame src/engine-gpg.c

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