Allow export to work on systems without funopen/fopencookie.
authorWerner Koch <wk@gnupg.org>
Mon, 19 Mar 2007 15:44:59 +0000 (15:44 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 19 Mar 2007 15:44:59 +0000 (15:44 +0000)
14 files changed:
common/ChangeLog
common/miscellaneous.c
common/util.h
sm/ChangeLog
sm/base64.c
sm/certreqgen.c
sm/decrypt.c
sm/encrypt.c
sm/export.c
sm/gpgsm.c
sm/gpgsm.h
sm/server.c
sm/sign.c
sm/verify.c

index 58695ed..e42bebf 100644 (file)
@@ -1,5 +1,6 @@
 2007-03-19  Werner Koch  <wk@g10code.com>
 
+       * miscellaneous.c (print_hexstring): New.
        * estream.c (es_fprintf_unlocked): New.
        (es_write_sanitized): New.
        (es_write_hexstring): New.
index 948c8ef..498c2ab 100644 (file)
@@ -67,6 +67,22 @@ print_utf8_string( FILE *fp, const byte *p, size_t n )
     print_utf8_string2 (fp, p, n, 0);
 }
 
+/* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
+   RESERVED must be 0. */
+void
+print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
+{
+#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+  const unsigned char *s;
+
+  for (s = buffer; length; s++, length--)
+    {
+      putc ( tohex ((*s>>4)&15), fp);
+      putc ( tohex (*s&15), fp);
+    }
+#undef tohex
+}
+
 char *
 make_printable_string (const void *p, size_t n, int delim )
 {
index 324fbb2..2cf6e6c 100644 (file)
@@ -185,6 +185,8 @@ const char *print_fname_stdin (const char *s);
 void print_string (FILE *fp, const byte *p, size_t n, int delim);
 void print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim);
 void print_utf8_string (FILE *fp, const byte *p, size_t n);
+void print_hexstring (FILE *fp, const void *buffer, size_t length,
+                      int reserved);
 char *make_printable_string (const void *p, size_t n, int delim);
 
 int is_file_compressed (const char *s, int *ret_rc);
index cb154fc..f666af5 100644 (file)
@@ -1,7 +1,7 @@
 2007-03-19  Werner Koch  <wk@g10code.com>
 
-        Change to let the key listing use estream to help systems without
-       funopen.
+        Changes to let export and key listing use estream to help systems
+       without funopen.
        
        * keylist.c: Use estream in place of stdio functions.
        * gpgsm.c (open_es_fwrite): New.
@@ -9,6 +9,7 @@
        * server.c (data_line_cookie_functions): New.
        (data_line_cookie_write, data_line_cookie_close): New.
        (do_listkeys): Use estream.
+
        * certdump.c (gpgsm_print_serial): Changed to use estream.
        (gpgsm_print_time): Ditto.
        (pretty_es_print_sexp): New.
        (do_list, unknown_criticals, allowed_ca, check_cert_policy) 
        (is_cert_still_valid): Ditto.
 
+       * export.c (gpgsm_export): New arg STREAM.
+       (do_putc, do_fputs): New.
+       (print_short_info): Allow printing to optional STREAM.
+       * server.c (cmd_export): Use stream.
+       * base64.c (do_putc, do_fputs): New.
+       (base64_writer_cb, base64_finish_write): Let them cope with an
+       alternate output function.
+       (plain_writer_cb): New.
+       (gpgsm_create_writer): New arg STREAM and call plain_writer_cb for
+       binary output to an estream.  Changed call callers.
+
 2007-01-31  Werner Koch  <wk@g10code.com>
 
        * gpgsm.c (main): Let --gen-key print a more informative error
index 0c3ebd1..cc94d4b 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "gpgsm.h"
 
+
 #include <ksba.h>
 
 #include "i18n.h"
