Blame src/engine-spawn.c

Packit Service 672cf4
/* engine-spawn.c - Run an arbitrary program
Packit Service 6c01f9
   Copyright (C) 2014 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit Service 6c01f9
*/
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <stdio.h>
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
#ifdef HAVE_UNISTD_H
Packit Service 672cf4
# include <unistd.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#ifdef HAVE_LOCALE_H
Packit Service 672cf4
#include <locale.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "wait.h"
Packit Service 672cf4
#include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
Packit Service 672cf4
#include "priv-io.h"
Packit Service 672cf4
#include "sema.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4
#include "engine-backend.h"
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This type is used to build a list of data sources/sinks.  */
Packit Service 672cf4
struct datalist_s
Packit Service 672cf4
{
Packit Service 672cf4
  struct datalist_s *next;
Packit Service 672cf4
  gpgme_data_t data;  /* The data object. */
Packit Service 672cf4
  int inbound;        /* True if this is used for reading from the peer.  */
Packit Service 672cf4
  int dup_to;         /* The fd used by the peer.  */
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct fd_data_map_s
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_data_t data;
Packit Service 672cf4
  int inbound;  /* True if this is used for reading from the peer. */
Packit Service 672cf4
  int dup_to;   /* Dup the fd to that one.  */
Packit Service 672cf4
  int fd;       /* The fd to use.  */
Packit Service 672cf4
  int peer_fd;  /* The other side of the pipe. */
Packit Service 672cf4
  void *tag;    /* Tag used by the I/O callback.  */
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct engine_spawn
Packit Service 672cf4
{
Packit Service 672cf4
  struct datalist_s *arglist;
Packit Service 672cf4
  struct datalist_s **argtail;
Packit Service 672cf4
Packit Service 672cf4
  struct fd_data_map_s *fd_data_map;
Packit Service 672cf4
Packit Service 672cf4
  struct gpgme_io_cbs io_cbs;
Packit Service 672cf4
};
Packit Service 672cf4
typedef struct engine_spawn *engine_spawn_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void engspawn_io_event (void *engine,
Packit Service 672cf4
                               gpgme_event_io_t type, void *type_data);
Packit Service 672cf4
static gpgme_error_t engspawn_cancel (void *engine);
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static void
Packit Service 672cf4
close_notify_handler (int fd, void *opaque)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = opaque;
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  assert (fd != -1);
Packit Service 672cf4
Packit Service 672cf4
  if (esp->fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      for (i = 0; esp->fd_data_map[i].data; i++)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (esp->fd_data_map[i].fd == fd)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (esp->fd_data_map[i].tag)
Packit Service 672cf4
		(*esp->io_cbs.remove) (esp->fd_data_map[i].tag);
Packit Service 672cf4
	      esp->fd_data_map[i].fd = -1;
Packit Service 672cf4
	      break;
Packit Service 672cf4
            }
Packit Service 672cf4
	  if (esp->fd_data_map[i].peer_fd == fd)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      esp->fd_data_map[i].peer_fd = -1;
Packit Service 672cf4
	      break;
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_data (engine_spawn_t esp, gpgme_data_t data, int dup_to, int inbound)
Packit Service 672cf4
{
Packit Service 672cf4
  struct datalist_s *a;
Packit Service 672cf4
Packit Service 672cf4
  assert (esp);
Packit Service 672cf4
  assert (data);
Packit Service 672cf4
Packit Service 672cf4
  a = malloc (sizeof *a);
Packit Service 672cf4
  if (!a)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  a->next = NULL;
Packit Service 672cf4
  a->data = data;
Packit Service 672cf4
  a->inbound = inbound;
Packit Service 672cf4
  a->dup_to = dup_to;
Packit Service 672cf4
  *esp->argtail = a;
Packit Service 672cf4
  esp->argtail = &a->next;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static void
Packit Service 672cf4
free_fd_data_map (struct fd_data_map_s *fd_data_map)
Packit Service 672cf4
{
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  if (!fd_data_map)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (fd_data_map[i].fd != -1)
Packit Service 672cf4
	_gpgme_io_close (fd_data_map[i].fd);
Packit Service 672cf4
      if (fd_data_map[i].peer_fd != -1)
Packit Service 672cf4
	_gpgme_io_close (fd_data_map[i].peer_fd);
Packit Service 672cf4
      /* Don't release data because this is only a reference.  */
Packit Service 672cf4
    }
Packit Service 672cf4
  free (fd_data_map);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
build_fd_data_map (engine_spawn_t esp)
Packit Service 672cf4
{
Packit Service 672cf4
  struct datalist_s *a;
Packit Service 672cf4
  size_t datac;
Packit Service 672cf4
  int fds[2];
Packit Service 672cf4
Packit Service 672cf4
  for (datac = 0, a = esp->arglist; a; a = a->next)
Packit Service 672cf4
    if (a->data)
Packit Service 672cf4
      datac++;
Packit Service 672cf4
Packit Service 672cf4
  free_fd_data_map (esp->fd_data_map);
Packit Service 672cf4
  esp->fd_data_map = calloc (datac + 1, sizeof *esp->fd_data_map);
Packit Service 672cf4
  if (!esp->fd_data_map)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  for (datac = 0, a = esp->arglist; a; a = a->next)
Packit Service 672cf4
    {
Packit Service 672cf4
      assert (a->data);
Packit Service 672cf4
Packit Service 672cf4
      if (_gpgme_io_pipe (fds, a->inbound ? 1 : 0) == -1)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (esp->fd_data_map);
Packit Service 672cf4
          esp->fd_data_map = NULL;
Packit Service 672cf4
          return gpg_error_from_syserror ();
Packit Service 672cf4
        }
Packit Service 672cf4
      if (_gpgme_io_set_close_notify (fds[0], close_notify_handler, esp)
Packit Service 672cf4
          || _gpgme_io_set_close_notify (fds[1], close_notify_handler, esp))
Packit Service 672cf4
        {
Packit Service 672cf4
          /* FIXME: Need error cleanup.  */
Packit Service 672cf4
          return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
      esp->fd_data_map[datac].inbound = a->inbound;
Packit Service 672cf4
      if (a->inbound)
Packit Service 672cf4
        {
Packit Service 672cf4
          esp->fd_data_map[datac].fd       = fds[0];
Packit Service 672cf4
          esp->fd_data_map[datac].peer_fd  = fds[1];
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        {
Packit Service 672cf4
          esp->fd_data_map[datac].fd       = fds[1];
Packit Service 672cf4
          esp->fd_data_map[datac].peer_fd  = fds[0];
Packit Service 672cf4
        }
Packit Service 672cf4
      esp->fd_data_map[datac].data    = a->data;
Packit Service 672cf4
      esp->fd_data_map[datac].dup_to  = a->dup_to;
Packit Service 672cf4
      datac++;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_io_cb (engine_spawn_t esp, int fd, int dir, gpgme_io_cb_t handler,
Packit Service 672cf4
           void *data, void **tag)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 672cf4
  err = (*esp->io_cbs.add) (esp->io_cbs.add_priv, fd, dir, handler, data, tag);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
  if (!dir) /* Fixme: Kludge around poll() problem.  */
Packit Service 672cf4
    err = _gpgme_io_set_nonblocking (fd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
engspawn_start (engine_spawn_t esp, const char *file, const char *argv[],
Packit Service 672cf4
                unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  int i, n;
Packit Service 672cf4
  int status;
Packit Service 672cf4
  struct spawn_fd_item_s *fd_list;
Packit Service 672cf4
  pid_t pid;
Packit Service 672cf4
  unsigned int spflags;
Packit Service 672cf4
  const char *save_argv0 = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (!esp || !file || !argv || !argv[0])
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  spflags = 0;
Packit Service 672cf4
  if ((flags & GPGME_SPAWN_DETACHED))
Packit Service 672cf4
    spflags |= IOSPAWN_FLAG_DETACHED;
Packit Service 672cf4
  if ((flags & GPGME_SPAWN_ALLOW_SET_FG))
Packit Service 672cf4
    spflags |= IOSPAWN_FLAG_ALLOW_SET_FG;
Packit Service 6c01f9
Packit Service 672cf4
Packit Service 672cf4
  err = build_fd_data_map (esp);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  n = 0;
Packit Service 672cf4
  for (i = 0; esp->fd_data_map[i].data; i++)
Packit Service 672cf4
    n++;
Packit Service 672cf4
  fd_list = calloc (n+1, sizeof *fd_list);
Packit Service 672cf4
  if (!fd_list)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  /* Build the fd list for the child.  */
Packit Service 672cf4
  n = 0;
Packit Service 672cf4
  for (i = 0; esp->fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      fd_list[n].fd = esp->fd_data_map[i].peer_fd;
Packit Service 672cf4
      fd_list[n].dup_to = esp->fd_data_map[i].dup_to;
Packit Service 672cf4
      n++;
Packit Service 672cf4
    }
Packit Service 672cf4
  fd_list[n].fd = -1;
Packit Service 672cf4
  fd_list[n].dup_to = -1;
Packit Service 672cf4
Packit Service 672cf4
  if (argv[0] && !*argv[0])
Packit Service 672cf4
    {
Packit Service 672cf4
      save_argv0 = argv[0];
Packit Service 672cf4
      argv[0] = _gpgme_get_basename (file);
Packit Service 672cf4
    }
Packit Service 672cf4
  status = _gpgme_io_spawn (file, (char * const *)argv, spflags,
Packit Service 672cf4
                            fd_list, NULL, NULL, &pid;;
Packit Service 672cf4
  if (save_argv0)
Packit Service 672cf4
    argv[0] = save_argv0;
Packit Service 672cf4
  free (fd_list);
Packit Service 672cf4
  if (status == -1)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  for (i = 0; esp->fd_data_map[i].data; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = add_io_cb (esp, esp->fd_data_map[i].fd,
Packit Service 672cf4
                       esp->fd_data_map[i].inbound,
Packit Service 672cf4
                       esp->fd_data_map[i].inbound
Packit Service 672cf4
                       ? _gpgme_data_inbound_handler
Packit Service 672cf4
                       : _gpgme_data_outbound_handler,
Packit Service 672cf4
                       esp->fd_data_map[i].data, &esp->fd_data_map[i].tag);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        return err;  /* FIXME: kill the child */
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  engspawn_io_event (esp, GPGME_EVENT_START, NULL);
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
/*
Packit Service 672cf4
    Public functions
Packit Service 672cf4
 */
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
engspawn_get_file_name (void)
Packit Service 672cf4
{
Packit Service 672cf4
  return "/nonexistent";
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static char *
Packit Service 672cf4
engspawn_get_version (const char *file_name)
Packit Service 672cf4
{
Packit Service 672cf4
  (void)file_name;
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
engspawn_get_req_version (void)
Packit Service 672cf4
{
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
engspawn_new (void **engine, const char *file_name, const char *home_dir,
Packit Service 672cf4
              const char *version)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp;
Packit Service 672cf4
Packit Service 672cf4
  (void)file_name;
Packit Service 672cf4
  (void)home_dir;
Packit Service 672cf4
  (void)version;
Packit Service 672cf4
Packit Service 672cf4
  esp = calloc (1, sizeof *esp);
Packit Service 672cf4
  if (!esp)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  esp->argtail = &esp->arglist;
Packit Service 672cf4
  *engine = esp;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
engspawn_release (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!esp)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  engspawn_cancel (engine);
Packit Service 672cf4
Packit Service 672cf4
  while (esp->arglist)
Packit Service 672cf4
    {
Packit Service 672cf4
      struct datalist_s *next = esp->arglist->next;
Packit Service 672cf4
Packit Service 672cf4
      free (esp->arglist);
Packit Service 672cf4
      esp->arglist = next;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  free (esp);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
engspawn_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = engine;
Packit Service 672cf4
Packit Service 672cf4
  esp->io_cbs = *io_cbs;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
engspawn_io_event (void *engine, gpgme_event_io_t type, void *type_data)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = engine;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE3 (DEBUG_ENGINE, "gpgme:engspawn_io_event", esp,
Packit Service 672cf4
          "event %p, type %d, type_data %p",
Packit Service 672cf4
          esp->io_cbs.event, type, type_data);
Packit Service 672cf4
  if (esp->io_cbs.event)
Packit Service 672cf4
    (*esp->io_cbs.event) (esp->io_cbs.event_priv, type, type_data);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
engspawn_cancel (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!esp)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (esp->fd_data_map)
Packit Service 672cf4
    {
Packit Service 672cf4
      free_fd_data_map (esp->fd_data_map);
Packit Service 672cf4
      esp->fd_data_map = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
engspawn_op_spawn (void *engine,
Packit Service 672cf4
                   const char *file, const char *argv[],
Packit Service 672cf4
                   gpgme_data_t datain,
Packit Service 672cf4
                   gpgme_data_t dataout, gpgme_data_t dataerr,
Packit Service 672cf4
                   unsigned int flags)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_spawn_t esp = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
Packit Service 672cf4
  if (datain)
Packit Service 672cf4
    err = add_data (esp, datain, 0, 0);
Packit Service 672cf4
  if (!err && dataout)
Packit Service 672cf4
    err = add_data (esp, dataout, 1, 1);
Packit Service 672cf4
  if (!err && dataerr)
Packit Service 672cf4
    err = add_data (esp, dataerr, 2, 1);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = engspawn_start (esp, file, argv, flags);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
struct engine_ops _gpgme_engine_ops_spawn =
Packit Service 672cf4
  {
Packit Service 672cf4
    /* Static functions.  */
Packit Service 672cf4
    engspawn_get_file_name,
Packit Service 672cf4
    NULL,               /* get_home_dir */
Packit Service 672cf4
    engspawn_get_version,
Packit Service 672cf4
    engspawn_get_req_version,
Packit Service 672cf4
    engspawn_new,
Packit Service 672cf4
Packit Service 672cf4
    /* Member functions.  */
Packit Service 672cf4
    engspawn_release,
Packit Service 672cf4
    NULL,		/* reset */
Packit Service 672cf4
    NULL,               /* set_status_cb */
Packit Service 672cf4
    NULL,		/* set_status_handler */
Packit Service 672cf4
    NULL,		/* set_command_handler */
Packit Service 672cf4
    NULL,		/* set_colon_line_handler */
Packit Service 672cf4
    NULL,		/* set_locale */
Packit Service 672cf4
    NULL,		/* set_protocol */
Packit Service 672cf4
    NULL,		/* decrypt */
Packit Service 672cf4
    NULL,		/* delete */
Packit Service 672cf4
    NULL,		/* edit */
Packit Service 672cf4
    NULL,		/* encrypt */
Packit Service 672cf4
    NULL,		/* encrypt_sign */
Packit Service 672cf4
    NULL,		/* export */
Packit Service 672cf4
    NULL,		/* export_ext */
Packit Service 672cf4
    NULL,		/* genkey */
Packit Service 672cf4
    NULL,		/* import */
Packit Service 672cf4
    NULL,		/* keylist */
Packit Service 672cf4
    NULL,		/* keylist_ext */
Packit Service 672cf4
    NULL,               /* keylist_data */
Packit Service 672cf4
    NULL,               /* keysign */
Packit Service 672cf4
    NULL,               /* tofu_policy */
Packit Service 672cf4
    NULL,		/* sign */
Packit Service 672cf4
    NULL,		/* trustlist */
Packit Service 672cf4
    NULL,		/* verify */
Packit Service 672cf4
    NULL,		/* getauditlog */
Packit Service 672cf4
    NULL,               /* opassuan_transact */
Packit Service 672cf4
    NULL,		/* conf_load */
Packit Service 672cf4
    NULL,		/* conf_save */
Packit Service 672cf4
    NULL,		/* conf_dir */
Packit Service 672cf4
    NULL,               /* query_swdb */
Packit Service 672cf4
    engspawn_set_io_cbs,
Packit Service 672cf4
    engspawn_io_event,	/* io_event */
Packit Service 672cf4
    engspawn_cancel,	/* cancel */
Packit Service 672cf4
    NULL,               /* cancel_op */
Packit Service 672cf4
    NULL,               /* passwd */
Packit Service 672cf4
    NULL,               /* set_pinentry_mode */
Packit Service 672cf4
    engspawn_op_spawn   /* opspawn */
Packit Service 672cf4
  };