Blame src/engine-gpgsm.c

Packit Service 672cf4
/* engine-gpgsm.c - GpgSM engine.
Packit Service 0ef63b
 * Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 0ef63b
 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009,
Packit Service 0ef63b
 *               2010 g10 Code GmbH
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * This file is part of GPGME.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is free software; you can redistribute it and/or modify it
Packit Service 0ef63b
 * under the terms of the GNU Lesser General Public License as
Packit Service 0ef63b
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 0ef63b
 * the License, or (at your option) any later version.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * GPGME is distributed in the hope that it will be useful, but
Packit Service 0ef63b
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0ef63b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 0ef63b
 * Lesser General Public License for more details.
Packit Service 0ef63b
 *
Packit Service 0ef63b
 * You should have received a copy of the GNU Lesser General Public
Packit Service 0ef63b
 * License along with this program; if not, see <https://gnu.org/licenses/>.
Packit Service 0ef63b
 * SPDX-License-Identifier: LGPL-2.1-or-later
Packit Service 0ef63b
 */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#ifdef HAVE_SYS_TYPES_H
Packit Service 672cf4
# include <sys/types.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#ifdef HAVE_UNISTD_H
Packit Service 672cf4
# include <unistd.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef HAVE_LOCALE_H
Packit Service 672cf4
#include <locale.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <fcntl.h> /* FIXME */
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "wait.h"
Packit Service 672cf4
#include "priv-io.h"
Packit Service 672cf4
#include "sema.h"
Packit Service 672cf4
#include "data.h"
Packit Service 672cf4
Packit Service 672cf4
#include "assuan.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4
#include "engine-backend.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
typedef struct
Packit Service 672cf4
{
Packit Service 672cf4
  int fd;	/* FD we talk about.  */
Packit Service 672cf4
  int server_fd;/* Server FD for this connection.  */
Packit Service 672cf4
  int dir;	/* Inbound/Outbound, maybe given implicit?  */
Packit Service 672cf4
  void *data;	/* Handler-specific data.  */
Packit Service 672cf4
  void *tag;	/* ID from the user for gpgme_remove_io_callback.  */
Packit Service 672cf4
  char server_fd_str[15]; /* Same as SERVER_FD but as a string.  We
Packit Service 672cf4
                             need this because _gpgme_io_fd2str can't
Packit Service 672cf4
                             be used on a closed descriptor.  */
Packit Service 672cf4
} iocb_data_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct engine_gpgsm
Packit Service 672cf4
{
Packit Service 672cf4
  assuan_context_t assuan_ctx;
Packit Service 672cf4
Packit Service 672cf4
  int lc_ctype_set;
Packit Service 672cf4
  int lc_messages_set;
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t status_cb;
Packit Service 672cf4
Packit Service 672cf4
  /* Input, output etc are from the servers perspective.  */
Packit Service 672cf4
  iocb_data_t input_cb;
Packit Service 672cf4
  gpgme_data_t input_helper_data;  /* Input helper data object.  */
Packit Service 672cf4
  void *input_helper_memory;       /* Input helper memory block.  */
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t output_cb;
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t message_cb;
Packit Service 0ef63b
  iocb_data_t diag_cb;
Packit Service 672cf4
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    engine_status_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    gpgme_status_cb_t mon_cb;
Packit Service 672cf4
    void *mon_cb_value;
Packit Service 672cf4
  } status;
Packit Service 672cf4
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    engine_colon_line_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    struct
Packit Service 672cf4
    {
Packit Service 672cf4
      char *line;
Packit Service 672cf4
      int linesize;
Packit Service 672cf4
      int linelen;
Packit Service 672cf4
    } attic;
Packit Service 672cf4
    int any; /* any data line seen */
Packit Service 672cf4
  } colon;
Packit Service 672cf4
Packit Service 672cf4
  gpgme_data_t inline_data;  /* Used to collect D lines.  */
Packit Service 672cf4
Packit Service 0ef63b
  char request_origin[10];
Packit Service 0ef63b
Packit Service 672cf4
  struct gpgme_io_cbs io_cbs;
Packit Service 0ef63b
Packit Service 0ef63b
  /* Memory data containing diagnostics (--logger-fd) of gpgsm */
Packit Service 0ef63b
  gpgme_data_t diagnostics;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
