+2001-11-22 Marcus Brinkmann <marcus@g10code.de>
+
+ * rungpg.c (gpg_inbound_handler, write_mem_data, write_cb_data,
+ gpg_outbound_handler): Moved to ...
+ * data.c (_gpgme_data_inbound_handler, write_mem_data,
+ write_cb_data, _gpgme_data_outbound_handler): ... here. Make the
+ _gpgme_* ones non-static.
+ * data.c: Include io.h.
+
+ * ops.h (_gpgme_data_inbound_handler): New prototype.
+ (_gpgme_data_outbound_handler): Likewise.
+ (_gpgme_gpg_spawn): Use these new functions.
+
+ * engine-gpgsm.h (_gpgme_gpgsm_op_decrypt, _gpgme_gpgsm_op_delete,
+ _gpgme_gpgsm_op_encrypt, _gpgme_gpgsm_op_export,
+ _gpgme_gpgsm_op_genkey, _gpgme_gpgsm_op_import,
+ _gpgme_gpgsm_op_keylist, _gpgme_gpgsm_op_sign,
+ _gpgme_gpgsm_op_trustlist, _gpgme_gpgsm_op_verify,
+ _gpgme_gpgsm_start, _gpgme_gpgsm_set_status_handler): New prototype.
+ Include <rungpg.h> for status handler function.
+
+ * engine-gpgsm.c (struct gpgsm_object_s): New members input_fd,
+ input_data, output_fd, output_data, message_fd, message_data, command
+ and status.
+ (_gpgme_gpgsm_new): Open input, output and message pipes before
+ connecting to the client. Close server's ends afterwards.
+ (_gpgme_gpgsm_release): Close open file descriptors. Remove
+ server process from wait queue.
+ (_gpgme_gpgsm_op_verify, _gpgme_gpgsm_start,
+ _gpgme_gpgsm_set_status_handler, gpgms_status_handler): New function.
+
+ * engine.c (_gpgme_engine_start): Implement for GPGME_PROTOCOL_CMS.
+ (_gpgme_engine_set_status_handler): Likewise.
+ (_gpgme_engine_op_verify): Likewise.
+
2001-11-21 Marcus Brinkmann <marcus@g10code.de>
* context.h: Do not include rungpg.h, but engine.h.
#include "util.h"
#include "context.h"
#include "ops.h"
+#include "io.h"
#define ALLOC_CHUNK 1024
#define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
return c;
}
-
-
-
/*
* Append a string with percent style (%XX) escape characters as XML
*/
xfree (buf);
return err;
}
+
+/* Functions to support the wait interface. */
+
+int
+_gpgme_data_inbound_handler (void *opaque, int pid, int fd)
+{
+ GpgmeData dh = opaque;
+ GpgmeError err;
+ int nread;
+ char buf[200];
+
+ assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN);
+
+ nread = _gpgme_io_read (fd, buf, 200);
+ if (nread < 0)
+ {
+ DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
+ fd, nread, strerror (errno) );
+ return 1;
+ }
+ else if (!nread)
+ return 1; /* eof */
+
+ /* We could improve this with a GpgmeData function which takes
+ * the read function or provides a memory area for writing to it.
+ */
+
+ err = _gpgme_data_append (dh, buf, nread);
+ if (err)
+ {
+ DEBUG1 ("_gpgme_append_data failed: %s\n",
+ gpgme_strerror(err));
+ /* Fixme: we should close the pipe or read it to /dev/null in
+ * this case. Returnin EOF is not sufficient */
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+write_mem_data (GpgmeData dh, int fd)
+{
+ size_t nbytes;
+ int nwritten;
+
+ nbytes = dh->len - dh->readpos;
+ if (!nbytes)
+ {
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ /* FIXME: Arggg, the pipe blocks on large write request, although
+ * select told us that it is okay to write - need to figure out
+ * why this happens? Stevens says nothing about this problem (or
+ * is it my Linux kernel 2.4.0test1)
+ * To avoid that we have set the pipe to nonblocking.
+ */
+
+ nwritten = _gpgme_io_write (fd, dh->data+dh->readpos, nbytes);
+ if (nwritten == -1 && errno == EAGAIN)
+ return 0;
+ if (nwritten < 1)
+ {
+ DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
+ fd, nwritten, strerror (errno));
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ dh->readpos += nwritten;
+ return 0;
+}
+
+static int
+write_cb_data (GpgmeData dh, int fd)
+{
+ size_t nbytes;
+ int err, nwritten;
+ char buffer[512];
+
+ err = gpgme_data_read (dh, buffer, DIM(buffer), &nbytes);
+ if (err == GPGME_EOF)
+ {
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ nwritten = _gpgme_io_write (fd, buffer, nbytes);
+ if (nwritten == -1 && errno == EAGAIN )
+ return 0;
+ if (nwritten < 1)
+ {
+ DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
+ fd, nwritten, strerror (errno));
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ if (nwritten < nbytes)
+ {
+ /* ugly, ugly: It does currently only for for MEM type data */
+ if (_gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten))
+ DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
+ nbytes - nwritten);
+ _gpgme_io_close (fd);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+_gpgme_data_outbound_handler (void *opaque, int pid, int fd)
+{
+ GpgmeData dh = opaque;
+
+ assert (_gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT);
+ switch (gpgme_data_get_type (dh))
+ {
+ case GPGME_DATA_TYPE_MEM:
+ if (write_mem_data (dh, fd))
+ return 1; /* ready */
+ break;
+ case GPGME_DATA_TYPE_CB:
+ if (write_cb_data (dh, fd))
+ return 1; /* ready */
+ break;
+ default:
+ assert (0);
+ }
+
+ return 0;
+}
#include <config.h>
#endif
-#include "gpgme.h"
-#include "util.h"
-#include "types.h"
-#include "ops.h"
-
-#include "engine-gpgsm.h"
-
/* FIXME: Correct check? */
#ifdef GPGSM_PATH
#define ENABLE_GPGSM 1
#ifdef ENABLE_GPGSM
+#include <sys/types.h>
+#include <assert.h>
+
+/* FIXME */
+#include "../assuan/assuan-defs.h"
+#undef xtrymalloc
+#undef xtrycalloc
+#undef xtryrealloc
+#undef xfree
+
+#include "gpgme.h"
+#include "util.h"
+#include "types.h"
+#include "ops.h"
+#include "wait.h"
+#include "io.h"
+
+#include "engine-gpgsm.h"
+
#include "assuan.h"
struct gpgsm_object_s
{
ASSUAN_CONTEXT assuan_ctx;
+
+ /* Input, output etc are from the servers perspective. */
+ int input_fd;
+ int input_fd_server;
+ GpgmeData input_data;
+ int output_fd;
+ int output_fd_server;
+ GpgmeData output_data;
+ int message_fd;
+ int message_fd_server;
+ GpgmeData message_data;
+
+ char *command;
+
+ struct
+ {
+ GpgStatusHandler fnc;
+ void *fnc_value;
+ } status;
+
};
const char *
GpgmeError err = 0;
GpgsmObject gpgsm;
char *argv[] = { "gpgsm", "--server", NULL };
+ int ip[2] = { -1, -1 };
+ int op[2] = { -1, -1 };
+ int mp[2] = { -1, -1 };
*r_gpgsm = NULL;
gpgsm = xtrycalloc (1, sizeof *gpgsm);
goto leave;
}
+ if (_gpgme_io_pipe (ip, 0) < 0)
+ {
+ err = mk_error (General_Error);
+ goto leave;
+ }
+ gpgsm->input_fd = ip[1];
+ gpgsm->input_fd_server = ip[0];
+ if (_gpgme_io_pipe (op, 1) < 0)
+ {
+ err = mk_error (General_Error);
+ goto leave;
+ }
+ gpgsm->output_fd = op[0];
+ gpgsm->output_fd_server = op[1];
+ if (_gpgme_io_pipe (mp, 0) < 0)
+ {
+ err = mk_error (General_Error);
+ goto leave;
+ }
+ gpgsm->message_fd = mp[1];
+ gpgsm->message_fd_server = mp[0];
+
err = assuan_pipe_connect (&gpgsm->assuan_ctx,
_gpgme_get_gpgsm_path (), argv);
leave:
+ if (ip[0] != -1)
+ _gpgme_io_close (ip[0]);
+ if (op[1] != -1)
+ _gpgme_io_close (op[1]);
+ if (mp[0] != -1)
+ _gpgme_io_close (mp[0]);
+
if (err)
_gpgme_gpgsm_release (gpgsm);
else
void
_gpgme_gpgsm_release (GpgsmObject gpgsm)
{
+ pid_t pid;
+
if (!gpgsm)
return;
+ pid = assuan_get_pid (gpgsm->assuan_ctx);
+ if (pid != -1)
+ _gpgme_remove_proc_from_wait_queue (pid);
+
+ if (gpgsm->input_fd != -1)
+ _gpgme_io_close (gpgsm->input_fd);
+ if (gpgsm->output_fd != -1)
+ _gpgme_io_close (gpgsm->output_fd);
+ if (gpgsm->message_fd != -1)
+ _gpgme_io_close (gpgsm->message_fd);
+
assuan_pipe_disconnect (gpgsm->assuan_ctx);
xfree (gpgsm);
}
+#define COMMANDLINELEN 40
+static AssuanError
+gpgsm_set_fd (ASSUAN_CONTEXT ctx, const char *which, int fd)
+{
+ AssuanError err;
+ char line[COMMANDLINELEN];
+
+ snprintf (line, COMMANDLINELEN, "%s FD=%i", which, fd);
+ err = _assuan_write_line (ctx, line);
+ if (err)
+ return err;
+
+ do
+ {
+ err = _assuan_read_line (ctx);
+ if (err)
+ return err;
+ }
+ while (*ctx->inbound.line == '#' || !ctx->inbound.linelen);
+
+ if (ctx->inbound.linelen >= 2
+ && ctx->inbound.line[0] == 'O' && ctx->inbound.line[1] == 'K'
+ && (ctx->inbound.line[2] == '\0' || ctx->inbound.line[2] == ' '))
+ return 0;
+ else
+ return ASSUAN_General_Error;
+}
+
+GpgmeError
+_gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
+{
+ AssuanError err;
+
+ if (!gpgsm)
+ return mk_error (Invalid_Value);
+
+ gpgsm->input_data = sig;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "INPUT", gpgsm->input_fd_server);
+ if (err)
+ return mk_error (General_Error); /* FIXME */
+ gpgsm->message_data = sig;
+ err = gpgsm_set_fd (gpgsm->assuan_ctx, "MESSAGE", gpgsm->message_fd_server);
+ if (err)
+ return mk_error (General_Error); /* FIXME */
+ _gpgme_io_close (gpgsm->output_fd);
+ gpgsm->output_fd = -1;
+
+ gpgsm->command = "VERIFY";
+ return 0;
+}
+
+static int
+gpgsm_status_handler (void *opaque, int pid, int fd)
+{
+ int err;
+ GpgsmObject gpgsm = opaque;
+ ASSUAN_CONTEXT actx = gpgsm->assuan_ctx;
+
+ assert (fd == gpgsm->assuan_ctx->inbound.fd);
+
+ err = _assuan_read_line (gpgsm->assuan_ctx);
+
+ if (actx->inbound.line[0] == '#' || !actx->inbound.linelen)
+ return 0; /* FIXME */
+
+ if (actx->inbound.linelen >= 2
+ && actx->inbound.line[0] == 'O' && actx->inbound.line[1] == 'K'
+ && (actx->inbound.line[2] == '\0' || actx->inbound.line[2] == ' '))
+ {
+ if (gpgsm->status.fnc)
+ gpgsm->status.fnc (gpgsm->status.fnc_value, STATUS_EOF, "");
+ return 1;
+ }
+ /* FIXME: Parse the status and call the handler. */
+
+ fprintf (stderr, "[UNCAUGHT STATUS]%s", actx->inbound.line);
+ return 0;
+}
+
+void
+_gpgme_gpgsm_set_status_handler (GpgsmObject gpgsm,
+ GpgStatusHandler fnc, void *fnc_value)
+{
+ assert (gpgsm);
+
+ gpgsm->status.fnc = fnc;
+ gpgsm->status.fnc_value = fnc_value;
+}
+
+GpgmeError
+_gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
+{
+ GpgmeError err = 0;
+ pid_t pid;
+
+ if (!gpgsm)
+ return mk_error (Invalid_Value);
+
+ pid = assuan_get_pid (gpgsm->assuan_ctx);
+
+ err = _gpgme_register_pipe_handler (opaque, gpgsm_status_handler, gpgsm, pid,
+ gpgsm->assuan_ctx->inbound.fd, 1);
+
+ if (gpgsm->input_fd != -1)
+ {
+ err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
+ gpgsm->input_data, pid,
+ gpgsm->input_fd, 0);
+ if (!err) /* FIXME Kludge around poll() problem. */
+ err = _gpgme_io_set_nonblocking (gpgsm->input_fd);
+ }
+ if (!err && gpgsm->output_fd != -1)
+ err = _gpgme_register_pipe_handler (opaque, _gpgme_data_inbound_handler,
+ gpgsm->output_data, pid,
+ gpgsm->output_fd, 1);
+ if (!err && gpgsm->message_fd != -1)
+ {
+ err = _gpgme_register_pipe_handler (opaque, _gpgme_data_outbound_handler,
+ gpgsm->message_data, pid,
+ gpgsm->message_fd, 0);
+ if (!err) /* FIXME Kludge around poll() problem. */
+ err = _gpgme_io_set_nonblocking (gpgsm->message_fd);
+ }
+
+ if (!err)
+ err = _assuan_write_line (gpgsm->assuan_ctx, gpgsm->command);
+
+ return err;
+}
+
#else /* ENABLE_GPGSM */
const char *
return;
}
+GpgmeError
+ _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text)
+{
+ return mk_error (Invalid_Engine);
+}
+
+GpgmeError
+_gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque)
+{
+ return mk_error (Invalid_Engine);
+}
+
#endif /* ! ENABLE_GPGSM */
#define ENGINE_GPGSM_H
#include "types.h"
+#include "rungpg.h" /* FIXME statusHandler */
const char *_gpgme_gpgsm_get_version (void);
GpgmeError _gpgme_gpgsm_check_version (void);
GpgmeError _gpgme_gpgsm_new (GpgsmObject *r_gpg);
void _gpgme_gpgsm_release (GpgsmObject gpg);
+void _gpgme_gpgsm_set_status_handler (GpgsmObject gpgsm,
+ GpgStatusHandler fnc, void *fnc_value);
+GpgmeError _gpgme_gpgsm_op_decrypt (GpgsmObject gpgsm, GpgmeData ciph,
+ GpgmeData plain);
+GpgmeError _gpgme_gpgsm_op_delete (GpgsmObject gpgsm, GpgmeKey key, int allow_secret);
+GpgmeError _gpgme_gpgsm_op_encrypt (GpgsmObject gpgsm, GpgmeRecipients recp,
+ GpgmeData plain, GpgmeData ciph,
+ int use_armor);
+GpgmeError _gpgme_gpgsm_op_export (GpgsmObject gpgsm, GpgmeRecipients recp,
+ GpgmeData keydata, int use_armor);
+GpgmeError _gpgme_gpgsm_op_genkey (GpgsmObject gpgsm, GpgmeData help_data,
+ int use_armor);
+GpgmeError _gpgme_gpgsm_op_import (GpgsmObject gpgsm, GpgmeData keydata);
+GpgmeError _gpgme_gpgsm_op_keylist (GpgsmObject gpgsm, const char *pattern,
+ int secret_only, int keylist_mode);
+GpgmeError _gpgme_gpgsm_op_sign (GpgsmObject gpgsm, GpgmeData in, GpgmeData out,
+ GpgmeSigMode mode, int use_armor,
+ int use_textmode, GpgmeCtx ctx /* FIXME */);
+GpgmeError _gpgme_gpgsm_op_trustlist (GpgsmObject gpgsm, const char *pattern);
+GpgmeError _gpgme_gpgsm_op_verify (GpgsmObject gpgsm, GpgmeData sig, GpgmeData text);
+GpgmeError _gpgme_gpgsm_start (GpgsmObject gpgsm, void *opaque);
+
#endif /* ENGINE_GPGSM_H */
_gpgme_gpg_set_status_handler (engine->engine.gpg, fnc, fnc_value);
break;
case GPGME_PROTOCOL_CMS:
- /* FIXME */
+ _gpgme_gpgsm_set_status_handler (engine->engine.gpgsm, fnc, fnc_value);
break;
default:
break;
case GPGME_PROTOCOL_OpenPGP:
return _gpgme_gpg_op_verify (engine->engine.gpg, sig, text);
case GPGME_PROTOCOL_CMS:
- /* FIXME */
- break;
+ return _gpgme_gpgsm_op_verify (engine->engine.gpgsm, sig, text);
default:
break;
}
case GPGME_PROTOCOL_OpenPGP:
return _gpgme_gpg_spawn (engine->engine.gpg, opaque);
case GPGME_PROTOCOL_CMS:
- /* FIXME */
- break;
+ return _gpgme_gpgsm_start (engine->engine.gpgsm, opaque);
default:
break;
}
GpgmeError _gpgme_data_unread (GpgmeData dh,
const char *buffer, size_t length );
+int _gpgme_data_inbound_handler (void *opaque, int pid, int fd);
+int _gpgme_data_outbound_handler (void *opaque, int pid, int fd);
+
/*-- key.c --*/
GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
static void free_argv ( char **argv );
static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
-static int gpg_inbound_handler ( void *opaque, int pid, int fd );
-static int gpg_outbound_handler ( void *opaque, int pid, int fd );
-
static int gpg_status_handler ( void *opaque, int pid, int fd );
static GpgmeError read_status ( GpgObject gpg );
if ( _gpgme_register_pipe_handler (
opaque,
gpg->fd_data_map[i].inbound?
- gpg_inbound_handler:gpg_outbound_handler,
+ _gpgme_data_inbound_handler:_gpgme_data_outbound_handler,
gpg->fd_data_map[i].data,
pid, gpg->fd_data_map[i].fd,
gpg->fd_data_map[i].inbound )
}
-static int
-gpg_inbound_handler ( void *opaque, int pid, int fd )
-{
- GpgmeData dh = opaque;
- GpgmeError err;
- int nread;
- char buf[200];
-
- assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
-
- nread = _gpgme_io_read (fd, buf, 200 );
- if ( nread < 0 ) {
- DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
- fd, nread, strerror (errno) );
- return 1;
- }
- else if (!nread)
- return 1; /* eof */
-
- /* We could improve this with a GpgmeData function which takes
- * the read function or provides a memory area for writing to it.
- */
-
- err = _gpgme_data_append ( dh, buf, nread );
- if ( err ) {
- DEBUG1 ("_gpgme_append_data failed: %s\n",
- gpgme_strerror(err));
- /* Fixme: we should close the pipe or read it to /dev/null in
- * this case. Returnin EOF is not sufficient */
- return 1;
- }
-
- return 0;
-}
-
-
-static int
-write_mem_data ( GpgmeData dh, int fd )
-{
- size_t nbytes;
- int nwritten;
-
- nbytes = dh->len - dh->readpos;
- if ( !nbytes ) {
- _gpgme_io_close (fd);
- return 1;
- }
-
- /* FIXME: Arggg, the pipe blocks on large write request, although
- * select told us that it is okay to write - need to figure out
- * why this happens? Stevens says nothing about this problem (or
- * is it my Linux kernel 2.4.0test1)
- * To avoid that we have set the pipe to nonblocking.
- */
-
- nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
- if (nwritten == -1 && errno == EAGAIN )
- return 0;
- if ( nwritten < 1 ) {
- DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
- fd, nwritten, strerror (errno) );
- _gpgme_io_close (fd);
- return 1;
- }
-
- dh->readpos += nwritten;
- return 0;
-}
-
-static int
-write_cb_data ( GpgmeData dh, int fd )
-{
- size_t nbytes;
- int err, nwritten;
- char buffer[512];
-
- err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
- if (err == GPGME_EOF) {
- _gpgme_io_close (fd);
- return 1;
- }
-
- nwritten = _gpgme_io_write ( fd, buffer, nbytes );
- if (nwritten == -1 && errno == EAGAIN )
- return 0;
- if ( nwritten < 1 ) {
- DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
- fd, nwritten, strerror (errno) );
- _gpgme_io_close (fd);
- return 1;
- }
-
- if ( nwritten < nbytes ) {
- /* ugly, ugly: It does currently only for for MEM type data */
- if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
- DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
- nbytes - nwritten );
- _gpgme_io_close (fd);
- return 1;
- }
-
- return 0;
-}
-
-
-static int
-gpg_outbound_handler ( void *opaque, int pid, int fd )
-{
- GpgmeData dh = opaque;
-
- assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT );
- switch ( gpgme_data_get_type (dh) ) {
- case GPGME_DATA_TYPE_MEM:
- if ( write_mem_data ( dh, fd ) )
- return 1; /* ready */
- break;
- case GPGME_DATA_TYPE_CB:
- if (write_cb_data (dh, fd))
- return 1; /* ready */
- break;
- default:
- assert (0);
- }
-
- return 0;
-}
-
-
-
static int
gpg_status_handler ( void *opaque, int pid, int fd )
{