@@ -43,6 +44,7 @@
 /* data used by the reader callbacks */
 struct reader_cb_parm_s {
   FILE *fp;
+  
   unsigned char line[1024];
   int linelen;
   int readpos;
@@ -71,7 +73,9 @@ struct reader_cb_parm_s {
 
 /* data used by the writer callbacks */
 struct writer_cb_parm_s {
-  FILE *fp;
+  FILE *fp;            /* FP is only used if STREAM is NULL.  */
+  estream_t stream;    /* Alternative output if not NULL.  */
+
   const char *pem_name;
   
   int wrote_begin;
@@ -400,6 +404,27 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
 
 
 \f
+/* Call either es_putc or the plain putc.  */
+static void
+do_putc (int value, FILE *fp, estream_t stream)
+{
+  if (stream)
+    es_putc (value, stream);
+  else
+    putc (value, fp);
+}
+
+/* Call either es_fputs or the plain fputs.  */
+static void
+do_fputs (const char *string, FILE *fp, estream_t stream)
+{
+  if (stream)
+    es_fputs (string, stream);
+  else
+    fputs (string, fp);
+}
+
+
 static int
 base64_writer_cb (void *cb_value, const void *buffer, size_t count)
 {
@@ -408,6 +433,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
   int i, c, idx, quad_count;
   const unsigned char *p;
   FILE *fp = parm->fp;
+  estream_t stream = parm->stream;
 
   if (!count)
     return 0;
@@ -416,9 +442,9 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
     {
       if (parm->pem_name)
         {
-          fputs ("-----BEGIN ", fp);
-          fputs (parm->pem_name, fp);
-          fputs ("-----\n", fp);
+          do_fputs ("-----BEGIN ", fp, stream);
+          do_fputs (parm->pem_name, fp, stream);
+          do_fputs ("-----\n", fp, stream);
         }
       parm->wrote_begin = 1;
       parm->base64.idx = 0;
@@ -437,16 +463,16 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
         {
           idx = 0;
           c = bintoasc[(*radbuf >> 2) & 077];
-          putc (c, fp);
+          do_putc (c, fp, stream);
           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
-          putc (c, fp);
+          do_putc (c, fp, stream);
           c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
-          putc (c, fp);
+          do_putc (c, fp, stream);
           c = bintoasc[radbuf[2]&077];
-          putc (c, fp);
+          do_putc (c, fp, stream);
           if (++quad_count >= (64/4)) 
             {
-              fputs (LF, fp);
+              do_fputs (LF, fp, stream);
               quad_count = 0;
             }
         }
@@ -456,7 +482,31 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
   parm->base64.idx = idx;
   parm->base64.quad_count = quad_count;
 
-  return ferror (fp) ? gpg_error_from_syserror () : 0;
+  return ((stream? es_ferror (stream) : ferror (fp)) 
+          ? gpg_error_from_syserror () 
+          : 0);
+}
+
+/* This callback is only used in stream mode.  Hiowever, we don't
+   restrict it to this.  */
+static int
+plain_writer_cb (void *cb_value, const void *buffer, size_t count)
+{
+  struct writer_cb_parm_s *parm = cb_value;
+  FILE *fp = parm->fp;
+  estream_t stream = parm->stream;
+
+  if (!count)
+    return 0;
+
+  if (stream)
+    es_write (stream, buffer, count, NULL);
+  else
+    fwrite (buffer, count, 1, fp);
+
+  return ((stream? es_ferror (stream) : ferror (fp)) 
+          ? gpg_error_from_syserror () 
+          : 0);
 }
 
 static int
@@ -465,9 +515,10 @@ base64_finish_write (struct writer_cb_parm_s *parm)
   unsigned char radbuf[4];
   int i, c, idx, quad_count;
   FILE *fp = parm->fp;
+  estream_t stream = parm->stream;
 
   if (!parm->wrote_begin)
-    return 0; /* nothing written */
+    return 0; /* Nothing written or we are not called in base-64 mode. */
 
   /* flush the base64 encoding */
   idx = parm->base64.idx;
@@ -478,40 +529,43 @@ base64_finish_write (struct writer_cb_parm_s *parm)
   if (idx)
     {
       c = bintoasc[(*radbuf>>2)&077];
-      putc (c, fp);
+      do_putc (c, fp, stream);
       if (idx == 1)
         {
           c = bintoasc[((*radbuf << 4) & 060) & 077];
-          putc (c, fp);
-          putc ('=', fp);
-          putc ('=', fp);
+          do_putc (c, fp, stream);
+          do_putc ('=', fp, stream);
+          do_putc ('=', fp, stream);
         }
       else 
         { 
           c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
-          putc (c, fp);
+          do_putc (c, fp, stream);
           c = bintoasc[((radbuf[1] << 2) & 074) & 077];
-          putc (c, fp);
-          putc ('=', fp);
+          do_putc (c, fp, stream);
+          do_putc ('=', fp, stream);
 
         }
       if (++quad_count >= (64/4)) 
         {
-          fputs (LF, fp);
+          do_fputs (LF, fp, stream);
           quad_count = 0;
         }
     }
 
   if (quad_count)
-    fputs (LF, fp);
+    do_fputs (LF, fp, stream);
 
   if (parm->pem_name)
     {
-      fputs ("-----END ", fp);
-      fputs (parm->pem_name, fp);
-      fputs ("-----\n", fp);
+      do_fputs ("-----END ", fp, stream);
+      do_fputs (parm->pem_name, fp, stream);
+      do_fputs ("-----\n", fp, stream);
     }
-  return ferror (fp)? gpg_error (gpg_err_code_from_errno (errno)) : 0;
+
+  return ((stream? es_ferror (stream) : ferror (fp)) 
+          ? gpg_error_from_syserror () 
+          : 0);
 }
 
 
@@ -597,15 +651,16 @@ gpgsm_destroy_reader (Base64Context ctx)
 
 
 \f
-/* Create a writer for the given stream.  Depending on the control
-   information an output encoding is automagically choosen.  The
-   function returns a Base64Context object which must be passed to the
-   gpgme_destroy_writer function.  The created KsbaWriter object is
-   also returned, but the caller must not call the ksba_reader_release
-   function on. */
+/* Create a writer for the given stream FP or STREAM.  Depending on
+   the control information an output encoding is automagically
+   choosen.  The function returns a Base64Context object which must be
+   passed to the gpgme_destroy_writer function.  The created
+   KsbaWriter object is also returned, but the caller must not call
+   the ksba_reader_release function on. */
 int
 gpgsm_create_writer (Base64Context *ctx,
-                     ctrl_t ctrl, FILE *fp, ksba_writer_t *r_writer)
+                     ctrl_t ctrl, FILE *fp, estream_t stream,
+                     ksba_writer_t *r_writer)
 {
   int rc;
   ksba_writer_t w;
@@ -625,11 +680,18 @@ gpgsm_create_writer (Base64Context *ctx,
   if (ctrl->create_pem || ctrl->create_base64)
     {
       (*ctx)->u.wparm.fp = fp;
+      (*ctx)->u.wparm.stream = stream;
       if (ctrl->create_pem)
         (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
                                                  : "CMS OBJECT";
       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
     }
+  else if (stream)
+    {
+      (*ctx)->u.wparm.fp = fp;
+      (*ctx)->u.wparm.stream = stream;
+      rc = ksba_writer_set_cb (w, plain_writer_cb, &(*ctx)->u.wparm);
+    }
   else
     rc = ksba_writer_set_file (w, fp);
 
@@ -655,10 +717,10 @@ gpgsm_finish_writer (Base64Context ctx)
     return gpg_error (GPG_ERR_INV_VALUE);
   parm = &ctx->u.wparm;
   if (parm->did_finish)
-    return 0; /* already done */
+    return 0; /* Already done. */
   parm->did_finish = 1;
-  if (!parm->fp)
-    return 0; /* callback was not used */
+  if (!parm->fp && !parm->stream)
+    return 0; /* Callback was not used.  */
   return base64_finish_write (parm);
 }
 
index 0fafea1..043e218 100644 (file)
@@ -850,7 +850,7 @@ gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp)
     }
 
   ctrl->pem_name = "CERTIFICATE REQUEST";
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
index 48be8a0..baf77d0 100644 (file)
@@ -279,7 +279,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
       goto leave;
     }
 
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
index 907fabc..0969c08 100644 (file)
@@ -364,7 +364,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, FILE *out_fp)
   encparm.fp = data_fp;
 
   ctrl->pem_name = "ENCRYPTED MESSAGE";
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
index dc0820e..a87499f 100644 (file)
@@ -57,7 +57,7 @@ typedef struct duptable_s *duptable_t;
 #define DUPTABLE_SIZE (1 << DUPTABLE_BITS)
 
 