typedef struct engine_gpgsm *engine_gpgsm_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void gpgsm_io_event (void *engine,
Packit Service 672cf4
                            gpgme_event_io_t type, void *type_data);
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static char *
Packit Service 672cf4
gpgsm_get_version (const char *file_name)
Packit Service 672cf4
{
Packit Service 672cf4
  return _gpgme_get_program_version (file_name ? file_name
Packit Service 672cf4
				     : _gpgme_get_default_gpgsm_name ());
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
gpgsm_get_req_version (void)
Packit Service 672cf4
{
Packit Service 672cf4
  return "2.0.4";
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static void
Packit Service 672cf4
close_notify_handler (int fd, void *opaque)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = opaque;
Packit Service 672cf4
Packit Service 672cf4
  assert (fd != -1);
Packit Service 672cf4
  if (gpgsm->status_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgsm->status_cb.tag)
Packit Service 672cf4
	(*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
Packit Service 672cf4
      gpgsm->status_cb.fd = -1;
Packit Service 672cf4
      gpgsm->status_cb.tag = NULL;
Packit Service 0ef63b
      /* Because the server keeps on running as long as the
Packit Service 0ef63b
       * gpgme_ctx_t is valid the diag fd will not receive a close and
Packit Service 0ef63b
       * thus the operation gets stuck trying to read the diag fd.
Packit Service 0ef63b
       * The status fd however is closed right after it received the
Packit Service 0ef63b
       * "OK" from the command.  So we use this event to also close
Packit Service 0ef63b
       * the diag fd.  */
Packit Service 0ef63b
      _gpgme_io_close (gpgsm->diag_cb.fd);
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpgsm->input_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgsm->input_cb.tag)
Packit Service 672cf4
	(*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
Packit Service 672cf4
      gpgsm->input_cb.fd = -1;
Packit Service 672cf4
      gpgsm->input_cb.tag = NULL;
Packit Service 672cf4
      if (gpgsm->input_helper_data)
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgme_data_release (gpgsm->input_helper_data);
Packit Service 672cf4
          gpgsm->input_helper_data = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (gpgsm->input_helper_memory)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (gpgsm->input_helper_memory);
Packit Service 672cf4
          gpgsm->input_helper_memory = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpgsm->output_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgsm->output_cb.tag)
Packit Service 672cf4
	(*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
Packit Service 672cf4
      gpgsm->output_cb.fd = -1;
Packit Service 672cf4
      gpgsm->output_cb.tag = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (gpgsm->message_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgsm->message_cb.tag)
Packit Service 672cf4
	(*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
Packit Service 672cf4
      gpgsm->message_cb.fd = -1;
Packit Service 672cf4
      gpgsm->message_cb.tag = NULL;
Packit Service 672cf4
    }
Packit Service 0ef63b
  else if (gpgsm->diag_cb.fd == fd)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (gpgsm->diag_cb.tag)
Packit Service 0ef63b
	(*gpgsm->io_cbs.remove) (gpgsm->diag_cb.tag);
Packit Service 0ef63b
      gpgsm->diag_cb.fd = -1;
Packit Service 0ef63b
      gpgsm->diag_cb.tag = NULL;
Packit Service 0ef63b
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This is the default inquiry callback.  We use it to handle the
Packit Service 672cf4
   Pinentry notifications.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
Packit Service 672cf4
{
Packit Service 672cf4
  (void)gpgsm;
Packit Service 672cf4
Packit Service 672cf4
  if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_cancel (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgsm->status_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->status_cb.fd);
Packit Service 672cf4
  if (gpgsm->input_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->input_cb.fd);
Packit Service 672cf4
  if (gpgsm->output_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->output_cb.fd);
Packit Service 672cf4
  if (gpgsm->message_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->message_cb.fd);
Packit Service 0ef63b
  if (gpgsm->diag_cb.fd != -1)
Packit Service 0ef63b
    _gpgme_io_close (gpgsm->diag_cb.fd);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgsm->assuan_ctx)
Packit Service 672cf4
    {
Packit Service 672cf4
      assuan_release (gpgsm->assuan_ctx);
Packit Service 672cf4
      gpgsm->assuan_ctx = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_release (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_cancel (engine);
Packit Service 672cf4
Packit Service 0ef63b
  gpgme_data_release (gpgsm->diagnostics);
Packit Service 0ef63b
Packit Service 672cf4
  free (gpgsm->colon.attic.line);
Packit Service 672cf4
  free (gpgsm);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_new (void **engine, const char *file_name, const char *home_dir,
Packit Service 672cf4
           const char *version)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  engine_gpgsm_t gpgsm;
Packit Service 672cf4
  const char *pgmname;
Packit Service 0ef63b
  const char *argv[7];
Packit Service 0ef63b
  char *diag_fd_str = NULL;
Packit Service 672cf4
  int argc;
Packit Service 672cf4
  int fds[2];
Packit Service 0ef63b
  int child_fds[5];
Packit Service 0ef63b
  int nchild_fds;
Packit Service 672cf4
  char *dft_display = NULL;
Packit Service 672cf4
  char dft_ttyname[64];
Packit Service 672cf4
  char *env_tty = NULL;
Packit Service 672cf4
  char *dft_ttytype = NULL;
Packit Service 672cf4
  char *optstr;
Packit Service 0ef63b
  unsigned int connect_flags;
Packit Service 672cf4
Packit Service 672cf4
  (void)version; /* Not yet used.  */
Packit Service 672cf4
Packit Service 672cf4
  gpgsm = calloc (1, sizeof *gpgsm);
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->status_cb.fd = -1;
Packit Service 672cf4
  gpgsm->status_cb.dir = 1;
Packit Service 672cf4
  gpgsm->status_cb.tag = 0;
Packit Service 672cf4
  gpgsm->status_cb.data = gpgsm;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->input_cb.fd = -1;
Packit Service 672cf4
  gpgsm->input_cb.dir = 0;
Packit Service 672cf4
  gpgsm->input_cb.tag = 0;
Packit Service 672cf4
  gpgsm->input_cb.server_fd = -1;
Packit Service 672cf4
  *gpgsm->input_cb.server_fd_str = 0;
Packit Service 672cf4
  gpgsm->output_cb.fd = -1;
Packit Service 672cf4
  gpgsm->output_cb.dir = 1;
Packit Service 672cf4
  gpgsm->output_cb.tag = 0;
Packit Service 672cf4
  gpgsm->output_cb.server_fd = -1;
Packit Service 672cf4
  *gpgsm->output_cb.server_fd_str = 0;
Packit Service 672cf4
  gpgsm->message_cb.fd = -1;
Packit Service 672cf4
  gpgsm->message_cb.dir = 0;
Packit Service 672cf4
  gpgsm->message_cb.tag = 0;
Packit Service 672cf4
  gpgsm->message_cb.server_fd = -1;
Packit Service 672cf4
  *gpgsm->message_cb.server_fd_str = 0;
Packit Service 0ef63b
  gpgsm->diag_cb.fd = -1;
Packit Service 0ef63b
  gpgsm->diag_cb.dir = 1;
Packit Service 0ef63b
  gpgsm->diag_cb.tag = 0;
Packit Service 0ef63b
  gpgsm->diag_cb.server_fd = -1;
Packit Service 0ef63b
  *gpgsm->diag_cb.server_fd_str = 0;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->status.fnc = 0;
Packit Service 672cf4
  gpgsm->colon.fnc = 0;
Packit Service 672cf4
  gpgsm->colon.attic.line = 0;
Packit Service 672cf4
  gpgsm->colon.attic.linesize = 0;
Packit Service 672cf4
  gpgsm->colon.attic.linelen = 0;
Packit Service 672cf4
  gpgsm->colon.any = 0;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->io_cbs.add = NULL;
Packit Service 672cf4
  gpgsm->io_cbs.add_priv = NULL;
Packit Service 672cf4
  gpgsm->io_cbs.remove = NULL;
Packit Service 672cf4
  gpgsm->io_cbs.event = NULL;
Packit Service 672cf4
  gpgsm->io_cbs.event_priv = NULL;
Packit Service 672cf4
Packit Service 0ef63b
  if (_gpgme_io_pipe (fds, 1) < 0)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error_from_syserror ();
Packit Service 0ef63b
      goto leave;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  gpgsm->diag_cb.fd = fds[0];
Packit Service 0ef63b
  gpgsm->diag_cb.server_fd = fds[1];
Packit Service 0ef63b
Packit Service 0ef63b
#if USE_DESCRIPTOR_PASSING
Packit Service 0ef63b
  child_fds[0] = gpgsm->diag_cb.server_fd;
Packit Service 0ef63b
  child_fds[1] = -1;
Packit Service 0ef63b
  nchild_fds = 2;
Packit Service 0ef63b
  connect_flags = ASSUAN_PIPE_CONNECT_FDPASSING;
Packit Service 0ef63b
#else /*!USE_DESCRIPTOR_PASSING*/
Packit Service 672cf4
  if (_gpgme_io_pipe (fds, 0) < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  gpgsm->input_cb.fd = fds[1];
Packit Service 672cf4
  gpgsm->input_cb.server_fd = fds[0];
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_io_pipe (fds, 1) < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  gpgsm->output_cb.fd = fds[0];
Packit Service 672cf4
  gpgsm->output_cb.server_fd = fds[1];
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_io_pipe (fds, 0) < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error_from_syserror ();
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
  gpgsm->message_cb.fd = fds[1];
Packit Service 672cf4
  gpgsm->message_cb.server_fd = fds[0];
Packit Service 672cf4
Packit Service 672cf4
  child_fds[0] = gpgsm->input_cb.server_fd;
Packit Service 672cf4
  child_fds[1] = gpgsm->output_cb.server_fd;
Packit Service 672cf4
  child_fds[2] = gpgsm->message_cb.server_fd;
Packit Service 0ef63b
  child_fds[3] = gpgsm->diag_cb.server_fd;
Packit Service 0ef63b
  child_fds[4] = -1;
Packit Service 0ef63b
  nchild_fds = 5;
Packit Service 0ef63b
  connect_flags = 0;
Packit Service 0ef63b
#endif  /*!USE_DESCRIPTOR_PASSING*/
Packit Service 672cf4
Packit Service 672cf4
  pgmname = file_name ? file_name : _gpgme_get_default_gpgsm_name ();
Packit Service 672cf4
Packit Service 672cf4
  argc = 0;
Packit Service 672cf4
  argv[argc++] = _gpgme_get_basename (pgmname);
Packit Service 672cf4
  if (home_dir)
Packit Service 672cf4
    {
Packit Service 672cf4
      argv[argc++] = "--homedir";
Packit Service 672cf4
      argv[argc++] = home_dir;
Packit Service 672cf4
    }
Packit Service 0ef63b
  /* Set up diagnostics */
Packit Service 0ef63b
  err = gpgme_data_new (&gpgsm->diagnostics);
Packit Service 0ef63b
  if (err)
Packit Service 0ef63b
    goto leave;
Packit Service 0ef63b
  gpgsm->diag_cb.data = gpgsm->diagnostics;
Packit Service 0ef63b
  argv[argc++] = "--logger-fd";
Packit Service 0ef63b
  if (gpgrt_asprintf (&diag_fd_str, "%i", gpgsm->diag_cb.server_fd) == -1)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error_from_syserror ();
Packit Service 0ef63b
      goto leave;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  argv[argc++] = diag_fd_str;
Packit Service 672cf4
  argv[argc++] = "--server";
Packit Service 672cf4
  argv[argc++] = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
Packit Service 672cf4
			&_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
Packit Service 672cf4
			NULL);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
  assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
Packit Service 672cf4
Packit Service 672cf4
  {
Packit Service 0ef63b
    assuan_fd_t achild_fds[5];
Packit Service 672cf4
    int i;
Packit Service 672cf4
Packit Service 672cf4
    /* For now... */
Packit Service 0ef63b
    for (i = 0; i < nchild_fds; i++)
Packit Service 672cf4
      achild_fds[i] = (assuan_fd_t) child_fds[i];
Packit Service 672cf4
Packit Service 672cf4
    err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
Packit Service 0ef63b
                               achild_fds, NULL, NULL, connect_flags);
Packit Service 672cf4
Packit Service 0ef63b
    /* FIXME: Check whether our Windows code still updates the list.*/
Packit Service 0ef63b
    for (i = 0; i < nchild_fds; i++)
Packit Service 672cf4
      child_fds[i] = (int) achild_fds[i];
Packit Service 672cf4
  }
Packit Service 672cf4
Packit Service 0ef63b
Packit Service 0ef63b
#if !USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  /* On Windows, handles are inserted in the spawned process with
Packit Service 672cf4
     DuplicateHandle, and child_fds contains the server-local names
Packit Service 672cf4
     for the inserted handles when assuan_pipe_connect returns.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Note: We don't use _gpgme_io_fd2str here.  On W32 the
Packit Service 672cf4
	 returned handles are real W32 system handles, not whatever
Packit Service 672cf4
	 GPGME uses internally (which may be a system handle, a C
Packit Service 672cf4
	 library handle or a GLib/Qt channel.  Confusing, yes, but
Packit Service 672cf4
	 remember these are server-local names, so they are not part
Packit Service 672cf4
	 of GPGME at all.  */
Packit Service 672cf4
      snprintf (gpgsm->input_cb.server_fd_str,
Packit Service 672cf4
		sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
Packit Service 672cf4
      snprintf (gpgsm->output_cb.server_fd_str,
Packit Service 672cf4
		sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
Packit Service 672cf4
      snprintf (gpgsm->message_cb.server_fd_str,
Packit Service 672cf4
		sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
Packit Service 0ef63b
      snprintf (gpgsm->diag_cb.server_fd_str,
Packit Service 0ef63b
		sizeof gpgsm->diag_cb.server_fd_str, "%d", child_fds[3]);
Packit Service 672cf4
    }
Packit Service 672cf4
#endif
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_getenv ("DISPLAY", &dft_display);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
  if (dft_display)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgrt_asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
Packit Service 672cf4
        {
Packit Service 672cf4
	  free (dft_display);
Packit Service 672cf4
	  err = gpg_error_from_syserror ();
Packit Service 672cf4
	  goto leave;
Packit Service 672cf4
	}
Packit Service 672cf4
      free (dft_display);
Packit Service 672cf4
Packit Service 672cf4
      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
Packit Service 672cf4
			     NULL, NULL, NULL);
Packit Service 672cf4
      gpgrt_free (optstr);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_getenv ("GPG_TTY", &env_tty);
Packit Service 672cf4
  if (isatty (1) || env_tty || err)
Packit Service 672cf4
    {
Packit Service 672cf4
      int rc = 0;
Packit Service 672cf4
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        goto leave;
Packit Service 672cf4
      else if (env_tty)
Packit Service 672cf4
        {
Packit Service 672cf4
          snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
Packit Service 672cf4
          free (env_tty);
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
Packit Service 672cf4
Packit Service 672cf4
      /* Even though isatty() returns 1, ttyname_r() may fail in many
Packit Service 672cf4
	 ways, e.g., when /dev/pts is not accessible under chroot.  */
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (gpgrt_asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      err = gpg_error_from_syserror ();
Packit Service 672cf4
	      goto leave;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
Packit Service 672cf4
				 NULL, NULL, NULL);
Packit Service 672cf4
	  gpgrt_free (optstr);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    goto leave;
Packit Service 672cf4
Packit Service 672cf4
	  err = _gpgme_getenv ("TERM", &dft_ttytype);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    goto leave;
Packit Service 672cf4
	  if (dft_ttytype)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (gpgrt_asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype)< 0)
Packit Service 672cf4
		{
Packit Service 672cf4
		  free (dft_ttytype);
Packit Service 672cf4
		  err = gpg_error_from_syserror ();
Packit Service 672cf4
		  goto leave;
Packit Service 672cf4
		}
Packit Service 672cf4
	      free (dft_ttytype);
Packit Service 672cf4
Packit Service 672cf4
	      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
Packit Service 672cf4
				     NULL, NULL, NULL, NULL);
Packit Service 672cf4
	      gpgrt_free (optstr);
Packit Service 672cf4
	      if (err)
Packit Service 672cf4
		goto leave;
Packit Service 672cf4
	    }
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  /* Ask gpgsm to enable the audit log support.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
Packit Service 672cf4
                             NULL, NULL, NULL, NULL, NULL, NULL);
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
Packit Service 672cf4
        err = 0; /* This is an optional feature of gpgsm.  */
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
#ifdef HAVE_W32_SYSTEM
Packit Service 672cf4
  /* Under Windows we need to use AllowSetForegroundWindow.  Tell
Packit Service 672cf4
     gpgsm to tell us when it needs it.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
Packit Service 672cf4
                             NULL, NULL, NULL, NULL, NULL, NULL);
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
Packit Service 672cf4
        err = 0; /* This is a new feature of gpgsm.  */
Packit Service 672cf4
    }
Packit Service 672cf4
#endif /*HAVE_W32_SYSTEM*/
Packit Service 672cf4
Packit Service 672cf4
#if !USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  if (!err
Packit Service 672cf4
      && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
Packit Service 672cf4
				      close_notify_handler, gpgsm)
Packit Service 672cf4
	  || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
Packit Service 672cf4
					 close_notify_handler, gpgsm)
Packit Service 672cf4
	  || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
Packit Service 672cf4
					 close_notify_handler, gpgsm)))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
      goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
