Blame src/engine-gpgsm.c

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