-static void print_short_info (ksba_cert_t cert, FILE *fp);
+static void print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream);
 static gpg_error_t export_p12 (ctrl_t ctrl,
                                const unsigned char *certimg, size_t certimglen,
                                const char *prompt, const char *keygrip,
@@ -127,9 +127,10 @@ insert_duptable (duptable_t *table, unsigned char *fpr, int *exists)
 
 
 
-/* Export all certificates or just those given in NAMES. */
+/* Export all certificates or just those given in NAMES. If STREAM is
+   not NULL the output is send to this extended stream. */
 void
-gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp)
+gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp, estream_t stream)
 {
   KEYDB_HANDLE hd = NULL;
   KEYDB_SEARCH_DESC *desc = NULL;
@@ -257,16 +258,24 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp)
           if (ctrl->create_pem)
             {
               if (count)
+                {
+                  if (stream)
+                    es_putc ('\n', stream);
+                  else
+                    putc ('\n', fp);
+                }
+              print_short_info (cert, fp, stream);
+              if (stream)
+                es_putc ('\n', stream);
+              else
                 putc ('\n', fp);
-              print_short_info (cert, fp);
-              putc ('\n', fp);
             }
           count++;
 
           if (!b64writer)
             {
               ctrl->pem_name = "CERTIFICATE";
-              rc = gpgsm_create_writer (&b64writer, ctrl, fp, &writer);
+              rc = gpgsm_create_writer (&b64writer, ctrl, fp, stream, &writer);
               if (rc)
                 {
                   log_error ("can't create writer: %s\n", gpg_strerror (rc));
@@ -403,12 +412,12 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
 
   if (ctrl->create_pem)
     {
-      print_short_info (cert, fp);
+      print_short_info (cert, fp, NULL);
       putc ('\n', fp);
     }
 
   ctrl->pem_name = "PKCS12";
-  rc = gpgsm_create_writer (&b64writer, ctrl, fp, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, fp, NULL, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
@@ -461,9 +470,30 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
 }
 
 
-/* Print some info about the certifciate CERT to FP */
+/* Call either es_putc or the plain putc.  */
 static void
-print_short_info (ksba_cert_t cert, FILE *fp)
+do_putc (int value, FILE *fp, estream_t stream)
+{
+  if (stream)
+    es_putc (value, stream);
+  else
+    putc (value, fp);
+}
+
+/* Call either es_fputs or the plain fputs.  */
+static void
+do_fputs (const char *string, FILE *fp, estream_t stream)
+{
+  if (stream)
+    es_fputs (string, stream);
+  else
+    fputs (string, fp);
+}
+
+
+/* Print some info about the certifciate CERT to FP or STREAM */
+static void
+print_short_info (ksba_cert_t cert, FILE *fp, estream_t stream)
 {
   char *p;
   ksba_sexp_t sexp;
@@ -471,14 +501,18 @@ print_short_info (ksba_cert_t cert, FILE *fp)
 
   for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
     {
-      fputs (!idx?   "Issuer ...: "
-                 : "\n   aka ...: ", fp); 
-      gpgsm_print_name (fp, p);
+      do_fputs ((!idx
+                 ?   "Issuer ...: "
+                 : "\n   aka ...: "), fp, stream); 
+      if (stream)
+        gpgsm_es_print_name (stream, p);
+      else
+        gpgsm_print_name (fp, p);
       xfree (p);
     }
-  putc ('\n', fp);
+  do_putc ('\n', fp, stream);
 
-  fputs ("Serial ...: ", fp); 
+  do_fputs ("Serial ...: ", fp, stream); 
   sexp = ksba_cert_get_serial (cert);
   if (sexp)
     {
@@ -491,21 +525,29 @@ print_short_info (ksba_cert_t cert, FILE *fp)
           for (len=0; *s && *s != ':' && digitp (s); s++)
             len = len*10 + atoi_1 (s);
           if (*s == ':')
-            for (s++; len; len--, s++)
-              fprintf (fp, "%02X", *s);
+            {
+              if (stream)
+                es_write_hexstring (stream, s+1, len, 0, NULL);
+              else
+                print_hexstring (fp, s+1, len, 0);
+            }
         }
       xfree (sexp);
     }
-  putc ('\n', fp);
+  do_putc ('\n', fp, stream);
 
   for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
     {
-      fputs (!idx?   "Subject ..: "
-                 : "\n    aka ..: ", fp); 
-      gpgsm_print_name (fp, p);
+      do_fputs ((!idx
+                 ?   "Subject ..: "
+                 : "\n    aka ..: "), fp, stream); 
+      if (stream)
+        gpgsm_es_print_name (stream, p);
+      else
+        gpgsm_print_name (fp, p);
       xfree (p);
     }
-  putc ('\n', fp);
+  do_putc ('\n', fp, stream);
 }
 
 
index b71107a..415a7ca 100644 (file)
@@ -1613,7 +1613,7 @@ main ( int argc, char **argv)
 
         for (sl=NULL; argc; argc--, argv++)
           add_to_strlist (&sl, *argv);
-        gpgsm_export (&ctrl, sl, fp);
+        gpgsm_export (&ctrl, sl, fp, NULL);
         free_strlist(sl);
         if (fp != stdout)
           fclose (fp);
index a128374..a52e9e6 100644 (file)
@@ -220,7 +220,8 @@ int  gpgsm_create_reader (Base64Context *ctx,
 int gpgsm_reader_eof_seen (Base64Context ctx);
 void gpgsm_destroy_reader (Base64Context ctx);
 int  gpgsm_create_writer (Base64Context *ctx,
-                          ctrl_t ctrl, FILE *fp, ksba_writer_t *r_writer);
+                          ctrl_t ctrl, FILE *fp, estream_t stream,
+                          ksba_writer_t *r_writer);
 int  gpgsm_finish_writer (Base64Context ctx);
 void gpgsm_destroy_writer (Base64Context ctx);
 
@@ -291,7 +292,7 @@ int gpgsm_import_files (ctrl_t ctrl, int nfiles, char **files,
                         int (*of)(const char *fname));
 
 /*-- export.c --*/
-void gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp);
+void gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp, estream_t stream);
 void gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp);
 
 /*-- delete.c --*/