#endif
Packit Service 0ef63b
  if (!err && _gpgme_io_set_close_notify (gpgsm->diag_cb.fd,
Packit Service 0ef63b
                                          close_notify_handler, gpgsm))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      err = gpg_error (GPG_ERR_GENERAL);
Packit Service 0ef63b
      goto leave;
Packit Service 0ef63b
    }
Packit Service 672cf4
Packit Service 672cf4
 leave:
Packit Service 672cf4
  /* Close the server ends of the pipes (because of this, we must use
Packit Service 672cf4
     the stored server_fd_str in the function start).  Our ends are
Packit Service 672cf4
     closed in gpgsm_release().  */
Packit Service 672cf4
#if !USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  if (gpgsm->input_cb.server_fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->input_cb.server_fd);
Packit Service 672cf4
  if (gpgsm->output_cb.server_fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->output_cb.server_fd);
Packit Service 672cf4
  if (gpgsm->message_cb.server_fd != -1)
Packit Service 672cf4
    _gpgme_io_close (gpgsm->message_cb.server_fd);
Packit Service 0ef63b
  if (gpgsm->diag_cb.server_fd != -1)
Packit Service 0ef63b
    _gpgme_io_close (gpgsm->diag_cb.server_fd);
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    gpgsm_release (gpgsm);
Packit Service 672cf4
  else
Packit Service 672cf4
    *engine = gpgsm;
Packit Service 0ef63b
  free (diag_fd_str);
Packit Service 6c01f9
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Copy flags from CTX into the engine object.  */
Packit Service 0ef63b
static void
Packit Service 0ef63b
gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
Packit Service 0ef63b
{
Packit Service 0ef63b
  engine_gpgsm_t gpgsm = engine;
Packit Service 0ef63b
Packit Service 0ef63b
  if (ctx->request_origin)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      if (strlen (ctx->request_origin) + 1 > sizeof gpgsm->request_origin)
Packit Service 0ef63b
        strcpy (gpgsm->request_origin, "xxx"); /* Too long  - force error */
Packit Service 0ef63b
      else
Packit Service 0ef63b
        strcpy (gpgsm->request_origin, ctx->request_origin);
Packit Service 0ef63b
    }
Packit Service 0ef63b
  else
Packit Service 0ef63b
    *gpgsm->request_origin = 0;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_set_locale (void *engine, int category, const char *value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *optstr;
Packit Service 672cf4
  const char *catstr;
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: If value is NULL, we need to reset the option to default.
Packit Service 672cf4
     But we can't do this.  So we error out here.  GPGSM needs support
Packit Service 672cf4
     for this.  */
Packit Service 672cf4
  if (0)
Packit Service 672cf4
    ;
Packit Service 672cf4
#ifdef LC_CTYPE
Packit Service 672cf4
  else if (category == LC_CTYPE)
Packit Service 672cf4
    {
Packit Service 672cf4
      catstr = "lc-ctype";
Packit Service 672cf4
      if (!value && gpgsm->lc_ctype_set)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	gpgsm->lc_ctype_set = 1;
Packit Service 672cf4
    }
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef LC_MESSAGES
Packit Service 672cf4
  else if (category == LC_MESSAGES)
Packit Service 672cf4
    {
Packit Service 672cf4
      catstr = "lc-messages";
Packit Service 672cf4
      if (!value && gpgsm->lc_messages_set)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	gpgsm->lc_messages_set = 1;
Packit Service 672cf4
    }
Packit Service 672cf4
#endif /* LC_MESSAGES */
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: Reset value to default.  */
Packit Service 672cf4
  if (!value)
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
Packit Service 672cf4
    err = gpg_error_from_syserror ();
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
Packit Service 672cf4
			     NULL, NULL, NULL, NULL);
Packit Service 672cf4
      gpgrt_free (optstr);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, const char *cmd,
Packit Service 672cf4
			     engine_status_handler_t status_fnc,
Packit Service 672cf4
			     void *status_fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  assuan_context_t ctx = gpgsm->assuan_ctx;
Packit Service 672cf4
  gpg_error_t err, cb_err;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  size_t linelen;
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_write_line (ctx, cmd);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  cb_err = 0;
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_read_line (ctx, &line, &linelen);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	break;
Packit Service 672cf4
Packit Service 672cf4
      if (*line == '#' || !linelen)
Packit Service 672cf4
	continue;
Packit Service 672cf4
Packit Service 672cf4
      if (linelen >= 2
Packit Service 672cf4
	  && line[0] == 'O' && line[1] == 'K'
Packit Service 672cf4
	  && (line[2] == '\0' || line[2] == ' '))
Packit Service 672cf4
	break;
Packit Service 672cf4
      else if (linelen >= 4
Packit Service 672cf4
	  && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
Packit Service 672cf4
	  && line[3] == ' ')
