Add GPGME_PROTOCOL_SPAWN and gpgme_op_spawn.
* src/gpgme.h.in (GPGME_PROTOCOL_SPAWN): New. (GPGME_SPAWN_DETACHED, GPGME_SPAWN_ALLOW_SET_FG): New. * src/gpgme.c (gpgme_set_protocol): Add new protocol. (gpgme_get_protocol_name): Ditto. * src/spawn.c: New. * src/libgpgme.vers, src/gpgme.def: Add new public functions. * src/engine-spawn.c: New. * src/Makefile.am: Add new files. * src/engine-backend.h (struct engine_ops): Add OPSPAWN. * src/engine.c (engine_ops): Add _gpgme_engine_ops_spawn. (gpgme_get_engine_info): Add Spawn to the list of protocols. (_gpgme_engine_op_spawn): New. * src/gpgme-tool.c (gt_protocol_from_name): Add new protocol. (gt_spawn, cmd_spawn): New.
This commit is contained in:
parent
77931a9a14
commit
4f2d652e60
8
NEWS
8
NEWS
@ -9,9 +9,17 @@ Noteworthy changes in version 1.5.0 (unreleased)
|
|||||||
whatever gpgconf tells as name for the OpenPGP engine. If gpgconf
|
whatever gpgconf tells as name for the OpenPGP engine. If gpgconf
|
||||||
is not found, GPGME looks for an engine named "gpg".
|
is not found, GPGME looks for an engine named "gpg".
|
||||||
|
|
||||||
|
* Add feature to use the gpgme I/O subsystem to run arbitrary
|
||||||
|
commands.
|
||||||
|
|
||||||
* Interface changes relative to the 1.4.3 release:
|
* Interface changes relative to the 1.4.3 release:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
gpgme_get_dirinfo NEW.
|
gpgme_get_dirinfo NEW.
|
||||||
|
gpgme_op_spawn_start NEW.
|
||||||
|
gpgme_op_spawn NEW.
|
||||||
|
GPGME_PROTOCOL_SPAWN NEW.
|
||||||
|
GPGME_SPAWN_DETACHED NEW.
|
||||||
|
GPGME_SPAWN_ALLOW_SET_FG NEW.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 1.4.3 (2013-08-12)
|
Noteworthy changes in version 1.4.3 (2013-08-12)
|
||||||
|
@ -113,7 +113,6 @@ Indices
|
|||||||
* Concept Index:: Index of concepts and programs.
|
* Concept Index:: Index of concepts and programs.
|
||||||
* Function and Data Index:: Index of functions, variables and data types.
|
* Function and Data Index:: Index of functions, variables and data types.
|
||||||
|
|
||||||
|
|
||||||
@detailmenu
|
@detailmenu
|
||||||
--- The Detailed Node Listing ---
|
--- The Detailed Node Listing ---
|
||||||
|
|
||||||
@ -170,6 +169,7 @@ Manipulating Data Buffers
|
|||||||
|
|
||||||
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
||||||
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
||||||
|
* Data Buffer Convenience:: Convenience function for data buffers.
|
||||||
|
|
||||||
Contexts
|
Contexts
|
||||||
|
|
||||||
@ -180,6 +180,7 @@ Contexts
|
|||||||
* Key Management:: Managing keys with @acronym{GPGME}.
|
* Key Management:: Managing keys with @acronym{GPGME}.
|
||||||
* Trust Item Management:: Managing trust items with @acronym{GPGME}.
|
* Trust Item Management:: Managing trust items with @acronym{GPGME}.
|
||||||
* Crypto Operations:: Using a context for cryptography.
|
* Crypto Operations:: Using a context for cryptography.
|
||||||
|
* Miscellaneous:: Miscellaneous operations.
|
||||||
* Run Control:: Controlling how operations are run.
|
* Run Control:: Controlling how operations are run.
|
||||||
|
|
||||||
Context Attributes
|
Context Attributes
|
||||||
@ -204,6 +205,7 @@ Key Management
|
|||||||
* Exporting Keys:: Retrieving key data from the key ring.
|
* Exporting Keys:: Retrieving key data from the key ring.
|
||||||
* Importing Keys:: Adding keys to the key ring.
|
* Importing Keys:: Adding keys to the key ring.
|
||||||
* Deleting Keys:: Removing keys from the key ring.
|
* Deleting Keys:: Removing keys from the key ring.
|
||||||
|
* Changing Passphrases:: Change the passphrase of a key.
|
||||||
* Advanced Key Editing:: Advanced key edit operation.
|
* Advanced Key Editing:: Advanced key edit operation.
|
||||||
|
|
||||||
Trust Item Management
|
Trust Item Management
|
||||||
@ -230,6 +232,10 @@ Encrypt
|
|||||||
|
|
||||||
* Encrypting a Plaintext:: How to encrypt a plaintext.
|
* Encrypting a Plaintext:: How to encrypt a plaintext.
|
||||||
|
|
||||||
|
Miscellaneous
|
||||||
|
|
||||||
|
* Running other Programs:: Running other Programs
|
||||||
|
|
||||||
Run Control
|
Run Control
|
||||||
|
|
||||||
* Waiting For Completion:: Waiting until an operation is completed.
|
* Waiting For Completion:: Waiting until an operation is completed.
|
||||||
@ -850,6 +856,9 @@ Under development. Please ask on @email{gnupg-devel@@gnupg.org} for help.
|
|||||||
@item GPGME_PROTOCOL_UISERVER
|
@item GPGME_PROTOCOL_UISERVER
|
||||||
Under development. Please ask on @email{gnupg-devel@@gnupg.org} for help.
|
Under development. Please ask on @email{gnupg-devel@@gnupg.org} for help.
|
||||||
|
|
||||||
|
@item GPGME_PROTOCOL_SPAWN
|
||||||
|
Special protocol for use with @code{gpgme_op_spawn}.
|
||||||
|
|
||||||
@item GPGME_PROTOCOL_UNKNOWN
|
@item GPGME_PROTOCOL_UNKNOWN
|
||||||
Reserved for future extension. You may use this to indicate that the
|
Reserved for future extension. You may use this to indicate that the
|
||||||
used protocol is not known to the application. Currently,
|
used protocol is not known to the application. Currently,
|
||||||
@ -1946,7 +1955,7 @@ be used to manipulate both.
|
|||||||
@menu
|
@menu
|
||||||
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
* Data Buffer I/O Operations:: I/O operations on data buffers.
|
||||||
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
* Data Buffer Meta-Data:: Meta-data manipulation of data buffers.
|
||||||
* Data Buffer Convenience:: Convenience fucntion for data buffers.
|
* Data Buffer Convenience:: Convenience function for data buffers.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
@ -2187,6 +2196,7 @@ cryptographic operations.
|
|||||||
* Key Management:: Managing keys with @acronym{GPGME}.
|
* Key Management:: Managing keys with @acronym{GPGME}.
|
||||||
* Trust Item Management:: Managing trust items with @acronym{GPGME}.
|
* Trust Item Management:: Managing trust items with @acronym{GPGME}.
|
||||||
* Crypto Operations:: Using a context for cryptography.
|
* Crypto Operations:: Using a context for cryptography.
|
||||||
|
* Miscellaneous:: Miscellaneous operations
|
||||||
* Run Control:: Controlling how operations are run.
|
* Run Control:: Controlling how operations are run.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@ -2261,7 +2271,7 @@ started. In fact, these references are accessed through the
|
|||||||
* Crypto Engine:: Configuring the crypto engine.
|
* Crypto Engine:: Configuring the crypto engine.
|
||||||
* ASCII Armor:: Requesting @acronym{ASCII} armored output.
|
* ASCII Armor:: Requesting @acronym{ASCII} armored output.
|
||||||
* Text Mode:: Choosing canonical text mode.
|
* Text Mode:: Choosing canonical text mode.
|
||||||
* Included Certificates:: Including a number of certificates.
|
* Included Certificates:: Including a number of certificates.
|
||||||
* Key Listing Mode:: Selecting key listing mode.
|
* Key Listing Mode:: Selecting key listing mode.
|
||||||
* Passphrase Callback:: Getting the passphrase from the user.
|
* Passphrase Callback:: Getting the passphrase from the user.
|
||||||
* Progress Meter Callback:: Being informed about the progress.
|
* Progress Meter Callback:: Being informed about the progress.
|
||||||
@ -5222,6 +5232,66 @@ pointer.
|
|||||||
@end deftypefun
|
@end deftypefun
|
||||||
|
|
||||||
|
|
||||||
|
@node Miscellaneous
|
||||||
|
@section Miscellaneous operations
|
||||||
|
|
||||||
|
Here are some support functions which are sometimes useful.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Running other Programs:: Running other Programs
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
|
@node Running other Programs
|
||||||
|
@subsection Running other Programs
|
||||||
|
|
||||||
|
GPGME features an internal subsystem to run the actual backend
|
||||||
|
engines. Along with data abstraction object this subsystem can be
|
||||||
|
used to run arbitrary simple programs which even need not be related
|
||||||
|
to cryptographic features. It may for example be used to run tools
|
||||||
|
which are part of the GnuPG system but are not directly accessible
|
||||||
|
with the GPGME API.
|
||||||
|
|
||||||
|
|
||||||
|
@deftypefun gpgme_error_t gpgme_op_spawn
|
||||||
|
(@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{file}}, @
|
||||||
|
@w{const char *@var{argv}[]}, @w{gpgme_data_t @var{datain}}, @
|
||||||
|
@w{gpgme_data_t @var{dataout}}, @w{gpgme_data_t @var{dataerr}}, @
|
||||||
|
@w{unsigned int @var{flags}})
|
||||||
|
|
||||||
|
The function @code{gpgme_op_spawn} runs the program @var{file} with
|
||||||
|
the arguments taken from the NULL terminated array @var{argv}. If no
|
||||||
|
arguments are required @var{argv} may be given as @code{NULL} (in that
|
||||||
|
case GPGME uses the basename of @var{file} for @code{argv[0]}). The
|
||||||
|
file descriptors @code{stdin}, @code{stdout}, and @code{stderr} are
|
||||||
|
connected to the data objects @var{datain}, @var{dataout}, and
|
||||||
|
@var{dataerr}. If NULL is passed for one of these data objects the
|
||||||
|
corresponding file descriptor is connected to @file{/dev/null}.
|
||||||
|
|
||||||
|
The value in @var{flags} is a bitwise-or combination of one or
|
||||||
|
multiple of the following bit values:
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item GPGME_SPAWN_DETACHED
|
||||||
|
Under Windows this flag inhibits the allocation of a new console for
|
||||||
|
the program. This is useful for a GUI application which needs to call
|
||||||
|
a command line helper tool.
|
||||||
|
@item GPGME_SPAWN_ALLOW_SET_FG
|
||||||
|
Under Windows this flag allows the called program to put itself into
|
||||||
|
the foreground.
|
||||||
|
@end table
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
@deftypefun gpgme_error_t gpgme_op_spawn_start
|
||||||
|
(@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{file}}, @
|
||||||
|
@w{const char *@var{argv}[]}, @w{gpgme_data_t @var{datain}}, @
|
||||||
|
@w{gpgme_data_t @var{dataout}}, @w{gpgme_data_t @var{dataerr}}, @
|
||||||
|
@w{unsigned int @var{flags}})
|
||||||
|
|
||||||
|
This is the asynchronous variant of @code{gpgme_op_spawn}.
|
||||||
|
@end deftypefun
|
||||||
|
|
||||||
|
|
||||||
@node Run Control
|
@node Run Control
|
||||||
@section Run Control
|
@section Run Control
|
||||||
@cindex run control
|
@cindex run control
|
||||||
|
@ -89,11 +89,12 @@ main_sources = \
|
|||||||
sign.c passphrase.c progress.c \
|
sign.c passphrase.c progress.c \
|
||||||
key.c keylist.c trust-item.c trustlist.c \
|
key.c keylist.c trust-item.c trustlist.c \
|
||||||
import.c export.c genkey.c delete.c edit.c getauditlog.c \
|
import.c export.c genkey.c delete.c edit.c getauditlog.c \
|
||||||
opassuan.c passwd.c assuan-support.c \
|
opassuan.c passwd.c spawn.c assuan-support.c \
|
||||||
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
|
engine.h engine-backend.h engine.c engine-gpg.c status-table.c \
|
||||||
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
|
engine-gpgsm.c engine-assuan.c engine-gpgconf.c \
|
||||||
$(uiserver_components) \
|
$(uiserver_components) \
|
||||||
engine-g13.c vfs-mount.c vfs-create.c \
|
engine-g13.c vfs-mount.c vfs-create.c \
|
||||||
|
engine-spawn.c \
|
||||||
gpgconf.c \
|
gpgconf.c \
|
||||||
sema.h priv-io.h $(system_components) sys-util.h dirinfo.c \
|
sema.h priv-io.h $(system_components) sys-util.h dirinfo.c \
|
||||||
debug.c debug.h gpgme.c version.c error.c
|
debug.c debug.h gpgme.c version.c error.c
|
||||||
|
@ -783,5 +783,6 @@ struct engine_ops _gpgme_engine_ops_assuan =
|
|||||||
llass_cancel,
|
llass_cancel,
|
||||||
llass_cancel_op,
|
llass_cancel_op,
|
||||||
NULL, /* passwd */
|
NULL, /* passwd */
|
||||||
NULL /* set_pinentry_mode */
|
NULL, /* set_pinentry_mode */
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
@ -124,6 +124,14 @@ struct engine_ops
|
|||||||
|
|
||||||
/* Set the pinentry mode. */
|
/* Set the pinentry mode. */
|
||||||
gpgme_error_t (*set_pinentry_mode) (void *engine, gpgme_pinentry_mode_t mode);
|
gpgme_error_t (*set_pinentry_mode) (void *engine, gpgme_pinentry_mode_t mode);
|
||||||
|
|
||||||
|
/* The spawn command. */
|
||||||
|
gpgme_error_t (*opspawn) (void * engine,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout,
|
||||||
|
gpgme_data_t dataerr);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -135,6 +143,7 @@ extern struct engine_ops _gpgme_engine_ops_g13; /* Crypto VFS. */
|
|||||||
#ifdef ENABLE_UISERVER
|
#ifdef ENABLE_UISERVER
|
||||||
extern struct engine_ops _gpgme_engine_ops_uiserver;
|
extern struct engine_ops _gpgme_engine_ops_uiserver;
|
||||||
#endif
|
#endif
|
||||||
|
extern struct engine_ops _gpgme_engine_ops_spawn; /* Spawn engine. */
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes for extra functions in engine-gpgconf.c */
|
/* Prototypes for extra functions in engine-gpgconf.c */
|
||||||
|
@ -799,5 +799,6 @@ struct engine_ops _gpgme_engine_ops_g13 =
|
|||||||
g13_cancel,
|
g13_cancel,
|
||||||
g13_cancel_op,
|
g13_cancel_op,
|
||||||
NULL, /* passwd */
|
NULL, /* passwd */
|
||||||
NULL /* set_pinentry_mode */
|
NULL, /* set_pinentry_mode */
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
@ -2445,5 +2445,6 @@ struct engine_ops _gpgme_engine_ops_gpg =
|
|||||||
gpg_cancel,
|
gpg_cancel,
|
||||||
NULL, /* cancel_op */
|
NULL, /* cancel_op */
|
||||||
gpg_passwd,
|
gpg_passwd,
|
||||||
gpg_set_pinentry_mode
|
gpg_set_pinentry_mode,
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
@ -963,5 +963,6 @@ struct engine_ops _gpgme_engine_ops_gpgconf =
|
|||||||
NULL, /* cancel */
|
NULL, /* cancel */
|
||||||
NULL, /* cancel_op */
|
NULL, /* cancel_op */
|
||||||
NULL, /* passwd */
|
NULL, /* passwd */
|
||||||
NULL /* set_pinentry_mode */
|
NULL, /* set_pinentry_mode */
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
@ -1988,5 +1988,6 @@ struct engine_ops _gpgme_engine_ops_gpgsm =
|
|||||||
gpgsm_cancel,
|
gpgsm_cancel,
|
||||||
NULL, /* cancel_op */
|
NULL, /* cancel_op */
|
||||||
gpgsm_passwd,
|
gpgsm_passwd,
|
||||||
NULL /* set_pinentry_mode */
|
NULL, /* set_pinentry_mode */
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
467
src/engine-spawn.c
Normal file
467
src/engine-spawn.c
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
/* engine-spawn.c - Run an arbitrary program
|
||||||
|
Copyright (C) 2014 g10 Code GmbH
|
||||||
|
|
||||||
|
This file is part of GPGME.
|
||||||
|
|
||||||
|
GPGME is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
GPGME is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LOCALE_H
|
||||||
|
#include <locale.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "gpgme.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ops.h"
|
||||||
|
#include "wait.h"
|
||||||
|
#include "context.h" /*temp hack until we have GpmeData methods to do I/O */
|
||||||
|
#include "priv-io.h"
|
||||||
|
#include "sema.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "engine-backend.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* This type is used to build a list of data sources/sinks. */
|
||||||
|
struct datalist_s
|
||||||
|
{
|
||||||
|
struct datalist_s *next;
|
||||||
|
gpgme_data_t data; /* The data object. */
|
||||||
|
int inbound; /* True if this is used for reading from the peer. */
|
||||||
|
int dup_to; /* The fd used by the peer. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct fd_data_map_s
|
||||||
|
{
|
||||||
|
gpgme_data_t data;
|
||||||
|
int inbound; /* True if this is used for reading from the peer. */
|
||||||
|
int dup_to; /* Dup the fd to that one. */
|
||||||
|
int fd; /* The fd to use. */
|
||||||
|
int peer_fd; /* The other side of the pipe. */
|
||||||
|
void *tag; /* Tag used by the I/O callback. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct engine_spawn
|
||||||
|
{
|
||||||
|
struct datalist_s *arglist;
|
||||||
|
struct datalist_s **argtail;
|
||||||
|
|
||||||
|
struct fd_data_map_s *fd_data_map;
|
||||||
|
|
||||||
|
struct gpgme_io_cbs io_cbs;
|
||||||
|
};
|
||||||
|
typedef struct engine_spawn *engine_spawn_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void engspawn_io_event (void *engine,
|
||||||
|
gpgme_event_io_t type, void *type_data);
|
||||||
|
static gpgme_error_t engspawn_cancel (void *engine);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
close_notify_handler (int fd, void *opaque)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = opaque;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert (fd != -1);
|
||||||
|
|
||||||
|
if (esp->fd_data_map)
|
||||||
|
{
|
||||||
|
for (i = 0; esp->fd_data_map[i].data; i++)
|
||||||
|
{
|
||||||
|
if (esp->fd_data_map[i].fd == fd)
|
||||||
|
{
|
||||||
|
if (esp->fd_data_map[i].tag)
|
||||||
|
(*esp->io_cbs.remove) (esp->fd_data_map[i].tag);
|
||||||
|
esp->fd_data_map[i].fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (esp->fd_data_map[i].peer_fd == fd)
|
||||||
|
{
|
||||||
|
esp->fd_data_map[i].peer_fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
add_data (engine_spawn_t esp, gpgme_data_t data, int dup_to, int inbound)
|
||||||
|
{
|
||||||
|
struct datalist_s *a;
|
||||||
|
|
||||||
|
assert (esp);
|
||||||
|
assert (data);
|
||||||
|
|
||||||
|
a = malloc (sizeof *a - 1);
|
||||||
|
if (!a)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
a->next = NULL;
|
||||||
|
a->data = data;
|
||||||
|
a->inbound = inbound;
|
||||||
|
a->dup_to = dup_to;
|
||||||
|
*esp->argtail = a;
|
||||||
|
esp->argtail = &a->next;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_fd_data_map (struct fd_data_map_s *fd_data_map)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!fd_data_map)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; fd_data_map[i].data; i++)
|
||||||
|
{
|
||||||
|
if (fd_data_map[i].fd != -1)
|
||||||
|
_gpgme_io_close (fd_data_map[i].fd);
|
||||||
|
if (fd_data_map[i].peer_fd != -1)
|
||||||
|
_gpgme_io_close (fd_data_map[i].peer_fd);
|
||||||
|
/* Don't release data because this is only a reference. */
|
||||||
|
}
|
||||||
|
free (fd_data_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
build_fd_data_map (engine_spawn_t esp)
|
||||||
|
{
|
||||||
|
struct datalist_s *a;
|
||||||
|
size_t datac;
|
||||||
|
int fds[2];
|
||||||
|
|
||||||
|
for (datac = 0, a = esp->arglist; a; a = a->next)
|
||||||
|
if (a->data)
|
||||||
|
datac++;
|
||||||
|
|
||||||
|
free_fd_data_map (esp->fd_data_map);
|
||||||
|
esp->fd_data_map = calloc (datac + 1, sizeof *esp->fd_data_map);
|
||||||
|
if (!esp->fd_data_map)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
for (datac = 0, a = esp->arglist; a; a = a->next)
|
||||||
|
{
|
||||||
|
assert (a->data);
|
||||||
|
|
||||||
|
if (_gpgme_io_pipe (fds, a->inbound ? 1 : 0) == -1)
|
||||||
|
{
|
||||||
|
free (esp->fd_data_map);
|
||||||
|
esp->fd_data_map = NULL;
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
if (_gpgme_io_set_close_notify (fds[0], close_notify_handler, esp)
|
||||||
|
|| _gpgme_io_set_close_notify (fds[1], close_notify_handler, esp))
|
||||||
|
{
|
||||||
|
/* FIXME: Need error cleanup. */
|
||||||
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp->fd_data_map[datac].inbound = a->inbound;
|
||||||
|
if (a->inbound)
|
||||||
|
{
|
||||||
|
esp->fd_data_map[datac].fd = fds[0];
|
||||||
|
esp->fd_data_map[datac].peer_fd = fds[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
esp->fd_data_map[datac].fd = fds[1];
|
||||||
|
esp->fd_data_map[datac].peer_fd = fds[0];
|
||||||
|
}
|
||||||
|
esp->fd_data_map[datac].data = a->data;
|
||||||
|
esp->fd_data_map[datac].dup_to = a->dup_to;
|
||||||
|
datac++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
add_io_cb (engine_spawn_t esp, int fd, int dir, gpgme_io_cb_t handler,
|
||||||
|
void *data, void **tag)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
|
||||||
|
err = (*esp->io_cbs.add) (esp->io_cbs.add_priv, fd, dir, handler, data, tag);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (!dir) /* Fixme: Kludge around poll() problem. */
|
||||||
|
err = _gpgme_io_set_nonblocking (fd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
engspawn_start (engine_spawn_t esp, const char *file, const char *argv[],
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
int i, n;
|
||||||
|
int status;
|
||||||
|
struct spawn_fd_item_s *fd_list;
|
||||||
|
pid_t pid;
|
||||||
|
unsigned int spflags;
|
||||||
|
|
||||||
|
if (!esp || !file || !argv || !argv[0])
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
spflags = 0;
|
||||||
|
if ((flags & GPGME_SPAWN_DETACHED))
|
||||||
|
spflags |= IOSPAWN_FLAG_DETACHED;
|
||||||
|
if ((flags & GPGME_SPAWN_ALLOW_SET_FG))
|
||||||
|
spflags |= IOSPAWN_FLAG_ALLOW_SET_FG;
|
||||||
|
|
||||||
|
|
||||||
|
err = build_fd_data_map (esp);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for (i = 0; esp->fd_data_map[i].data; i++)
|
||||||
|
n++;
|
||||||
|
fd_list = calloc (n, sizeof *fd_list);
|
||||||
|
if (!fd_list)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
/* Build the fd list for the child. */
|
||||||
|
n = 0;
|
||||||
|
for (i = 0; esp->fd_data_map[i].data; i++)
|
||||||
|
{
|
||||||
|
fd_list[n].fd = esp->fd_data_map[i].peer_fd;
|
||||||
|
fd_list[n].dup_to = esp->fd_data_map[i].dup_to;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
fd_list[n].fd = -1;
|
||||||
|
fd_list[n].dup_to = -1;
|
||||||
|
|
||||||
|
status = _gpgme_io_spawn (file, (char * const *)argv, spflags,
|
||||||
|
fd_list, NULL, NULL, &pid);
|
||||||
|
free (fd_list);
|
||||||
|
if (status == -1)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
for (i = 0; esp->fd_data_map[i].data; i++)
|
||||||
|
{
|
||||||
|
err = add_io_cb (esp, esp->fd_data_map[i].fd,
|
||||||
|
esp->fd_data_map[i].inbound,
|
||||||
|
esp->fd_data_map[i].inbound
|
||||||
|
? _gpgme_data_inbound_handler
|
||||||
|
: _gpgme_data_outbound_handler,
|
||||||
|
esp->fd_data_map[i].data, &esp->fd_data_map[i].tag);
|
||||||
|
if (err)
|
||||||
|
return err; /* FIXME: kill the child */
|
||||||
|
}
|
||||||
|
|
||||||
|
engspawn_io_event (esp, GPGME_EVENT_START, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Public functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
engspawn_get_file_name (void)
|
||||||
|
{
|
||||||
|
return "/nonexistent";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
engspawn_get_version (const char *file_name)
|
||||||
|
{
|
||||||
|
(void)file_name;
|
||||||
|
return strdup ("1.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
engspawn_get_req_version (void)
|
||||||
|
{
|
||||||
|
return "1.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
engspawn_new (void **engine, const char *file_name, const char *home_dir)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp;
|
||||||
|
|
||||||
|
(void)file_name;
|
||||||
|
(void)home_dir;
|
||||||
|
|
||||||
|
esp = calloc (1, sizeof *esp);
|
||||||
|
if (!esp)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
esp->argtail = &esp->arglist;
|
||||||
|
*engine = esp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
engspawn_release (void *engine)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = engine;
|
||||||
|
|
||||||
|
if (!esp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
engspawn_cancel (engine);
|
||||||
|
|
||||||
|
while (esp->arglist)
|
||||||
|
{
|
||||||
|
struct datalist_s *next = esp->arglist->next;
|
||||||
|
|
||||||
|
if (esp->arglist)
|
||||||
|
free (esp->arglist);
|
||||||
|
esp->arglist = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free (esp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
engspawn_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = engine;
|
||||||
|
|
||||||
|
esp->io_cbs = *io_cbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
engspawn_io_event (void *engine, gpgme_event_io_t type, void *type_data)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = engine;
|
||||||
|
|
||||||
|
TRACE3 (DEBUG_ENGINE, "gpgme:engspawn_io_event", esp,
|
||||||
|
"event %p, type %d, type_data %p",
|
||||||
|
esp->io_cbs.event, type, type_data);
|
||||||
|
if (esp->io_cbs.event)
|
||||||
|
(*esp->io_cbs.event) (esp->io_cbs.event_priv, type, type_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
engspawn_cancel (void *engine)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = engine;
|
||||||
|
|
||||||
|
if (!esp)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
if (esp->fd_data_map)
|
||||||
|
{
|
||||||
|
free_fd_data_map (esp->fd_data_map);
|
||||||
|
esp->fd_data_map = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
engspawn_op_spawn (void *engine,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
engine_spawn_t esp = engine;
|
||||||
|
gpgme_error_t err = 0;
|
||||||
|
|
||||||
|
if (datain)
|
||||||
|
err = add_data (esp, datain, 0, 0);
|
||||||
|
if (!err && dataout)
|
||||||
|
err = add_data (esp, dataout, 1, 1);
|
||||||
|
if (!err && dataerr)
|
||||||
|
err = add_data (esp, dataerr, 2, 1);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
err = engspawn_start (esp, file, argv, flags);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct engine_ops _gpgme_engine_ops_spawn =
|
||||||
|
{
|
||||||
|
/* Static functions. */
|
||||||
|
engspawn_get_file_name,
|
||||||
|
NULL, /* get_home_dir */
|
||||||
|
engspawn_get_version,
|
||||||
|
engspawn_get_req_version,
|
||||||
|
engspawn_new,
|
||||||
|
|
||||||
|
/* Member functions. */
|
||||||
|
engspawn_release,
|
||||||
|
NULL, /* reset */
|
||||||
|
NULL, /* set_status_handler */
|
||||||
|
NULL, /* set_command_handler */
|
||||||
|
NULL, /* set_colon_line_handler */
|
||||||
|
NULL, /* set_locale */
|
||||||
|
NULL, /* set_protocol */
|
||||||
|
NULL, /* decrypt */
|
||||||
|
NULL, /* decrypt_verify */
|
||||||
|
NULL, /* delete */
|
||||||
|
NULL, /* edit */
|
||||||
|
NULL, /* encrypt */
|
||||||
|
NULL, /* encrypt_sign */
|
||||||
|
NULL, /* export */
|
||||||
|
NULL, /* export_ext */
|
||||||
|
NULL, /* genkey */
|
||||||
|
NULL, /* import */
|
||||||
|
NULL, /* keylist */
|
||||||
|
NULL, /* keylist_ext */
|
||||||
|
NULL, /* sign */
|
||||||
|
NULL, /* trustlist */
|
||||||
|
NULL, /* verify */
|
||||||
|
NULL, /* getauditlog */
|
||||||
|
NULL, /* opassuan_transact */
|
||||||
|
NULL, /* conf_load */
|
||||||
|
NULL, /* conf_save */
|
||||||
|
engspawn_set_io_cbs,
|
||||||
|
engspawn_io_event, /* io_event */
|
||||||
|
engspawn_cancel, /* cancel */
|
||||||
|
NULL, /* cancel_op */
|
||||||
|
NULL, /* passwd */
|
||||||
|
NULL, /* set_pinentry_mode */
|
||||||
|
engspawn_op_spawn /* opspawn */
|
||||||
|
};
|
@ -1340,5 +1340,6 @@ struct engine_ops _gpgme_engine_ops_uiserver =
|
|||||||
uiserver_cancel,
|
uiserver_cancel,
|
||||||
NULL, /* cancel_op */
|
NULL, /* cancel_op */
|
||||||
NULL, /* passwd */
|
NULL, /* passwd */
|
||||||
NULL /* set_pinentry_mode */
|
NULL, /* set_pinentry_mode */
|
||||||
|
NULL /* opspawn */
|
||||||
};
|
};
|
||||||
|
25
src/engine.c
25
src/engine.c
@ -51,10 +51,11 @@ static struct engine_ops *engine_ops[] =
|
|||||||
&_gpgme_engine_ops_assuan, /* Low-Level Assuan. */
|
&_gpgme_engine_ops_assuan, /* Low-Level Assuan. */
|
||||||
&_gpgme_engine_ops_g13, /* Crypto VFS. */
|
&_gpgme_engine_ops_g13, /* Crypto VFS. */
|
||||||
#ifdef ENABLE_UISERVER
|
#ifdef ENABLE_UISERVER
|
||||||
&_gpgme_engine_ops_uiserver /* UI-Server. */
|
&_gpgme_engine_ops_uiserver, /* UI-Server. */
|
||||||
#else
|
#else
|
||||||
NULL
|
NULL,
|
||||||
#endif
|
#endif
|
||||||
|
&_gpgme_engine_ops_spawn
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -193,7 +194,8 @@ gpgme_get_engine_info (gpgme_engine_info_t *info)
|
|||||||
GPGME_PROTOCOL_GPGCONF,
|
GPGME_PROTOCOL_GPGCONF,
|
||||||
GPGME_PROTOCOL_ASSUAN,
|
GPGME_PROTOCOL_ASSUAN,
|
||||||
GPGME_PROTOCOL_G13,
|
GPGME_PROTOCOL_G13,
|
||||||
GPGME_PROTOCOL_UISERVER };
|
GPGME_PROTOCOL_UISERVER,
|
||||||
|
GPGME_PROTOCOL_SPAWN };
|
||||||
unsigned int proto;
|
unsigned int proto;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
@ -936,3 +938,20 @@ _gpgme_engine_set_pinentry_mode (engine_t engine, gpgme_pinentry_mode_t mode)
|
|||||||
|
|
||||||
return (*engine->ops->set_pinentry_mode) (engine->engine, mode);
|
return (*engine->ops->set_pinentry_mode) (engine->engine, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpgme_error_t
|
||||||
|
_gpgme_engine_op_spawn (engine_t engine,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr)
|
||||||
|
{
|
||||||
|
if (!engine)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
if (!engine->ops->opspawn)
|
||||||
|
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||||
|
|
||||||
|
return (*engine->ops->opspawn) (engine->engine, file, argv,
|
||||||
|
datain, dataout, dataerr);
|
||||||
|
}
|
||||||
|
@ -163,5 +163,11 @@ gpgme_error_t _gpgme_engine_op_passwd (engine_t engine, gpgme_key_t key,
|
|||||||
gpgme_error_t _gpgme_engine_set_pinentry_mode (engine_t engine,
|
gpgme_error_t _gpgme_engine_set_pinentry_mode (engine_t engine,
|
||||||
gpgme_pinentry_mode_t mode);
|
gpgme_pinentry_mode_t mode);
|
||||||
|
|
||||||
|
gpgme_error_t _gpgme_engine_op_spawn (engine_t engine,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout,
|
||||||
|
gpgme_data_t dataerr);
|
||||||
|
|
||||||
|
|
||||||
#endif /* ENGINE_H */
|
#endif /* ENGINE_H */
|
||||||
|
@ -1742,6 +1742,8 @@ gt_protocol_from_name (const char *name)
|
|||||||
return GPGME_PROTOCOL_G13;
|
return GPGME_PROTOCOL_G13;
|
||||||
if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
|
if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_UISERVER)))
|
||||||
return GPGME_PROTOCOL_UISERVER;
|
return GPGME_PROTOCOL_UISERVER;
|
||||||
|
if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_SPAWN)))
|
||||||
|
return GPGME_PROTOCOL_SPAWN;
|
||||||
if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
|
if (! strcasecmp (name, gpgme_get_protocol_name (GPGME_PROTOCOL_DEFAULT)))
|
||||||
return GPGME_PROTOCOL_DEFAULT;
|
return GPGME_PROTOCOL_DEFAULT;
|
||||||
return GPGME_PROTOCOL_UNKNOWN;
|
return GPGME_PROTOCOL_UNKNOWN;
|
||||||
@ -2106,6 +2108,18 @@ gt_identify (gpgme_tool_t gt, gpgme_data_t data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpg_error_t
|
||||||
|
gt_spawn (gpgme_tool_t gt, const char *pgm,
|
||||||
|
gpgme_data_t inp, gpgme_data_t outp)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
|
||||||
|
err = gpgme_op_spawn (gt->ctx, pgm, NULL, inp, outp, outp, 0);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define GT_RESULT_ENCRYPT 0x1
|
#define GT_RESULT_ENCRYPT 0x1
|
||||||
#define GT_RESULT_DECRYPT 0x2
|
#define GT_RESULT_DECRYPT 0x2
|
||||||
#define GT_RESULT_SIGN 0x4
|
#define GT_RESULT_SIGN 0x4
|
||||||
@ -3487,6 +3501,55 @@ cmd_identify (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_spawn[] =
|
||||||
|
"SPAWN PGM [args]\n"
|
||||||
|
"\n"
|
||||||
|
"Run program PGM with stdin connected to the INPUT source;\n"
|
||||||
|
"stdout and stderr to the OUTPUT source.";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_spawn (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
struct server *server = assuan_get_pointer (ctx);
|
||||||
|
gpg_error_t err;
|
||||||
|
assuan_fd_t inp_fd;
|
||||||
|
char *inp_fn;
|
||||||
|
assuan_fd_t out_fd;
|
||||||
|
char *out_fn;
|
||||||
|
gpgme_data_t inp_data = NULL;
|
||||||
|
gpgme_data_t out_data = NULL;
|
||||||
|
|
||||||
|
inp_fd = server->input_fd;
|
||||||
|
inp_fn = server->input_filename;
|
||||||
|
out_fd = server->output_fd;
|
||||||
|
out_fn = server->output_filename;
|
||||||
|
if (inp_fd != ASSUAN_INVALID_FD || inp_fn)
|
||||||
|
{
|
||||||
|
err = server_data_obj (inp_fd, inp_fn, 0, server->input_enc, &inp_data,
|
||||||
|
&server->input_stream);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (out_fd != ASSUAN_INVALID_FD || out_fn)
|
||||||
|
{
|
||||||
|
err = server_data_obj (out_fd, out_fn, 1, server->output_enc, &out_data,
|
||||||
|
&server->output_stream);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
gpgme_data_release (inp_data);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gt_spawn (server->gt, line, inp_data, out_data);
|
||||||
|
|
||||||
|
gpgme_data_release (inp_data);
|
||||||
|
gpgme_data_release (out_data);
|
||||||
|
|
||||||
|
server_reset_fds (server);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Tell the assuan library about our commands. */
|
/* Tell the assuan library about our commands. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -3547,6 +3610,7 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "HASH_ALGO_NAME", cmd_hash_algo_name },
|
{ "HASH_ALGO_NAME", cmd_hash_algo_name },
|
||||||
{ "PASSWD", cmd_passwd, hlp_passwd },
|
{ "PASSWD", cmd_passwd, hlp_passwd },
|
||||||
{ "IDENTIFY", cmd_identify, hlp_identify },
|
{ "IDENTIFY", cmd_identify, hlp_identify },
|
||||||
|
{ "SPAWN", cmd_spawn, hlp_spawn },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
int idx;
|
int idx;
|
||||||
|
14
src/gpgme.c
14
src/gpgme.c
@ -1,6 +1,7 @@
|
|||||||
/* gpgme.c - GnuPG Made Easy.
|
/* gpgme.c - GnuPG Made Easy.
|
||||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012 g10 Code GmbH
|
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2012,
|
||||||
|
2014 g10 Code GmbH
|
||||||
|
|
||||||
This file is part of GPGME.
|
This file is part of GPGME.
|
||||||
|
|
||||||
@ -15,9 +16,8 @@
|
|||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this program; if not, write to the Free Software
|
License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
*/
|
||||||
02111-1307, USA. */
|
|
||||||
|
|
||||||
#if HAVE_CONFIG_H
|
#if HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -321,7 +321,8 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol)
|
|||||||
&& protocol != GPGME_PROTOCOL_GPGCONF
|
&& protocol != GPGME_PROTOCOL_GPGCONF
|
||||||
&& protocol != GPGME_PROTOCOL_ASSUAN
|
&& protocol != GPGME_PROTOCOL_ASSUAN
|
||||||
&& protocol != GPGME_PROTOCOL_G13
|
&& protocol != GPGME_PROTOCOL_G13
|
||||||
&& protocol != GPGME_PROTOCOL_UISERVER)
|
&& protocol != GPGME_PROTOCOL_UISERVER
|
||||||
|
&& protocol != GPGME_PROTOCOL_SPAWN)
|
||||||
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
||||||
|
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
@ -405,6 +406,9 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol)
|
|||||||
case GPGME_PROTOCOL_UISERVER:
|
case GPGME_PROTOCOL_UISERVER:
|
||||||
return "UIServer";
|
return "UIServer";
|
||||||
|
|
||||||
|
case GPGME_PROTOCOL_SPAWN:
|
||||||
|
return "Spawn";
|
||||||
|
|
||||||
case GPGME_PROTOCOL_DEFAULT:
|
case GPGME_PROTOCOL_DEFAULT:
|
||||||
return "default";
|
return "default";
|
||||||
|
|
||||||
|
@ -215,5 +215,7 @@ EXPORTS
|
|||||||
|
|
||||||
gpgme_get_dirinfo @162
|
gpgme_get_dirinfo @162
|
||||||
|
|
||||||
|
gpgme_op_spawn_start @163
|
||||||
|
gpgme_op_spawn @164
|
||||||
; END
|
; END
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*-
|
/* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*-
|
||||||
Copyright (C) 2000 Werner Koch (dd9jn)
|
Copyright (C) 2000 Werner Koch (dd9jn)
|
||||||
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009
|
Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009
|
||||||
2010, 2011, 2012, 2013 g10 Code GmbH
|
2010, 2011, 2012, 2013, 2014 g10 Code GmbH
|
||||||
|
|
||||||
This file is part of GPGME.
|
This file is part of GPGME.
|
||||||
|
|
||||||
@ -354,6 +354,7 @@ typedef enum
|
|||||||
GPGME_PROTOCOL_ASSUAN = 3, /* Low-level access to an Assuan server. */
|
GPGME_PROTOCOL_ASSUAN = 3, /* Low-level access to an Assuan server. */
|
||||||
GPGME_PROTOCOL_G13 = 4,
|
GPGME_PROTOCOL_G13 = 4,
|
||||||
GPGME_PROTOCOL_UISERVER= 5,
|
GPGME_PROTOCOL_UISERVER= 5,
|
||||||
|
GPGME_PROTOCOL_SPAWN = 6, /* Direct access to any program. */
|
||||||
GPGME_PROTOCOL_DEFAULT = 254,
|
GPGME_PROTOCOL_DEFAULT = 254,
|
||||||
GPGME_PROTOCOL_UNKNOWN = 255
|
GPGME_PROTOCOL_UNKNOWN = 255
|
||||||
}
|
}
|
||||||
@ -1694,6 +1695,26 @@ gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key,
|
|||||||
gpgme_edit_cb_t fnc, void *fnc_value,
|
gpgme_edit_cb_t fnc, void *fnc_value,
|
||||||
gpgme_data_t out);
|
gpgme_data_t out);
|
||||||
|
|
||||||
|
|
||||||
|
/* Flags for the spawn operations. */
|
||||||
|
#define GPGME_SPAWN_DETACHED 1
|
||||||
|
#define GPGME_SPAWN_ALLOW_SET_FG 2
|
||||||
|
|
||||||
|
|
||||||
|
/* Run the command FILE with the arguments in ARGV. Connect stdin to
|
||||||
|
DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
|
||||||
|
streams is NULL, connect to /dev/null instead. */
|
||||||
|
gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr,
|
||||||
|
unsigned int flags);
|
||||||
|
gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr,
|
||||||
|
unsigned int flags);
|
||||||
|
|
||||||
|
|
||||||
/* Key management functions. */
|
/* Key management functions. */
|
||||||
struct _gpgme_op_keylist_result
|
struct _gpgme_op_keylist_result
|
||||||
|
@ -89,6 +89,9 @@ GPGME_1.1 {
|
|||||||
gpgme_get_pinentry_mode;
|
gpgme_get_pinentry_mode;
|
||||||
|
|
||||||
gpgme_get_dirinfo;
|
gpgme_get_dirinfo;
|
||||||
|
|
||||||
|
gpgme_op_spawn_start;
|
||||||
|
gpgme_op_spawn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
105
src/spawn.c
Normal file
105
src/spawn.c
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/* spawn.c - Run an arbitrary command with callbacks.
|
||||||
|
Copyright (C) 2014 Code GmbH
|
||||||
|
|
||||||
|
This file is part of GPGME.
|
||||||
|
|
||||||
|
GPGME is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of
|
||||||
|
the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
GPGME is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
02111-1307, USA. */
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "gpgme.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "ops.h"
|
||||||
|
|
||||||
|
|
||||||
|
static gpgme_error_t
|
||||||
|
spawn_start (gpgme_ctx_t ctx, int synchronous,
|
||||||
|
const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
const char *tmp_argv[2];
|
||||||
|
|
||||||
|
if (ctx->protocol != GPGME_PROTOCOL_SPAWN)
|
||||||
|
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
|
||||||
|
|
||||||
|
err = _gpgme_op_reset (ctx, synchronous);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!argv)
|
||||||
|
{
|
||||||
|
tmp_argv[0] = _gpgme_get_basename (file);
|
||||||
|
tmp_argv[1] = NULL;
|
||||||
|
argv = tmp_argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _gpgme_engine_op_spawn (ctx->engine, file, argv,
|
||||||
|
datain, dataout, dataerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Run the command FILE with the arguments in ARGV. Connect stdin to
|
||||||
|
DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
|
||||||
|
streams is NULL, connect to /dev/null instead. */
|
||||||
|
gpgme_error_t
|
||||||
|
gpgme_op_spawn_start (gpgme_ctx_t ctx, const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
|
||||||
|
TRACE_BEG2 (DEBUG_CTX, "gpgme_op_spawn_start", ctx, "file=(%s) flaggs=%x",
|
||||||
|
file, flags);
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
||||||
|
|
||||||
|
err = spawn_start (ctx, 0, file, argv, datain, dataout, dataerr);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Run the command FILE with the arguments in ARGV. Connect stdin to
|
||||||
|
DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data
|
||||||
|
streams is NULL, connect to /dev/null instead. Synchronous
|
||||||
|
variant. */
|
||||||
|
gpgme_error_t
|
||||||
|
gpgme_op_spawn (gpgme_ctx_t ctx, const char *file, const char *argv[],
|
||||||
|
gpgme_data_t datain,
|
||||||
|
gpgme_data_t dataout, gpgme_data_t dataerr,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
gpgme_error_t err;
|
||||||
|
|
||||||
|
TRACE_BEG2 (DEBUG_CTX, "gpgme_op_spawn", ctx, "file=(%s) flags=%x",
|
||||||
|
file, flags);
|
||||||
|
if (!ctx)
|
||||||
|
return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
|
||||||
|
|
||||||
|
err = spawn_start (ctx, 1, file, argv, datain, dataout, dataerr);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
err = _gpgme_wait_one (ctx);
|
||||||
|
return TRACE_ERR (err);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user