From 9e95c2dff6374fea6007711635063d8c1ab4fb2b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 19 Mar 2007 15:44:59 +0000 Subject: [PATCH] Allow export to work on systems without funopen/fopencookie. --- common/ChangeLog | 1 + common/miscellaneous.c | 16 +++++ common/util.h | 2 + sm/ChangeLog | 16 ++++- sm/base64.c | 130 ++++++++++++++++++++++++++++++----------- sm/certreqgen.c | 2 +- sm/decrypt.c | 2 +- sm/encrypt.c | 2 +- sm/export.c | 86 ++++++++++++++++++++------- sm/gpgsm.c | 2 +- sm/gpgsm.h | 5 +- sm/server.c | 19 +++--- sm/sign.c | 2 +- sm/verify.c | 2 +- 14 files changed, 214 insertions(+), 73 deletions(-) diff --git a/common/ChangeLog b/common/ChangeLog index 58695ed35..e42bebfd4 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,5 +1,6 @@ 2007-03-19 Werner Koch + * miscellaneous.c (print_hexstring): New. * estream.c (es_fprintf_unlocked): New. (es_write_sanitized): New. (es_write_hexstring): New. diff --git a/common/miscellaneous.c b/common/miscellaneous.c index 948c8ef48..498c2ab60 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -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 ) { diff --git a/common/util.h b/common/util.h index 324fbb265..2cf6e6cbe 100644 --- a/common/util.h +++ b/common/util.h @@ -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); diff --git a/sm/ChangeLog b/sm/ChangeLog index cb154fcf9..f666af5c3 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,7 +1,7 @@ 2007-03-19 Werner Koch - 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. @@ -20,6 +21,17 @@ (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 * gpgsm.c (main): Let --gen-key print a more informative error diff --git a/sm/base64.c b/sm/base64.c index 0c3ebd150..cc94d4b88 100644 --- a/sm/base64.c +++ b/sm/base64.c @@ -30,6 +30,7 @@ #include "gpgsm.h" + #include #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) +/* 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) -/* 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); } diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 0fafea1ec..043e218c4 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -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)); diff --git a/sm/decrypt.c b/sm/decrypt.c index 48be8a014..baf77d024 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -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)); diff --git a/sm/encrypt.c b/sm/encrypt.c index 907fabc01..0969c082f 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -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)); diff --git a/sm/export.c b/sm/export.c index dc0820e50..a87499f94 100644 --- a/sm/export.c +++ b/sm/export.c @@ -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); } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index b71107a43..415a7cafa 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -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); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index a12837470..a52e9e653 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -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 --*/ diff --git a/sm/server.c b/sm/server.c index dde097e03..278f4ecbf 100644 --- a/sm/server.c +++ b/sm/server.c @@ -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); } diff --git a/sm/sign.c b/sm/sign.c index e30287348..03ce6a754 100644 --- 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)); diff --git a/sm/verify.c b/sm/verify.c index a34b5b05c..ae17d21f3 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -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));