Packit Service 672cf4
        {
Packit Service 672cf4
          /* We prefer a callback generated error because that one is
Packit Service 672cf4
             more related to gpgme and thus probably more important
Packit Service 672cf4
             than the error returned by the engine.  */
Packit Service 672cf4
          err = cb_err? cb_err : atoi (&line[4]);
Packit Service 672cf4
          cb_err = 0;
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (linelen >= 2
Packit Service 672cf4
	       && line[0] == 'S' && line[1] == ' ')
Packit Service 672cf4
	{
Packit Service 672cf4
          /* After an error from a status callback we skip all further
Packit Service 672cf4
             status lines.  */
Packit Service 672cf4
          if (!cb_err)
Packit Service 672cf4
            {
Packit Service 672cf4
              char *rest;
Packit Service 672cf4
              gpgme_status_code_t r;
Packit Service 672cf4
Packit Service 672cf4
              rest = strchr (line + 2, ' ');
Packit Service 672cf4
              if (!rest)
Packit Service 672cf4
                rest = line + linelen; /* set to an empty string */
Packit Service 672cf4
              else
Packit Service 672cf4
                *(rest++) = 0;
Packit Service 672cf4
Packit Service 672cf4
              r = _gpgme_parse_status (line + 2);
Packit Service 672cf4
              if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
Packit Service 672cf4
                {
Packit Service 672cf4
                  /* Note that we call the monitor even if we do
Packit Service 672cf4
                   * not know the status code (r < 0).  */
Packit Service 672cf4
                  cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
Packit Service 672cf4
                                                 line + 2, rest);
Packit Service 672cf4
                }
Packit Service 672cf4
Packit Service 672cf4
              if (r >= 0 && status_fnc && !cb_err)
Packit Service 672cf4
                cb_err = status_fnc (status_fnc_value, r, rest);
Packit Service 672cf4
            }
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
        {
Packit Service 672cf4
          /* Invalid line or INQUIRY.  We can't do anything else than
Packit Service 672cf4
             to stop.  As with ERR we prefer a status callback
Packit Service 672cf4
             generated error code, though.  */
Packit Service 672cf4
          err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
          cb_err = 0;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  while (!err);
Packit Service 672cf4
Packit Service 672cf4
  /* We only want the first error from the status handler, thus we
Packit Service 672cf4
   * take the one saved in CB_ERR. */
Packit Service 672cf4
  if (!err && cb_err)
Packit Service 672cf4
    err = cb_err;
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
Packit Service 672cf4
{
Packit Service 672cf4
#if !USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  switch (fd_type)
Packit Service 672cf4
    {
Packit Service 672cf4
    case INPUT_FD:
Packit Service 672cf4
      _gpgme_io_close (gpgsm->input_cb.fd);
Packit Service 672cf4
      break;
Packit Service 672cf4
    case OUTPUT_FD:
Packit Service 672cf4
      _gpgme_io_close (gpgsm->output_cb.fd);
Packit Service 672cf4
      break;
Packit Service 672cf4
    case MESSAGE_FD:
Packit Service 672cf4
      _gpgme_io_close (gpgsm->message_cb.fd);
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
#else
Packit Service 672cf4
  (void)gpgsm;
Packit Service 672cf4
  (void)fd_type;
Packit Service 672cf4
#endif
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
#define COMMANDLINELEN 40
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err = 0;
Packit Service 672cf4
  char line[COMMANDLINELEN];
Packit Service 672cf4
  const char *which;
Packit Service 672cf4
  iocb_data_t *iocb_data;
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  int dir;
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
  switch (fd_type)
Packit Service 672cf4
    {
Packit Service 672cf4
    case INPUT_FD:
Packit Service 672cf4
      which = "INPUT";
Packit Service 672cf4
      iocb_data = &gpgsm->input_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case OUTPUT_FD:
Packit Service 672cf4
      which = "OUTPUT";
Packit Service 672cf4
      iocb_data = &gpgsm->output_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case MESSAGE_FD:
Packit Service 672cf4
      which = "MESSAGE";
Packit Service 672cf4
      iocb_data = &gpgsm->message_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  dir = iocb_data->dir;
Packit Service 672cf4
  /* We try to short-cut the communication by giving GPGSM direct
Packit Service 672cf4
     access to the file descriptor, rather than using a pipe.  */
Packit Service 672cf4
  iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
Packit Service 672cf4
  if (iocb_data->server_fd < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      int fds[2];
Packit Service 672cf4
Packit Service 672cf4
      if (_gpgme_io_pipe (fds, dir) < 0)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
      iocb_data->fd = dir ? fds[0] : fds[1];
Packit Service 672cf4
      iocb_data->server_fd = dir ? fds[1] : fds[0];
Packit Service 672cf4
Packit Service 672cf4
      if (_gpgme_io_set_close_notify (iocb_data->fd,
Packit Service 672cf4
				      close_notify_handler, gpgsm))
Packit Service 672cf4
	{
Packit Service 672cf4
	  err = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
	  goto leave_set_fd;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave_set_fd;
Packit Service 672cf4
Packit Service 672cf4
  _gpgme_io_close (iocb_data->server_fd);
Packit Service 672cf4
  iocb_data->server_fd = -1;
Packit Service 672cf4
Packit Service 672cf4
  if (opt)
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
Packit Service 672cf4
  else
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD", which);
Packit Service 672cf4
#else
Packit Service 672cf4
  if (opt)
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
Packit Service 672cf4
              which, iocb_data->server_fd_str, opt);
Packit Service 672cf4
  else
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD=%s",
Packit Service 672cf4
              which, iocb_data->server_fd_str);
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
  err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
Packit Service 672cf4
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
 leave_set_fd:
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_io_close (iocb_data->fd);
Packit Service 672cf4
      iocb_data->fd = -1;
Packit Service 672cf4
      if (iocb_data->server_fd != -1)
Packit Service 672cf4
        {
Packit Service 672cf4
          _gpgme_io_close (iocb_data->server_fd);
Packit Service 672cf4
          iocb_data->server_fd = -1;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
map_data_enc (gpgme_data_t d)
Packit Service 672cf4
{
Packit Service 672cf4
  switch (gpgme_data_get_encoding (d))
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_DATA_ENCODING_NONE:
Packit Service 672cf4
      break;
Packit Service 672cf4
    case GPGME_DATA_ENCODING_BINARY:
Packit Service 672cf4
      return "--binary";
Packit Service 672cf4
    case GPGME_DATA_ENCODING_BASE64:
Packit Service 672cf4
      return "--base64";
Packit Service 672cf4
    case GPGME_DATA_ENCODING_ARMOR:
Packit Service 672cf4
      return "--armor";
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
status_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  size_t linelen;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* Try our best to terminate the connection friendly.  */
Packit Service 672cf4
	  /*	  assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: error from assuan (%d) getting status line : %s",
Packit Service 672cf4
                  fd, err, gpg_strerror (err));
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 3
Packit Service 672cf4
	       && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
Packit Service 672cf4
	       && (line[3] == '\0' || line[3] == ' '))
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (line[3] == ' ')
Packit Service 672cf4
	    err = atoi (&line[4]);
Packit Service 672cf4
	  if (! err)
Packit Service 672cf4
	    err = gpg_error (GPG_ERR_GENERAL);
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: ERR line - mapped to: %s",
Packit Service 672cf4
                  fd, err ? gpg_strerror (err) : "ok");
Packit Service 672cf4
	  /* Try our best to terminate the connection friendly.  */
Packit Service 672cf4
	  /*	  assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 2
Packit Service 672cf4
	       && line[0] == 'O' && line[1] == 'K'
Packit Service 672cf4
	       && (line[2] == '\0' || line[2] == ' '))
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (gpgsm->status.fnc)
Packit Service 672cf4
            {
Packit Service 672cf4
              char emptystring[1] = {0};
Packit Service 672cf4
              err = gpgsm->status.fnc (gpgsm->status.fnc_value,
Packit Service 672cf4
                                       GPGME_STATUS_EOF, emptystring);
Packit Service 672cf4
              if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
                err = 0; /* Drop special error code.  */
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 672cf4
	  if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
Packit Service 672cf4
            {
Packit Service 672cf4
              /* We must tell a colon function about the EOF. We do
Packit Service 672cf4
                 this only when we have seen any data lines.  Note
Packit Service 672cf4
                 that this inlined use of colon data lines will
Packit Service 672cf4
                 eventually be changed into using a regular data
Packit Service 672cf4
                 channel. */
Packit Service 672cf4
              gpgsm->colon.any = 0;
Packit Service 672cf4
              err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
Packit Service 672cf4
            }
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: OK line - final status: %s",
Packit Service 672cf4
                  fd, err ? gpg_strerror (err) : "ok");
Packit Service 672cf4
	  _gpgme_io_close (gpgsm->status_cb.fd);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'D' && line[1] == ' '
Packit Service 672cf4
	       && gpgsm->colon.fnc)
Packit Service 672cf4
        {
Packit Service 672cf4
	  /* We are using the colon handler even for plain inline data
Packit Service 672cf4
             - strange name for that function but for historic reasons
Packit Service 672cf4
             we keep it.  */
Packit Service 672cf4
          /* FIXME We can't use this for binary data because we
Packit Service 672cf4
             assume this is a string.  For the current usage of colon
Packit Service 672cf4
             output it is correct.  */
Packit Service 672cf4
          char *src = line + 2;
Packit Service 672cf4
	  char *end = line + linelen;
Packit Service 672cf4
	  char *dst;
Packit Service 672cf4
          char **aline = &gpgsm->colon.attic.line;
Packit Service 672cf4
	  int *alinelen = &gpgsm->colon.attic.linelen;
Packit Service 672cf4
Packit Service 672cf4
	  if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      char *newline = realloc (*aline, *alinelen + linelen + 1);
Packit Service 672cf4
	      if (!newline)
Packit Service 672cf4
		err = gpg_error_from_syserror ();
Packit Service 672cf4
	      else
Packit Service 672cf4
		{
Packit Service 672cf4
		  *aline = newline;
Packit Service 672cf4
		  gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      dst = *aline + *alinelen;
Packit Service 672cf4
Packit Service 672cf4
	      while (!err && src < end)
Packit Service 672cf4
		{
Packit Service 672cf4
		  if (*src == '%' && src + 2 < end)
Packit Service 672cf4
		    {
Packit Service 672cf4
		      /* Handle escaped characters.  */
Packit Service 672cf4
		      ++src;
Packit Service 672cf4
		      *dst = _gpgme_hextobyte (src);
Packit Service 672cf4
		      (*alinelen)++;
Packit Service 672cf4
		      src += 2;
Packit Service 672cf4
		    }
Packit Service 672cf4
		  else
Packit Service 672cf4
		    {
Packit Service 672cf4
		      *dst = *src++;
Packit Service 672cf4
		      (*alinelen)++;
Packit Service 672cf4
		    }
Packit Service 672cf4
Packit Service 672cf4
		  if (*dst == '\n')
Packit Service 672cf4
		    {
Packit Service 672cf4
		      /* Terminate the pending line, pass it to the colon
Packit Service 672cf4
			 handler and reset it.  */
Packit Service 672cf4
Packit Service 672cf4
		      gpgsm->colon.any = 1;
Packit Service 672cf4
		      if (*alinelen > 1 && *(dst - 1) == '\r')
Packit Service 672cf4
			dst--;
Packit Service 672cf4
		      *dst = '\0';
Packit Service 672cf4
Packit Service 672cf4
		      /* FIXME How should we handle the return code?  */
Packit Service 672cf4
		      err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
Packit Service 672cf4
		      if (!err)
Packit Service 672cf4
			{
Packit Service 672cf4
			  dst = *aline;
Packit Service 672cf4
			  *alinelen = 0;
Packit Service 672cf4
			}
Packit Service 672cf4
		    }
Packit Service 672cf4
		  else
Packit Service 672cf4
		    dst++;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: D line; final status: %s",
Packit Service 672cf4
                  fd, err? gpg_strerror (err):"ok");
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'D' && line[1] == ' '
Packit Service 672cf4
	       && gpgsm->inline_data)
Packit Service 672cf4
        {
Packit Service 672cf4
          char *src = line + 2;
Packit Service 672cf4
	  char *end = line + linelen;
Packit Service 672cf4
	  char *dst = src;
Packit Service 672cf4
          gpgme_ssize_t nwritten;
Packit Service 672cf4
Packit Service 672cf4
          linelen = 0;
Packit Service 672cf4
          while (src < end)
Packit Service 672cf4
            {
Packit Service 672cf4
              if (*src == '%' && src + 2 < end)
Packit Service 672cf4
                {
Packit Service 672cf4
                  /* Handle escaped characters.  */
Packit Service 672cf4
                  ++src;
Packit Service 672cf4
                  *dst++ = _gpgme_hextobyte (src);
Packit Service 672cf4
                  src += 2;
Packit Service 672cf4
                }
Packit Service 672cf4
              else
Packit Service 672cf4
                *dst++ = *src++;
Packit Service 672cf4
Packit Service 672cf4
              linelen++;
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 672cf4
          src = line + 2;
Packit Service 672cf4
          while (linelen > 0)
Packit Service 672cf4
            {
Packit Service 672cf4
              nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
Packit Service 0ef63b
              if (nwritten <= 0 || nwritten > linelen)
Packit Service 672cf4
                {
Packit Service 672cf4
                  err = gpg_error_from_syserror ();
Packit Service 672cf4
                  break;
Packit Service 672cf4
                }
Packit Service 672cf4
              src += nwritten;
Packit Service 672cf4
              linelen -= nwritten;
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: D inlinedata; final status: %s",
Packit Service 672cf4
                  fd, err? gpg_strerror (err):"ok");
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'S' && line[1] == ' ')
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *rest;
Packit Service 672cf4
	  gpgme_status_code_t r;
Packit Service 672cf4
Packit Service 672cf4
	  rest = strchr (line + 2, ' ');
Packit Service 672cf4
	  if (!rest)
Packit Service 672cf4
	    rest = line + linelen; /* set to an empty string */
Packit Service 672cf4
	  else
Packit Service 672cf4
	    *(rest++) = 0;
Packit Service 672cf4
Packit Service 672cf4
	  r = _gpgme_parse_status (line + 2);
Packit Service 0ef63b
          if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
Packit Service 0ef63b
            {
Packit Service 0ef63b
              /* Note that we call the monitor even if we do
Packit Service 0ef63b
               * not know the status code (r < 0).  */
Packit Service 0ef63b
              err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
Packit Service 0ef63b
                                          line + 2, rest);
Packit Service 0ef63b
            }
Packit Service 0ef63b
          else
Packit Service 0ef63b
            err = 0;
Packit Service 672cf4
Packit Service 0ef63b
	  if (r >= 0 && !err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (gpgsm->status.fnc)
Packit Service 672cf4
                {
Packit Service 672cf4
                  err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
Packit Service 672cf4
                  if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
                    err = 0; /* Drop special error code.  */
Packit Service 672cf4
                }
Packit Service 672cf4
	    }
Packit Service 672cf4
	  else
Packit Service 672cf4
	    fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
Packit Service 0ef63b
          TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
Packit Service 672cf4
		  "fd 0x%x: S line (%s) - final status: %s",
Packit Service 672cf4
                  fd, line+2, err? gpg_strerror (err):"ok");
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 7
Packit Service 672cf4
               && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
Packit Service 672cf4
               && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
Packit Service 672cf4
               && line[6] == 'E'
Packit Service 672cf4
               && (line[7] == '\0' || line[7] == ' '))
Packit Service 672cf4
        {
Packit Service 672cf4
          char *keyword = line+7;
Packit Service 672cf4
Packit Service 672cf4
          while (*keyword == ' ')
Packit Service 672cf4
            keyword++;;
Packit Service 672cf4
          default_inq_cb (gpgsm, keyword);
Packit Service 672cf4
          assuan_write_line (gpgsm->assuan_ctx, "END");
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
    }
Packit Service 672cf4
  while (!err && assuan_pending_line (gpgsm->assuan_ctx));
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 0ef63b
  TRACE_BEG  (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
Packit Service 0ef63b
              "fd=%d, dir %d", iocbd->fd, iocbd->dir);
Packit Service 672cf4
  err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
Packit Service 672cf4
			      iocbd->fd, iocbd->dir,
Packit Service 672cf4
			      handler, iocbd->data, &iocbd->tag);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return TRACE_ERR (err);
Packit Service 672cf4
  if (!iocbd->dir)
Packit Service 672cf4
    /* FIXME Kludge around poll() problem.  */
Packit Service 672cf4
    err = _gpgme_io_set_nonblocking (iocbd->fd);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
start (engine_gpgsm_t gpgsm, const char *command)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  assuan_fd_t afdlist[5];
Packit Service 672cf4
  int fdlist[5];
Packit Service 672cf4
  int nfds;
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 0ef63b
  if (*gpgsm->request_origin)
Packit Service 0ef63b
    {
Packit Service 0ef63b
      char *cmd;
Packit Service 0ef63b
Packit Service 0ef63b
      cmd = _gpgme_strconcat ("OPTION request-origin=",
Packit Service 0ef63b
                              gpgsm->request_origin, NULL);
Packit Service 0ef63b
      if (!cmd)
Packit Service 0ef63b
        return gpg_error_from_syserror ();
Packit Service 0ef63b
      err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL);
Packit Service 0ef63b
      free (cmd);
Packit Service 0ef63b
      if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
Packit Service 0ef63b
        return err;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 672cf4
  /* We need to know the fd used by assuan for reads.  We do this by
Packit Service 672cf4
     using the assumption that the first returned fd from
Packit Service 672cf4
     assuan_get_active_fds() is always this one.  */
Packit Service 672cf4
  nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
Packit Service 672cf4
                                afdlist, DIM (afdlist));
Packit Service 672cf4
  if (nfds < 1)
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
  /* For now... */
Packit Service 672cf4
  for (i = 0; i < nfds; i++)
Packit Service 672cf4
    fdlist[i] = (int) afdlist[i];
Packit Service 672cf4
Packit Service 672cf4
  /* We "duplicate" the file descriptor, so we can close it here (we
Packit Service 672cf4
     can't close fdlist[0], as that is closed by libassuan, and
Packit Service 672cf4
     closing it here might cause libassuan to close some unrelated FD
Packit Service 672cf4
     later).  Alternatively, we could special case status_fd and
Packit Service 672cf4
     register/unregister it manually as needed, but this increases
Packit Service 672cf4
     code duplication and is more complicated as we can not use the
Packit Service 672cf4
     close notifications etc.  A third alternative would be to let
Packit Service 672cf4
     Assuan know that we closed the FD, but that complicates the
Packit Service 672cf4
     Assuan interface.  */
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
Packit Service 672cf4
  if (gpgsm->status_cb.fd < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
Packit Service 672cf4
				  close_notify_handler, gpgsm))
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_io_close (gpgsm->status_cb.fd);
Packit Service 672cf4
      gpgsm->status_cb.fd = -1;
Packit Service 672cf4
      return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
Packit Service 672cf4
  if (!err && gpgsm->input_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
Packit Service 672cf4
  if (!err && gpgsm->output_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
Packit Service 672cf4
  if (!err && gpgsm->message_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
Packit Service 0ef63b
  if (!err && gpgsm->diag_cb.fd != -1)
Packit Service 0ef63b
    err = add_io_cb (gpgsm, &gpgsm->diag_cb, _gpgme_data_inbound_handler);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = assuan_write_line (gpgsm->assuan_ctx, command);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_reset (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  /* IF we have an active connection we must send a reset because we
Packit Service 672cf4
     need to reset the list of signers.  Note that RESET does not
Packit Service 672cf4
     reset OPTION commands. */
Packit Service 672cf4
  return (gpgsm->assuan_ctx
Packit Service 672cf4
          ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
Packit Service 672cf4
          : 0);
Packit Service 672cf4
}
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_decrypt (void *engine,
Packit Service 672cf4
               gpgme_decrypt_flags_t flags,
Packit Service 672cf4
               gpgme_data_t ciph, gpgme_data_t plain,
Packit Service 672cf4
               int export_session_key, const char *override_session_key,
Packit Service 672cf4
               int auto_key_retrieve)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)flags;
Packit Service 672cf4
Packit Service 672cf4
  /* gpgsm is not capable of exporting session keys right now, so we
Packit Service 672cf4
   * will ignore this if requested. */
Packit Service 672cf4
  (void)export_session_key;
Packit Service 672cf4
  (void)override_session_key;
Packit Service 672cf4
Packit Service 672cf4
  /* --auto-key-retrieve is also not supported.  */
Packit Service 672cf4
  (void)auto_key_retrieve;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->input_cb.data = ciph;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
  gpgsm->output_cb.data = plain;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (engine, "DECRYPT");
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_delete (void *engine, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
Packit Service 672cf4
  char *linep = fpr;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  int length = 8;	/* "DELKEYS " */
Packit Service 672cf4
Packit Service 672cf4
  (void)flags;
Packit Service 672cf4
Packit Service 672cf4
  if (!fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  while (*linep)
Packit Service 672cf4
    {
Packit Service 672cf4
      length++;
Packit Service 672cf4
      if (*linep == '%' || *linep == ' ' || *linep == '+')
Packit Service 672cf4
	length += 2;
Packit Service 672cf4
      linep++;
Packit Service 672cf4
    }
Packit Service 672cf4
  length++;
Packit Service 672cf4
Packit Service 672cf4
  line = malloc (length);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  strcpy (line, "DELKEYS ");
Packit Service 672cf4
  linep = &line[8];
Packit Service 672cf4
Packit Service 672cf4
  while (*fpr)
Packit Service 672cf4
    {
Packit Service 672cf4
      switch (*fpr)
Packit Service 672cf4
	{
Packit Service 672cf4
	case '%':
Packit Service 672cf4
	  *(linep++) = '%';
Packit Service 672cf4
	  *(linep++) = '2';
Packit Service 672cf4
	  *(linep++) = '5';
Packit Service 672cf4
	  break;
Packit Service 672cf4
	case ' ':
Packit Service 672cf4
	  *(linep++) = '%';
Packit Service 672cf4
	  *(linep++) = '2';
Packit Service 672cf4
	  *(linep++) = '0';
Packit Service 672cf4
	  break;
Packit Service 672cf4
	case '+':
Packit Service 672cf4
	  *(linep++) = '%';
Packit Service 672cf4
	  *(linep++) = '2';
Packit Service 672cf4
	  *(linep++) = 'B';
Packit Service 672cf4
	  break;
Packit Service 672cf4
	default:
Packit Service 672cf4
	  *(linep++) = *fpr;
Packit Service 672cf4
	  break;
Packit Service 672cf4
	}
Packit Service 672cf4
      fpr++;
Packit Service 672cf4
    }
Packit Service 672cf4
  *linep = '\0';
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, line);
Packit Service 672cf4
  free (line);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  int linelen;
Packit Service 672cf4
  int invalid_recipients = 0;
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  linelen = 10 + 40 + 1;	/* "RECIPIENT " + guess + '\0'.  */
Packit Service 672cf4
  line = malloc (10 + 40 + 1);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  strcpy (line, "RECIPIENT ");
Packit Service 672cf4
  for (i =0; !err && recp[i]; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      char *fpr;
Packit Service 672cf4
      int newlen;
Packit Service 672cf4
Packit Service 672cf4
      if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
Packit Service 672cf4
	{
Packit Service 672cf4
	  invalid_recipients++;
Packit Service 672cf4
	  continue;
Packit Service 672cf4
	}
Packit Service 672cf4
      fpr = recp[i]->subkeys->fpr;
Packit Service 672cf4
Packit Service 672cf4
      newlen = 11 + strlen (fpr);
Packit Service 672cf4
      if (linelen < newlen)
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *newline = realloc (line, newlen);
Packit Service 672cf4
	  if (! newline)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	      free (line);
Packit Service 672cf4
	      return saved_err;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  line = newline;
Packit Service 672cf4
	  linelen = newlen;
Packit Service 672cf4
	}
Packit Service 672cf4
      strcpy (&line[10], fpr);
Packit Service 672cf4
Packit Service 672cf4
      err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
Packit Service 672cf4
					 gpgsm->status.fnc_value);
Packit Service 672cf4
      /* FIXME: This requires more work.  */
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
Packit Service 672cf4
	invalid_recipients++;
Packit Service 672cf4
      else if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  free (line);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  free (line);
Packit Service 672cf4
  return gpg_error (invalid_recipients
Packit Service 672cf4
		    ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 0ef63b
/* Take recipients from the LF delimited STRING and send RECIPIENT
Packit Service 0ef63b
 * commands to gpgsm.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 0ef63b
set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
Packit Service 0ef63b
{
Packit Service 0ef63b
  gpg_error_t err = 0;
Packit Service 0ef63b
  char *line = NULL;
Packit Service 0ef63b
  int ignore = 0;
Packit Service 0ef63b
  int any = 0;
Packit Service 0ef63b
  const char *s;
Packit Service 0ef63b
  int n;
Packit Service 0ef63b
Packit Service 0ef63b
  do
Packit Service 0ef63b
    {
Packit Service 0ef63b
      while (*string == ' ' || *string == '\t')
Packit Service 0ef63b
        string++;
Packit Service 0ef63b
      if (!*string)
Packit Service 0ef63b
        break;
Packit Service 0ef63b
Packit Service 0ef63b
      s = strchr (string, '\n');
Packit Service 0ef63b
      if (s)
Packit Service 0ef63b
        n = s - string;
Packit Service 0ef63b
      else
Packit Service 0ef63b
        n = strlen (string);
Packit Service 0ef63b
      while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
Packit Service 0ef63b
        n--;
Packit Service 0ef63b
Packit Service 0ef63b
      if (!ignore && n == 2 && !memcmp (string, "--", 2))
Packit Service 0ef63b
        ignore = 1;
Packit Service 0ef63b
      else if (!ignore && n > 2 && !memcmp (string, "--", 2))
Packit Service 0ef63b
        err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
Packit Service 0ef63b
      else if (n) /* Not empty - use it.  */
Packit Service 0ef63b
        {
Packit Service 0ef63b
          gpgrt_free (line);
Packit Service 0ef63b
          if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
Packit Service 0ef63b
            err = gpg_error_from_syserror ();
Packit Service 0ef63b
          else
Packit Service 0ef63b
            {
Packit Service 0ef63b
              err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
Packit Service 0ef63b
                                                 gpgsm->status.fnc_value);
Packit Service 0ef63b
              if (!err)
Packit Service 0ef63b
                any = 1;
Packit Service 0ef63b
            }
Packit Service 0ef63b
        }
Packit Service 0ef63b
Packit Service 0ef63b
      string += n + !!s;
Packit Service 0ef63b
    }
Packit Service 0ef63b
  while (!err);
Packit Service 0ef63b
Packit Service 0ef63b
  if (!err && !any)
Packit Service 0ef63b
    err = gpg_error (GPG_ERR_MISSING_KEY);
Packit Service 0ef63b
  gpgrt_free (line);
Packit Service 0ef63b
  return err;
Packit Service 0ef63b
}
Packit Service 0ef63b
Packit Service 0ef63b
Packit Service 0ef63b
static gpgme_error_t
Packit Service 0ef63b
gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
Packit Service 0ef63b
               gpgme_encrypt_flags_t flags,
Packit Service 672cf4
	       gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 0ef63b
  if (!recp && !recpstring) /* Symmetric only */
Packit Service 672cf4
    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 672cf4
Packit Service 0ef63b
  if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
Packit Service 672cf4
    {
Packit Service 672cf4
      err = gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
					 "OPTION no-encrypt-to", NULL, NULL);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->input_cb.data = plain;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  gpgsm->output_cb.data = ciph;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
		      : map_data_enc (gpgsm->output_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 0ef63b
  if (!recp && recpstring)
Packit Service 0ef63b
    err = set_recipients_from_string (gpgsm, recpstring);
Packit Service 0ef63b
  else
Packit Service 0ef63b
    err = set_recipients (gpgsm, recp);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpgsm, "ENCRYPT");
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
Packit Service 672cf4
	      gpgme_data_t keydata, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *cmd;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (!pattern)
Packit Service 672cf4
    pattern = "";
Packit Service 672cf4
Packit Service 672cf4
  cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
Packit Service 672cf4
  if (!cmd)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  strcpy (cmd, "EXPORT ");
Packit Service 672cf4
  if ((mode & GPGME_EXPORT_MODE_SECRET))
Packit Service 672cf4
    {
Packit Service 672cf4
      strcat (cmd, "--secret ");
Packit Service 672cf4
      if ((mode & GPGME_EXPORT_MODE_RAW))
Packit Service 672cf4
        strcat (cmd, "--raw ");
Packit Service 672cf4
      else if ((mode & GPGME_EXPORT_MODE_PKCS12))
Packit Service 672cf4
        strcat (cmd, "--pkcs12 ");
Packit Service 672cf4
    }
Packit Service 672cf4
  strcat (cmd, pattern);
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->output_cb.data = keydata;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
		      : map_data_enc (gpgsm->output_cb.data));