index dde097e..278f4ec 100644 (file)
@@ -601,8 +601,6 @@ static int
 cmd_export (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
-  int fd = assuan_get_output_fd (ctx);
-  FILE *out_fp;
   char *p;
   strlist_t list, sl;
   int use_data;
@@ -643,16 +641,23 @@ cmd_export (assuan_context_t ctx, char *line)
 
   if (use_data)
     {
-      out_fp = assuan_get_data_fp (ctx);
-      if (!out_fp)
+      estream_t stream;
+
+      stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
+      if (!stream)
         {
           free_strlist (list);
-          return set_error (GPG_ERR_ASS_GENERAL, "no data stream");
+          return set_error (GPG_ERR_ASS_GENERAL, 
+                            "error setting up a data stream");
         }
-      gpgsm_export (ctrl, list, out_fp);
+      gpgsm_export (ctrl, list, NULL, stream);
+      es_fclose (stream);
     }
   else
     {
+      int fd = assuan_get_output_fd (ctx);
+      FILE *out_fp;
+
       if (fd == -1)
         {
           free_strlist (list);
@@ -665,7 +670,7 @@ cmd_export (assuan_context_t ctx, char *line)
           return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
         }
       
-      gpgsm_export (ctrl, list, out_fp);
+      gpgsm_export (ctrl, list, out_fp, NULL);
       fclose (out_fp);
     }
 
index e302873..03ce6a7 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -331,7 +331,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
     }
 
   ctrl->pem_name = "SIGNED MESSAGE";
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
index a34b5b0..ae17d21 100644 (file)
@@ -127,7 +127,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
 
   if (out_fp)
     {
-      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
+      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
       if (rc)
         {
           log_error ("can't create writer: %s\n", gpg_strerror (rc));