From 03bf88f32c8d203d5b3bfbbc48cc45e6c08cc187 Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Tue, 24 Nov 2015 18:31:14 +0100 Subject: [PATCH] common: Add stream interface to call-pgp. * common/call-gpg.c (struct writer_thread_parms): Add field 'stream'. (writer_thread_main): Support reading from a stream. (start_writer): Add stream argument. (struct reader_thread_parms): Add field 'stream'. (reader_thread_main): Support writing to a stream. (start_reader): Add stream argument. (_gpg_encrypt): Add stream api. (gpg_encrypt_blob): Adapt accordingly. (gpg_encrypt_stream): New function. (_gpg_decrypt): Add stream api. (gpg_decrypt_blob): Adapt accordingly. (gpg_decrypt_stream): New function. * common/call-gpg.h (gpg_encrypt_stream): New prototype. (gpg_decrypt_stream): Likewise. Signed-off-by: Justus Winter --- common/call-gpg.c | 135 +++++++++++++++++++++++++++++++++++++++------- common/call-gpg.h | 12 ++++- 2 files changed, 128 insertions(+), 19 deletions(-) diff --git a/common/call-gpg.c b/common/call-gpg.c index cc6b1e83f..8258b8378 100644 --- a/common/call-gpg.c +++ b/common/call-gpg.c @@ -151,6 +151,7 @@ struct writer_thread_parms int fd; const void *data; size_t datalen; + estream_t stream; gpg_error_t *err_addr; }; @@ -159,9 +160,27 @@ struct writer_thread_parms static void * writer_thread_main (void *arg) { + gpg_error_t err = 0; struct writer_thread_parms *parm = arg; - const char *buffer = parm->data; - size_t length = parm->datalen; + char _buffer[4096]; + char *buffer; + size_t length; + + if (parm->stream) + { + buffer = _buffer; + err = es_read (parm->stream, buffer, sizeof _buffer, &length); + if (err) + { + log_error ("reading stream failed: %s\n", gpg_strerror (err)); + goto leave; + } + } + else + { + buffer = (char *) parm->data; + length = parm->datalen; + } while (length) { @@ -172,13 +191,33 @@ writer_thread_main (void *arg) { if (errno == EINTR) continue; - *parm->err_addr = gpg_error_from_syserror (); + err = gpg_error_from_syserror (); break; /* Write error. */ } length -= nwritten; - buffer += nwritten; + + if (parm->stream) + { + if (length == 0) + { + err = es_read (parm->stream, buffer, sizeof _buffer, &length); + if (err) + { + log_error ("reading stream failed: %s\n", + gpg_strerror (err)); + break; + } + if (length == 0) + /* We're done. */ + break; + } + } + else + buffer += nwritten; } + leave: + *parm->err_addr = err; if (close (parm->fd)) log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno)); xfree (parm); @@ -192,7 +231,7 @@ writer_thread_main (void *arg) variable to receive a possible write error after the thread has finished. */ static gpg_error_t -start_writer (int fd, const void *data, size_t datalen, +start_writer (int fd, const void *data, size_t datalen, estream_t stream, npth_t *r_thread, gpg_error_t *err_addr) { gpg_error_t err; @@ -210,6 +249,7 @@ start_writer (int fd, const void *data, size_t datalen, parm->fd = fd; parm->data = data; parm->datalen = datalen; + parm->stream = stream; parm->err_addr = err_addr; npth_attr_init (&tattr); @@ -239,6 +279,7 @@ struct reader_thread_parms { int fd; membuf_t *mb; + estream_t stream; gpg_error_t *err_addr; }; @@ -247,6 +288,7 @@ struct reader_thread_parms static void * reader_thread_main (void *arg) { + gpg_error_t err = 0; struct reader_thread_parms *parm = arg; char buffer[4096]; int nread; @@ -257,13 +299,33 @@ reader_thread_main (void *arg) { if (errno == EINTR) continue; - *parm->err_addr = gpg_error_from_syserror (); + err = gpg_error_from_syserror (); break; /* Read error. */ } - put_membuf (parm->mb, buffer, nread); + if (parm->stream) + { + const char *p = buffer; + size_t nwritten; + while (nread) + { + err = es_write (parm->stream, p, nread, &nwritten); + if (err) + { + log_error ("writing stream failed: %s\n", + gpg_strerror (err)); + goto leave; + } + nread -= nwritten; + p += nwritten; + } + } + else + put_membuf (parm->mb, buffer, nread); } + leave: + *parm->err_addr = err; if (close (parm->fd)) log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno)); xfree (parm); @@ -276,7 +338,8 @@ reader_thread_main (void *arg) is stored at R_TID. After the thread has finished an error from the thread will be stored at ERR_ADDR. */ static gpg_error_t -start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr) +start_reader (int fd, membuf_t *mb, estream_t stream, + npth_t *r_thread, gpg_error_t *err_addr) { gpg_error_t err; struct reader_thread_parms *parm; @@ -292,6 +355,7 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr) return gpg_error_from_syserror (); parm->fd = fd; parm->mb = mb; + parm->stream = stream; parm->err_addr = err_addr; npth_attr_init (&tattr); @@ -324,8 +388,10 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr) static gpg_error_t _gpg_encrypt (ctrl_t ctrl, const char *gpg_program, const void *plain, size_t plainlen, + estream_t plain_stream, strlist_t keys, - membuf_t *reader_mb) + membuf_t *reader_mb, + estream_t cipher_stream) { gpg_error_t err; assuan_context_t ctx = NULL; @@ -338,6 +404,11 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program, strlist_t sl; int ret; + /* Make sure that either the stream interface xor the buffer + interface is used. */ + assert ((plain == NULL) != (plain_stream == NULL)); + assert ((reader_mb == NULL) != (cipher_stream == NULL)); + /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds); if (!err) @@ -356,7 +427,7 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program, close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ - err = start_writer (outbound_fds[1], plain, plainlen, + err = start_writer (outbound_fds[1], plain, plainlen, plain_stream, &writer_thread, &writer_err); if (err) return err; @@ -364,7 +435,7 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program, /* Start a reader thread to eat from the OUTPUT command of the server. */ - err = start_reader (inbound_fds[0], reader_mb, + err = start_reader (inbound_fds[0], reader_mb, cipher_stream, &reader_thread, &reader_err); if (err) return err; @@ -458,9 +529,9 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program, init_membuf (&reader_mb, 4096); err = _gpg_encrypt (ctrl, gpg_program, - plain, plainlen, + plain, plainlen, NULL, keys, - &reader_mb); + &reader_mb, NULL); if (! err) { @@ -478,6 +549,17 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program, return err; } +gpg_error_t +gpg_encrypt_stream (ctrl_t ctrl, const char *gpg_program, + estream_t plain_stream, + strlist_t keys, + estream_t cipher_stream) +{ + return _gpg_encrypt (ctrl, gpg_program, + NULL, 0, plain_stream, + keys, + NULL, cipher_stream); +} /* Call GPG to decrypt a block of data. @@ -486,7 +568,9 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program, static gpg_error_t _gpg_decrypt (ctrl_t ctrl, const char *gpg_program, const void *ciph, size_t ciphlen, - membuf_t *reader_mb) + estream_t cipher_stream, + membuf_t *reader_mb, + estream_t plain_stream) { gpg_error_t err; assuan_context_t ctx = NULL; @@ -497,6 +581,11 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program, gpg_error_t writer_err, reader_err; int ret; + /* Make sure that either the stream interface xor the buffer + interface is used. */ + assert ((ciph == NULL) != (cipher_stream == NULL)); + assert ((reader_mb == NULL) != (plain_stream == NULL)); + /* Create two pipes. */ err = gnupg_create_outbound_pipe (outbound_fds); if (!err) @@ -515,7 +604,7 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program, close (inbound_fds[1]); inbound_fds[1] = -1; /* Start a writer thread to feed the INPUT command of the server. */ - err = start_writer (outbound_fds[1], ciph, ciphlen, + err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream, &writer_thread, &writer_err); if (err) return err; @@ -523,7 +612,7 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program, /* Start a reader thread to eat from the OUTPUT command of the server. */ - err = start_reader (inbound_fds[0], reader_mb, + err = start_reader (inbound_fds[0], reader_mb, plain_stream, &reader_thread, &reader_err); if (err) return err; @@ -602,8 +691,8 @@ gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program, init_membuf_secure (&reader_mb, 1024); err = _gpg_decrypt (ctrl, gpg_program, - ciph, ciphlen, - &reader_mb); + ciph, ciphlen, NULL, + &reader_mb, NULL); if (! err) { @@ -620,3 +709,13 @@ gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program, xfree (get_membuf (&reader_mb, NULL)); return err; } + +gpg_error_t +gpg_decrypt_stream (ctrl_t ctrl, const char *gpg_program, + estream_t cipher_stream, + estream_t plain_stream) +{ + return _gpg_decrypt (ctrl, gpg_program, + NULL, 0, cipher_stream, + NULL, plain_stream); +} diff --git a/common/call-gpg.h b/common/call-gpg.h index 606473d88..2c5854d61 100644 --- a/common/call-gpg.h +++ b/common/call-gpg.h @@ -20,6 +20,8 @@ #ifndef G13_CALL_GPG_H #define G13_CALL_GPG_H +#include + #include "strlist.h" typedef struct server_control_s *ctrl_t; @@ -28,10 +30,18 @@ gpg_error_t gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program, const void *plain, size_t plainlen, strlist_t keys, void **r_ciph, size_t *r_ciphlen); + +gpg_error_t gpg_encrypt_stream (ctrl_t ctrl, const char *gpg_program, + estream_t plain_stream, + strlist_t keys, + estream_t cipher_stream); + gpg_error_t gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program, const void *ciph, size_t ciphlen, void **r_plain, size_t *r_plainlen); - +gpg_error_t gpg_decrypt_stream (ctrl_t ctrl, const char *gpg_program, + estream_t cipher_stream, + estream_t plain_stream); #endif /*G13_CALL_GPG_H*/