Packit Service cedd58
  if (err) {
Packit Service cedd58
    free (cmd);
Packit Service 672cf4
    return err;
Packit Service cedd58
  }
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, cmd);
Packit Service 672cf4
  free (cmd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
Packit Service 672cf4
		  gpgme_data_t keydata, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
Packit Service 672cf4
  int length = 7 + 9 + 9 + 1;
Packit Service 672cf4
  char *linep;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (pattern && *pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char **pat = pattern;
Packit Service 672cf4
Packit Service 672cf4
      while (*pat)
Packit Service 672cf4
	{
Packit Service 672cf4
	  const char *patlet = *pat;
Packit Service 672cf4
Packit Service 672cf4
	  while (*patlet)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      length++;
Packit Service 672cf4
	      if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
Packit Service 672cf4
		length += 2;
Packit Service 672cf4
	      patlet++;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  pat++;
Packit Service 672cf4
	  length++;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  line = malloc (length);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  strcpy (line, "EXPORT ");
Packit Service 672cf4
  if ((mode & GPGME_EXPORT_MODE_SECRET))
Packit Service 672cf4
    {
Packit Service 672cf4
      strcat (line, "--secret ");
Packit Service 672cf4
      if ((mode & GPGME_EXPORT_MODE_RAW))
Packit Service 672cf4
        strcat (line, "--raw ");
Packit Service 672cf4
      else if ((mode & GPGME_EXPORT_MODE_PKCS12))
Packit Service 672cf4
        strcat (line, "--pkcs12 ");
Packit Service 672cf4
    }
Packit Service 672cf4
  linep = &line[strlen (line)];
Packit Service 672cf4
Packit Service 672cf4
  if (pattern && *pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      while (*pattern)
Packit Service 672cf4
	{
Packit Service 672cf4
	  const char *patlet = *pattern;
Packit Service 672cf4
Packit Service 672cf4
	  while (*patlet)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      switch (*patlet)
Packit Service 672cf4
		{
Packit Service 672cf4
		case '%':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = '5';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		case ' ':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = '0';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		case '+':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = 'B';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		default:
Packit Service 672cf4
		  *(linep++) = *patlet;
Packit Service 672cf4
		  break;
Packit Service 672cf4
		}
Packit Service 672cf4
	      patlet++;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  pattern++;
Packit Service 672cf4
          if (*pattern)
Packit Service 672cf4
            *linep++ = ' ';
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  *linep = '\0';
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->output_cb.data = keydata;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
		      : map_data_enc (gpgsm->output_cb.data));
Packit Service cedd58
  if (err) {
Packit Service cedd58
    free (line);
Packit Service 672cf4
    return err;
Packit Service cedd58
  }
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, line);
Packit Service 672cf4
  free (line);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_genkey (void *engine,
Packit Service 672cf4
              const char *userid, const char *algo,
Packit Service 672cf4
              unsigned long reserved, unsigned long expires,
Packit Service 672cf4
              gpgme_key_t key, unsigned int flags,
Packit Service 672cf4
              gpgme_data_t help_data, unsigned int extraflags,
Packit Service 672cf4
	      gpgme_data_t pubkey, gpgme_data_t seckey)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)reserved;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (help_data)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!pubkey || seckey)
Packit Service 672cf4
        return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
      gpgsm->input_cb.data = help_data;
Packit Service 672cf4
      err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
      gpgsm->output_cb.data = pubkey;
Packit Service 672cf4
      err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
Packit Service 672cf4
                          (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
Packit Service 672cf4
                          : map_data_enc (gpgsm->output_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
      gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
      err = start (gpgsm, "GENKEY");
Packit Service 672cf4
      return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  (void)userid;
Packit Service 672cf4
  (void)algo;
Packit Service 672cf4
  (void)expires;
Packit Service 672cf4
  (void)key;
Packit Service 672cf4
  (void)flags;
Packit Service 672cf4
Packit Service 672cf4
  /* The new interface has not yet been implemented,  */
Packit Service 672cf4
  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  gpgme_data_encoding_t dataenc;
Packit Service 672cf4
  int idx;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (keydata && keyarray)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
Packit Service 672cf4
Packit Service 672cf4
  dataenc = gpgme_data_get_encoding (keydata);
Packit Service 672cf4
Packit Service 672cf4
  if (keyarray)
Packit Service 672cf4
    {
Packit Service 672cf4
      size_t buflen;
Packit Service 672cf4
      char *buffer, *p;
Packit Service 672cf4
Packit Service 672cf4
      /* Fist check whether the engine already features the
Packit Service 672cf4
         --re-import option.  */
Packit Service 672cf4
      err = gpgsm_assuan_simple_command
Packit Service 672cf4
        (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return gpg_error (GPG_ERR_NOT_SUPPORTED);
Packit Service 672cf4
Packit Service 672cf4
      /* Create an internal data object with a list of all
Packit Service 672cf4
         fingerprints.  The data object and its memory (to avoid an
Packit Service 672cf4
         extra copy by gpgme_data_new_from_mem) are stored in two
Packit Service 672cf4
         variables which are released by the close_notify_handler.  */
Packit Service 672cf4
      for (idx=0, buflen=0; keyarray[idx]; idx++)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
Packit Service 672cf4
              && keyarray[idx]->subkeys
Packit Service 672cf4
              && keyarray[idx]->subkeys->fpr
Packit Service 672cf4
              && *keyarray[idx]->subkeys->fpr)
Packit Service 672cf4
            buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
Packit Service 672cf4
        }
Packit Service 0ef63b
      /* Allocate a buffer with extra space for the trailing Nul
Packit Service 672cf4
         introduced by the use of stpcpy.  */
Packit Service 672cf4
      buffer = malloc (buflen+1);
Packit Service 672cf4
      if (!buffer)
Packit Service 672cf4
        return gpg_error_from_syserror ();
Packit Service 672cf4
      for (idx=0, p = buffer; keyarray[idx]; idx++)
Packit Service 672cf4
        {
Packit Service 672cf4
          if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
Packit Service 672cf4
              && keyarray[idx]->subkeys
Packit Service 672cf4
              && keyarray[idx]->subkeys->fpr
Packit Service 672cf4
              && *keyarray[idx]->subkeys->fpr)
Packit Service 672cf4
            p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
Packit Service 672cf4
                                     buffer, buflen, 0);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (buffer);
Packit Service 672cf4
          return err;
Packit Service 672cf4
        }
Packit Service 672cf4
      gpgsm->input_helper_memory = buffer;
Packit Service 672cf4
Packit Service 672cf4
      gpgsm->input_cb.data = gpgsm->input_helper_data;
Packit Service 672cf4
      err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgme_data_release (gpgsm->input_helper_data);
Packit Service 672cf4
          gpgsm->input_helper_data = NULL;
Packit Service 672cf4
          free (gpgsm->input_helper_memory);
Packit Service 672cf4
          gpgsm->input_helper_memory = NULL;
Packit Service 672cf4
          return err;
Packit Service 672cf4
        }
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
      gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
      return start (gpgsm, "IMPORT --re-import");
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (dataenc == GPGME_DATA_ENCODING_URL
Packit Service 672cf4
           || dataenc == GPGME_DATA_ENCODING_URL0
Packit Service 672cf4
           || dataenc == GPGME_DATA_ENCODING_URLESC)
Packit Service 672cf4
    {
Packit Service 672cf4
      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgsm->input_cb.data = keydata;
Packit Service 672cf4
      err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
      gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
      return start (gpgsm, "IMPORT");
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_keylist (void *engine, const char *pattern, int secret_only,
Packit Service 672cf4
	       gpgme_keylist_mode_t mode, int engine_flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  int list_mode = 0;
Packit Service 672cf4
Packit Service 672cf4
  if (mode & GPGME_KEYLIST_MODE_LOCAL)
Packit Service 672cf4
    list_mode |= 1;
Packit Service 672cf4
  if (mode & GPGME_KEYLIST_MODE_EXTERN)
Packit Service 672cf4
    list_mode |= 2;
Packit Service 672cf4
Packit Service 672cf4
  if (!pattern)
Packit Service 672cf4
    pattern = "";
Packit Service 672cf4
Packit Service 672cf4
  /* Hack to make sure that the agent is started.  Only if the agent
Packit Service 672cf4
     has been started an application may connect to the agent via
Packit Service 672cf4
     GPGME_PROTOCOL_ASSUAN - for example to look for smartcards.  We
Packit Service 672cf4
     do this only if a secret key listing has been requested.  In
Packit Service 672cf4
     general this is not needed because a secret key listing starts
Packit Service 672cf4
     the agent.  However on a fresh installation no public keys are
Packit Service 672cf4
     available and thus there is no need for gpgsm to ask the agent
Packit Service 672cf4
     whether a secret key exists for the public key.  */
Packit Service 672cf4
  if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
Packit Service 672cf4
    gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
Packit Service 672cf4
Packit Service 672cf4
  /* Always send list-mode option because RESET does not reset it.  */
Packit Service 672cf4
  if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
Packit Service 672cf4
  gpgrt_free (line);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
  /* Always send key validation because RESET does not reset it.  */
Packit Service 672cf4
Packit Service 672cf4
  /* Use the validation mode if requested.  We don't check for an error
Packit Service 672cf4
     yet because this is a pretty fresh gpgsm features. */
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (mode & GPGME_KEYLIST_MODE_VALIDATE)?
Packit Service 672cf4
                               "OPTION with-validation=1":
Packit Service 672cf4
                               "OPTION with-validation=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
  /* Include the ephemeral keys if requested.  We don't check for an error
Packit Service 672cf4
     yet because this is a pretty fresh gpgsm features. */
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
Packit Service 672cf4
                               "OPTION with-ephemeral-keys=1":
Packit Service 672cf4
                               "OPTION with-ephemeral-keys=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
Packit Service 672cf4
                               "OPTION with-secret=1":
Packit Service 672cf4
                               "OPTION with-secret=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
Packit Service 672cf4
                               "OPTION offline=1":
Packit Service 672cf4
                               "OPTION offline=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
  /* Length is "LISTSECRETKEYS " + p + '\0'.  */
Packit Service 672cf4
  line = malloc (15 + strlen (pattern) + 1);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  if (secret_only)
Packit Service 672cf4
    {
Packit Service 672cf4
      strcpy (line, "LISTSECRETKEYS ");
Packit Service 672cf4
      strcpy (&line[15], pattern);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      strcpy (line, "LISTKEYS ");
Packit Service 672cf4
      strcpy (&line[9], pattern);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, line);
Packit Service 672cf4
  free (line);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
Packit Service 672cf4
		   int reserved, gpgme_keylist_mode_t mode, int engine_flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  /* Length is "LISTSECRETKEYS " + p + '\0'.  */
Packit Service 672cf4
  int length = 15 + 1;
Packit Service 672cf4
  char *linep;
Packit Service 672cf4
  int any_pattern = 0;
Packit Service 672cf4
  int list_mode = 0;
Packit Service 672cf4
Packit Service 672cf4
  if (reserved)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (mode & GPGME_KEYLIST_MODE_LOCAL)
Packit Service 672cf4
    list_mode |= 1;
Packit Service 672cf4
  if (mode & GPGME_KEYLIST_MODE_EXTERN)
Packit Service 672cf4
    list_mode |= 2;
Packit Service 672cf4
Packit Service 672cf4
  /* Always send list-mode option because RESET does not reset it.  */
Packit Service 672cf4
  if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
Packit Service 672cf4
  gpgrt_free (line);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  /* Always send key validation because RESET does not reset it.  */
Packit Service 672cf4
  /* Use the validation mode if required.  We don't check for an error
Packit Service 672cf4
     yet because this is a pretty fresh gpgsm features. */
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (mode & GPGME_KEYLIST_MODE_VALIDATE)?
Packit Service 672cf4
                               "OPTION with-validation=1":
Packit Service 672cf4
                               "OPTION with-validation=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
Packit Service 672cf4
                               "OPTION with-secret=1":
Packit Service 672cf4
                               "OPTION with-secret=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
  gpgsm_assuan_simple_command (gpgsm,
Packit Service 672cf4
                               (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
Packit Service 672cf4
                               "OPTION offline=1":
Packit Service 672cf4
                               "OPTION offline=0" ,
Packit Service 672cf4
                               NULL, NULL);
Packit Service 672cf4
Packit Service 672cf4
  if (pattern && *pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char **pat = pattern;
Packit Service 672cf4
Packit Service 672cf4
      while (*pat)
Packit Service 672cf4
	{
Packit Service 672cf4
	  const char *patlet = *pat;
Packit Service 672cf4
Packit Service 672cf4
	  while (*patlet)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      length++;
Packit Service 672cf4
	      if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
Packit Service 672cf4
		length += 2;
Packit Service 672cf4
	      patlet++;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  pat++;
Packit Service 672cf4
	  length++;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  line = malloc (length);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  if (secret_only)
Packit Service 672cf4
    {
Packit Service 672cf4
      strcpy (line, "LISTSECRETKEYS ");
Packit Service 672cf4
      linep = &line[15];
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      strcpy (line, "LISTKEYS ");
Packit Service 672cf4
      linep = &line[9];
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (pattern && *pattern)
Packit Service 672cf4
    {
Packit Service 672cf4
      while (*pattern)
Packit Service 672cf4
	{
Packit Service 672cf4
	  const char *patlet = *pattern;
Packit Service 672cf4
Packit Service 672cf4
	  while (*patlet)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      switch (*patlet)
Packit Service 672cf4
		{
Packit Service 672cf4
		case '%':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = '5';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		case ' ':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = '0';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		case '+':
Packit Service 672cf4
		  *(linep++) = '%';
Packit Service 672cf4
		  *(linep++) = '2';
Packit Service 672cf4
		  *(linep++) = 'B';
Packit Service 672cf4
		  break;
Packit Service 672cf4
		default:
Packit Service 672cf4
		  *(linep++) = *patlet;
Packit Service 672cf4
		  break;
Packit Service 672cf4
		}
Packit Service 672cf4
	      patlet++;
Packit Service 672cf4
	    }
Packit Service 672cf4
          any_pattern = 1;
Packit Service 672cf4
          *linep++ = ' ';
Packit Service 672cf4
	  pattern++;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  if (any_pattern)
Packit Service 672cf4
    linep--;
Packit Service 672cf4
  *linep = '\0';
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, line);
Packit Service 672cf4
  free (line);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
Packit Service 672cf4
	    gpgme_sig_mode_t mode, int use_armor, int use_textmode,
Packit Service 672cf4
	    int include_certs, gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *assuan_cmd;
Packit Service 672cf4
  int i;
Packit Service 672cf4
  gpgme_key_t key;
Packit Service 672cf4
Packit Service 672cf4
  (void)use_textmode;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: This does not work as RESET does not reset it so we can't
Packit Service 672cf4
     revert back to default.  */
Packit Service 672cf4
  if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* FIXME: Make sure that if we run multiple operations, that we
Packit Service 672cf4
	 can reset any previously set value in case the default is
Packit Service 672cf4
	 requested.  */
Packit Service 672cf4
Packit Service 672cf4
      if (gpgrt_asprintf (&assuan_cmd,
Packit Service 672cf4
                          "OPTION include-certs %i", include_certs) < 0)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
      err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
Packit Service 672cf4
      gpgrt_free (assuan_cmd);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char *s = key->subkeys ? key->subkeys->fpr : NULL;
Packit Service 672cf4
      if (s && strlen (s) < 80)
Packit Service 672cf4
	{
Packit Service 672cf4
          char buf[100];
Packit Service 672cf4
Packit Service 672cf4
          strcpy (stpcpy (buf, "SIGNER "), s);
Packit Service 672cf4
          err = gpgsm_assuan_simple_command (gpgsm, buf,
Packit Service 672cf4
                                             gpgsm->status.fnc,
Packit Service 672cf4
                                             gpgsm->status.fnc_value);
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
        err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      gpgme_key_unref (key);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->input_cb.data = in;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  gpgsm->output_cb.data = out;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
		      : map_data_enc (gpgsm->output_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
Packit Service 672cf4
	       ? "SIGN --detached" : "SIGN");
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
Packit Service 672cf4
	      gpgme_data_t plaintext, gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  (void)ctx;
Packit Service 672cf4
Packit Service 672cf4
  if (!gpgsm)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->input_cb.data = sig;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 0ef63b
  if (!signed_text)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Normal or cleartext signature.  */
Packit Service 0ef63b
      if (plaintext)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          gpgsm->output_cb.data = plaintext;
Packit Service 0ef63b
          err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
Packit Service 0ef63b
        }
Packit Service 0ef63b
      else
Packit Service 0ef63b
        {
Packit Service 0ef63b
          /* No output requested.  */
Packit Service 0ef63b
          gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 0ef63b
        }
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Detached signature.  */
Packit Service 672cf4
      gpgsm->message_cb.data = signed_text;
Packit Service 672cf4
      err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
Packit Service 672cf4
      gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
    }
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (gpgsm, "VERIFY");
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* Send the GETAUDITLOG command.  The result is saved to a gpgme data
Packit Service 672cf4
   object.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
Packit Service 0ef63b
Packit Service 672cf4
  if (!gpgsm || !output)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 0ef63b
  if ((flags & GPGME_AUDITLOG_DIAG) && (flags & GPGME_AUDITLOG_HTML))
Packit Service 0ef63b
    return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
Packit Service 0ef63b
Packit Service 0ef63b
  if ((flags & GPGME_AUDITLOG_DIAG))
Packit Service 0ef63b
    {
Packit Service 0ef63b
      char buf[BUFFER_SIZE];
Packit Service 0ef63b
      int nread;
Packit Service 0ef63b
      int any_written = 0;
Packit Service 0ef63b
      gpgme_data_rewind (gpgsm->diagnostics);
Packit Service 0ef63b
Packit Service 0ef63b
      while ((nread = gpgme_data_read (gpgsm->diagnostics,
Packit Service 0ef63b
                                       buf, BUFFER_SIZE)) > 0)
Packit Service 0ef63b
        {
Packit Service 0ef63b
          any_written = 1;
Packit Service 0ef63b
          if (gpgme_data_write (output, buf, nread) == -1)
Packit Service 0ef63b
            return gpg_error_from_syserror ();
Packit Service 0ef63b
        }
Packit Service 0ef63b
      if (!any_written)
Packit Service 0ef63b
        return gpg_error (GPG_ERR_NO_DATA);
Packit Service 0ef63b
Packit Service 0ef63b
      if (nread == -1)
Packit Service 0ef63b
        return gpg_error_from_syserror ();
Packit Service 0ef63b
Packit Service 0ef63b
      gpgme_data_rewind (output);
Packit Service 0ef63b
      return 0;
Packit Service 0ef63b
    }
Packit Service 0ef63b
Packit Service 0ef63b
  if (!gpgsm->assuan_ctx)
Packit Service 0ef63b
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 0ef63b
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
  gpgsm->output_cb.data = output;
Packit Service 672cf4
  err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
# define CMD  "GETAUDITLOG"
Packit Service 672cf4
#else
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = output;
Packit Service 672cf4
# define CMD  "GETAUDITLOG --data"
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This sets a status callback for monitoring status lines before they
Packit Service 672cf4
 * are passed to a caller set handler.  */
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->status.mon_cb = cb;
Packit Service 672cf4
  gpgsm->status.mon_cb_value = cb_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
Packit Service 672cf4
			  void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->status.fnc = fnc;
Packit Service 672cf4
  gpgsm->status.fnc_value = fnc_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
Packit Service 672cf4
			      void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 672cf4
  gpgsm->colon.fnc = fnc;
Packit Service 672cf4
  gpgsm->colon.fnc_value = fnc_value;
Packit Service 672cf4
  gpgsm->colon.any = 0;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgsm->io_cbs = *io_cbs;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
Packit Service 0ef63b
  TRACE (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
Packit Service 672cf4
          "event %p, type %d, type_data %p",
Packit Service 672cf4
          gpgsm->io_cbs.event, type, type_data);
Packit Service 672cf4
  if (gpgsm->io_cbs.event)
Packit Service 672cf4
    (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_gpgsm_t gpgsm = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
Packit Service 672cf4
  (void)flags;
Packit Service 672cf4
Packit Service 672cf4
  if (!key || !key->subkeys || !key->subkeys->fpr)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_CERT_OBJ);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, OUTPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, INPUT_FD);
Packit Service 672cf4
  gpgsm_clear_fd (gpgsm, MESSAGE_FD);
Packit Service 672cf4
  gpgsm->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (gpgsm, line);
Packit Service 672cf4
  gpgrt_free (line);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct engine_ops _gpgme_engine_ops_gpgsm =
Packit Service 672cf4
  {
Packit Service 672cf4
    /* Static functions.  */
Packit Service 672cf4
    _gpgme_get_default_gpgsm_name,
Packit Service 672cf4
    NULL,
Packit Service 672cf4
    gpgsm_get_version,
Packit Service 672cf4
    gpgsm_get_req_version,
Packit Service 672cf4
    gpgsm_new,
Packit Service 672cf4
Packit Service 672cf4
    /* Member functions.  */
Packit Service 672cf4
    gpgsm_release,
Packit Service 672cf4
#if USE_DESCRIPTOR_PASSING
Packit Service 672cf4
    gpgsm_reset,
Packit Service 672cf4
#else
Packit Service 672cf4
    NULL,			/* reset */
Packit Service 672cf4
#endif
Packit Service 672cf4
    gpgsm_set_status_cb,
Packit Service 672cf4
    gpgsm_set_status_handler,
Packit Service 672cf4
    NULL,		/* set_command_handler */
Packit Service 672cf4
    gpgsm_set_colon_line_handler,
Packit Service 672cf4
    gpgsm_set_locale,
Packit Service 672cf4
    NULL,		/* set_protocol */
Packit Service 0ef63b
    gpgsm_set_engine_flags,
Packit Service 672cf4
    gpgsm_decrypt,
Packit Service 672cf4
    gpgsm_delete,	/* decrypt_verify */
Packit Service 672cf4
    NULL,		/* edit */
Packit Service 672cf4
    gpgsm_encrypt,
Packit Service 672cf4
    NULL,		/* encrypt_sign */
Packit Service 672cf4
    gpgsm_export,
Packit Service 672cf4
    gpgsm_export_ext,
Packit Service 672cf4
    gpgsm_genkey,
Packit Service 672cf4
    gpgsm_import,
Packit Service 672cf4
    gpgsm_keylist,
Packit Service 672cf4
    gpgsm_keylist_ext,
Packit Service 672cf4
    NULL,               /* keylist_data */
Packit Service 672cf4
    NULL,               /* keysign */
Packit Service 672cf4
    NULL,               /* tofu_policy */
Packit Service 672cf4
    gpgsm_sign,
Packit Service 672cf4
    NULL,		/* trustlist */
Packit Service 672cf4
    gpgsm_verify,
Packit Service 672cf4
    gpgsm_getauditlog,
Packit Service 672cf4
    NULL,               /* opassuan_transact */
Packit Service 672cf4
    NULL,		/* conf_load */
Packit Service 672cf4
    NULL,		/* conf_save */
Packit Service 672cf4
    NULL,		/* conf_dir */
Packit Service 672cf4
    NULL,               /* query_swdb */
Packit Service 672cf4
    gpgsm_set_io_cbs,
Packit Service 672cf4
    gpgsm_io_event,
Packit Service 672cf4
    gpgsm_cancel,
Packit Service 672cf4
    NULL,		/* cancel_op */
Packit Service 672cf4
    gpgsm_passwd,
Packit Service 672cf4
    NULL,               /* set_pinentry_mode */
Packit Service 672cf4
    NULL                /* opspawn */
Packit Service 672cf4
  };