From d9787447fe6a57e39113b60305b4ab672b9ba897 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 9 Feb 2021 16:00:19 +0900 Subject: Imported Upstream version 2.1.19 --- tools/gpg-connect-agent.c | 22 ++-- tools/gpg-wks-client.c | 90 ++++++++++++--- tools/gpg-wks-server.c | 27 ++++- tools/gpg-wks.h | 4 + tools/gpgconf-comp.c | 275 ++++++++++++++++++++++++++-------------------- tools/gpgconf.c | 2 +- tools/gpgparsemail.c | 2 +- tools/gpgtar.c | 4 +- tools/mail-signed-keys | 2 +- tools/mime-parser.c | 25 +++++ tools/mime-parser.h | 2 + tools/symcryptrun.c | 4 +- tools/wks-receive.c | 49 ++++++--- 13 files changed, 330 insertions(+), 178 deletions(-) (limited to 'tools') diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index a5413cf..59e2192 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -187,7 +187,7 @@ static assuan_context_t start_agent (void); -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage( int level ) { @@ -1155,7 +1155,7 @@ main (int argc, char **argv) int rc; int cmderr; const char *opt_run = NULL; - FILE *script_fp = NULL; + gpgrt_stream_t script_fp = NULL; int use_tty, keep_line; struct { int collecting; @@ -1271,7 +1271,7 @@ main (int argc, char **argv) "--tcp-socket", "--raw-socket"); } - if (opt_run && !(script_fp = fopen (opt_run, "r"))) + if (opt_run && !(script_fp = gpgrt_fopen (opt_run, "r"))) { log_error ("cannot open run file '%s': %s\n", opt_run, strerror (errno)); @@ -1425,15 +1425,15 @@ main (int argc, char **argv) linesize = 0; keep_line = 1; } - n = read_line (script_fp? script_fp:stdin, - &line, &linesize, &maxlength); + n = gpgrt_read_line (script_fp ? script_fp : gpgrt_stdin, + &line, &linesize, &maxlength); } if (n < 0) { log_error (_("error reading input: %s\n"), strerror (errno)); if (script_fp) { - fclose (script_fp); + gpgrt_fclose (script_fp); script_fp = NULL; log_error ("stopping script execution\n"); continue; @@ -1445,7 +1445,7 @@ main (int argc, char **argv) /* EOF */ if (script_fp) { - fclose (script_fp); + gpgrt_fclose (script_fp); script_fp = NULL; if (opt.verbose) log_info ("end of script\n"); @@ -1683,17 +1683,17 @@ main (int argc, char **argv) log_error ("syntax error in run command\n"); if (script_fp) { - fclose (script_fp); + gpgrt_fclose (script_fp); script_fp = NULL; } } else if (script_fp) { log_error ("cannot nest run commands - stop\n"); - fclose (script_fp); + gpgrt_fclose (script_fp); script_fp = NULL; } - else if (!(script_fp = fopen (p, "r"))) + else if (!(script_fp = gpgrt_fopen (p, "r"))) { log_error ("cannot open run file '%s': %s\n", p, strerror (errno)); @@ -1864,7 +1864,7 @@ main (int argc, char **argv) if ((rc || cmderr) && script_fp) { log_error ("stopping script execution\n"); - fclose (script_fp); + gpgrt_fclose (script_fp); script_fp = NULL; } diff --git a/tools/gpg-wks-client.c b/tools/gpg-wks-client.c index 5814b40..c31e3a1 100644 --- a/tools/gpg-wks-client.c +++ b/tools/gpg-wks-client.c @@ -129,7 +129,7 @@ static gpg_error_t command_receive_cb (void *opaque, -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage( int level ) { @@ -373,6 +373,7 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) log_error ("error allocating memory buffer: %s\n", gpg_strerror (err)); goto leave; } + /* Prefix the key with the MIME content type. */ es_fputs ("Content-Type: application/pgp-keys\n" "\n", key); @@ -437,20 +438,38 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec) +struct decrypt_stream_parm_s +{ + char *fpr; + char *mainfpr; + int otrust; +}; + static void decrypt_stream_status_cb (void *opaque, const char *keyword, char *args) { - (void)opaque; + struct decrypt_stream_parm_s *decinfo = opaque; if (DBG_CRYPTO) log_debug ("gpg status: %s %s\n", keyword, args); -} + if (!strcmp (keyword, "DECRYPTION_KEY") && !decinfo->fpr) + { + char *fields[3]; + if (split_fields (args, fields, DIM (fields)) >= 3) + { + decinfo->fpr = xstrdup (fields[0]); + decinfo->mainfpr = xstrdup (fields[1]); + decinfo->otrust = *fields[2]; + } + } +} /* Decrypt the INPUT stream to a new stream which is stored at success * at R_OUTPUT. */ static gpg_error_t -decrypt_stream (estream_t *r_output, estream_t input) +decrypt_stream (estream_t *r_output, struct decrypt_stream_parm_s *decinfo, + estream_t input) { gpg_error_t err; ccparray_t ccp; @@ -458,6 +477,7 @@ decrypt_stream (estream_t *r_output, estream_t input) estream_t output; *r_output = NULL; + memset (decinfo, 0, sizeof *decinfo); output = es_fopenmem (0, "w+b"); if (!output) @@ -492,7 +512,9 @@ decrypt_stream (estream_t *r_output, estream_t input) } err = gnupg_exec_tool_stream (opt.gpg_program, argv, input, NULL, output, - decrypt_stream_status_cb, NULL); + decrypt_stream_status_cb, decinfo); + if (!err && (!decinfo->fpr || !decinfo->mainfpr || !decinfo->otrust)) + err = gpg_error (GPG_ERR_INV_ENGINE); if (err) { log_error ("decryption failed: %s\n", gpg_strerror (err)); @@ -506,6 +528,12 @@ decrypt_stream (estream_t *r_output, estream_t input) output = NULL; leave: + if (err) + { + xfree (decinfo->fpr); + xfree (decinfo->mainfpr); + memset (decinfo, 0, sizeof *decinfo); + } es_fclose (output); xfree (argv); return err; @@ -749,8 +777,9 @@ command_send (const char *fingerprint, char *userid) if (err) goto leave; - /* Tell server that we support draft version 3. */ - err = mime_maker_add_header (mime, "Wks-Draft-Version", "3"); + /* Tell server which draft we support. */ + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); if (err) goto leave; @@ -948,6 +977,10 @@ send_confirmation_response (const char *sender, const char *address, err = mime_maker_add_header (mime, "Subject", "Key publication confirmation"); if (err) goto leave; + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); + if (err) + goto leave; if (encrypt) { @@ -998,9 +1031,11 @@ send_confirmation_response (const char *sender, const char *address, /* Reply to a confirmation request. The MSG has already been - * decrypted and we only need to send the nonce back. */ + * decrypted and we only need to send the nonce back. MAINFPR is + * either NULL or the primary key fingerprint of the key used to + * decrypt the request. */ static gpg_error_t -process_confirmation_request (estream_t msg) +process_confirmation_request (estream_t msg, const char *mainfpr) { gpg_error_t err; nvc_t nvc; @@ -1044,8 +1079,20 @@ process_confirmation_request (estream_t msg) } fingerprint = value; - /* FIXME: Check that the fingerprint matches the key used to decrypt the - * message. */ + /* Check that the fingerprint matches the key used to decrypt the + * message. In --read mode or with the old format we don't have the + * decryption key; thus we can't bail out. */ + if (!mainfpr || ascii_strcasecmp (mainfpr, fingerprint)) + { + log_info ("target fingerprint: %s\n", fingerprint); + log_info ("but decrypted with: %s\n", mainfpr); + log_error ("confirmation request not decrypted with target key\n"); + if (mainfpr) + { + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + } /* Get the address. */ if (!((item = nvc_lookup (nvc, "address:")) && (value = nve_value (item)) @@ -1058,10 +1105,7 @@ process_confirmation_request (estream_t msg) } address = value; /* FIXME: Check that the "address" matches the User ID we want to - * publish. Also get the "fingerprint" and compare that to our to - * be published key. Further we should make sure that we actually - * decrypted using that fingerprint (which is a bit problematic if - * --read is used). */ + * publish. */ /* Get the sender. */ if (!((item = nvc_lookup (nvc, "sender:")) && (value = nve_value (item)) @@ -1130,14 +1174,24 @@ read_confirmation_request (estream_t msg) } if (c != '-') - err = process_confirmation_request (msg); + err = process_confirmation_request (msg, NULL); else { - err = decrypt_stream (&plaintext, msg); + struct decrypt_stream_parm_s decinfo; + + err = decrypt_stream (&plaintext, &decinfo, msg); if (err) log_error ("decryption failed: %s\n", gpg_strerror (err)); + else if (decinfo.otrust != 'u') + { + err = gpg_error (GPG_ERR_WRONG_SECKEY); + log_error ("key used to decrypt the confirmation request" + " was not generated by us\n"); + } else - err = process_confirmation_request (plaintext); + err = process_confirmation_request (plaintext, decinfo.mainfpr); + xfree (decinfo.fpr); + xfree (decinfo.mainfpr); } es_fclose (plaintext); diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c index 1a91858..0376cce 100644 --- a/tools/gpg-wks-server.c +++ b/tools/gpg-wks-server.c @@ -133,7 +133,7 @@ static gpg_error_t command_cron (void); -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage( int level ) { @@ -915,6 +915,18 @@ send_confirmation_request (server_ctx_t ctx, err = mime_maker_add_header (mime, "Subject", "Confirm your key publication"); if (err) goto leave; + + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); + if (err) + goto leave; + + /* Help Enigmail to identify messages. Note that this is in no way + * secured. */ + err = mime_maker_add_header (mime, "WKS-Phase", "confirm"); + if (err) + goto leave; + for (sl = opt.extra_headers; sl; sl = sl->next) { err = mime_maker_add_header (mime, sl->d, NULL); @@ -1008,7 +1020,7 @@ send_confirmation_request (server_ctx_t ctx, if (err) goto leave; - mime_maker_dump_tree (mime); + /* mime_maker_dump_tree (mime); */ err = mime_maker_get_part (mime, partid, &signeddata); if (err) goto leave; @@ -1098,7 +1110,7 @@ process_new_key (server_ctx_t ctx, estream_t key) if (policybuf.auth_submit) { - /* Bypass the confirmation stuff and publish the the key as is. */ + /* Bypass the confirmation stuff and publish the key as is. */ log_info ("publishing address '%s'\n", sl->d); /* FIXME: We need to make sure that we do this only for the * address in the mail. */ @@ -1204,6 +1216,13 @@ send_congratulation_message (const char *mbox, const char *keyfile) if (err) goto leave; err = mime_maker_add_header (mime, "Subject", "Your key has been published"); + if (err) + goto leave; + err = mime_maker_add_header (mime, "Wks-Draft-Version", + STR2(WKS_DRAFT_VERSION)); + if (err) + goto leave; + err = mime_maker_add_header (mime, "WKS-Phase", "done"); if (err) goto leave; for (sl = opt.extra_headers; sl; sl = sl->next) @@ -1515,7 +1534,7 @@ command_receive_cb (void *opaque, const char *mediatype, /* Return a list of all configured domains. ECh list element is the - * top directory for for the domain. To figure out the actual domain + * top directory for the domain. To figure out the actual domain * name strrchr(name, '/') can be used. */ static gpg_error_t get_domain_list (strlist_t *r_list) diff --git a/tools/gpg-wks.h b/tools/gpg-wks.h index 62ceb34..3b28af4 100644 --- a/tools/gpg-wks.h +++ b/tools/gpg-wks.h @@ -24,6 +24,10 @@ #include "../common/strlist.h" #include "mime-maker.h" +/* The draft version we implement. */ +#define WKS_DRAFT_VERSION 3 + + /* We keep all global options in the structure OPT. */ struct { diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index a25b513..d53947e 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -47,6 +47,7 @@ #include "util.h" #include "i18n.h" #include "exechelp.h" +#include "sysutils.h" #include "gc-opt-flags.h" #include "gpgconf.h" @@ -716,6 +717,10 @@ static gc_option_t gc_options_gpg[] = (GC_OPT_FLAG_ARG_OPT|GC_OPT_FLAG_NO_CHANGE), GC_LEVEL_INVISIBLE, NULL, NULL, GC_ARG_TYPE_STRING, GC_BACKEND_GPG }, + { "trust-model", + GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, + NULL, NULL, + GC_ARG_TYPE_STRING, GC_BACKEND_GPG }, { "Debug", @@ -743,6 +748,8 @@ static gc_option_t gc_options_gpg[] = { "auto-key-locate", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, "gnupg", N_("|MECHANISMS|use MECHANISMS to locate keys by mail address"), GC_ARG_TYPE_STRING, GC_BACKEND_GPG }, + { "auto-key-retrieve", GC_OPT_FLAG_NONE, GC_LEVEL_INVISIBLE, + NULL, NULL, GC_ARG_TYPE_NONE, GC_BACKEND_GPG }, GC_OPTION_NULL @@ -2163,8 +2170,11 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend) config = es_fopen (config_filename, "r"); if (!config) - gc_error (0, errno, "warning: can not open config file %s", - config_filename); + { + if (errno != ENOENT) + gc_error (0, errno, "warning: can not open config file %s", + config_filename); + } else { while ((length = es_read_line (config, &line, &line_len, NULL)) > 0) @@ -2265,7 +2275,7 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend) gc_option_t *list_option; gc_option_t *config_option; char *list_filename; - FILE *list_file; + gpgrt_stream_t list_file; char *line = NULL; size_t line_len = 0; ssize_t length; @@ -2277,13 +2287,13 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend) assert (!list_option->active); list_filename = get_config_filename (component, backend); - list_file = fopen (list_filename, "r"); + list_file = gpgrt_fopen (list_filename, "r"); if (!list_file) gc_error (0, errno, "warning: can not open list file %s", list_filename); else { - while ((length = read_line (list_file, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (list_file, &line, &line_len, NULL)) > 0) { char *start; char *end; @@ -2316,7 +2326,7 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend) else list = xasprintf ("\"%s", gc_percent_escape (start)); } - if (length < 0 || ferror (list_file)) + if (length < 0 || gpgrt_ferror (list_file)) gc_error (1, errno, "can not read list file %s", list_filename); } @@ -2329,7 +2339,7 @@ retrieve_options_from_file (gc_component_t component, gc_backend_t backend) if (config_option->flags & GC_OPT_FLAG_NO_CHANGE) list_option->flags |= GC_OPT_FLAG_NO_CHANGE; - if (list_file && fclose (list_file)) + if (list_file && gpgrt_fclose (list_file)) gc_error (1, errno, "error closing %s", list_filename); xfree (line); } @@ -2515,7 +2525,6 @@ option_check_validity (gc_option_t *option, unsigned long flags, while (arg && *arg); } - #ifdef HAVE_W32_SYSTEM int copy_file (const char *src_name, const char *dst_name) @@ -2523,18 +2532,18 @@ copy_file (const char *src_name, const char *dst_name) #define BUF_LEN 4096 char buffer[BUF_LEN]; int len; - FILE *src; - FILE *dst; + gpgrt_stream_t src; + gpgrt_stream_t dst; - src = fopen (src_name, "r"); + src = gpgrt_fopen (src_name, "r"); if (src == NULL) return -1; - dst = fopen (dst_name, "w"); + dst = gpgrt_fopen (dst_name, "w"); if (dst == NULL) { int saved_err = errno; - fclose (src); + gpgrt_fclose (src); gpg_err_set_errno (saved_err); return -1; } @@ -2543,28 +2552,28 @@ copy_file (const char *src_name, const char *dst_name) { int written; - len = fread (buffer, 1, BUF_LEN, src); + len = gpgrt_fread (buffer, 1, BUF_LEN, src); if (len == 0) break; - written = fwrite (buffer, 1, len, dst); + written = gpgrt_fwrite (buffer, 1, len, dst); if (written != len) break; } - while (!feof (src) && !ferror (src) && !ferror (dst)); + while (! gpgrt_feof (src) && ! gpgrt_ferror (src) && ! gpgrt_ferror (dst)); - if (ferror (src) || ferror (dst) || !feof (src)) + if (gpgrt_ferror (src) || gpgrt_ferror (dst) || ! gpgrt_feof (src)) { int saved_errno = errno; - fclose (src); - fclose (dst); + gpgrt_fclose (src); + gpgrt_fclose (dst); unlink (dst_name); gpg_err_set_errno (saved_errno); return -1; } - if (fclose (dst)) + if (gpgrt_fclose (dst)) gc_error (1, errno, "error closing %s", dst_name); - if (fclose (src)) + if (gpgrt_fclose (src)) gc_error (1, errno, "error closing %s", src_name); return 0; @@ -2573,7 +2582,20 @@ copy_file (const char *src_name, const char *dst_name) /* Create and verify the new configuration file for the specified - backend and component. Returns 0 on success and -1 on error. */ + * backend and component. Returns 0 on success and -1 on error. This + * function may store pointers to malloced strings in SRC_FILENAMEP, + * DEST_FILENAMEP, and ORIG_FILENAMEP. Those must be freed by the + * caller. The strings refer to three versions of the configuration + * file: + * + * SRC_FILENAME: The updated configuration is written to this file. + * DEST_FILENAME: Name of the configuration file read by the + * component. + * ORIG_FILENAME: A backup of the previous configuration file. + * + * To apply the configuration change, rename SRC_FILENAME to + * DEST_FILENAME. To revert to the previous configuration, rename + * ORIG_FILENAME to DEST_FILENAME. */ static int change_options_file (gc_component_t component, gc_backend_t backend, char **src_filenamep, char **dest_filenamep, @@ -2588,8 +2610,8 @@ change_options_file (gc_component_t component, gc_backend_t backend, ssize_t length; int res; int fd; - FILE *src_file = NULL; - FILE *dest_file = NULL; + gpgrt_stream_t src_file = NULL; + gpgrt_stream_t dest_file = NULL; char *src_filename; char *dest_filename; char *orig_filename; @@ -2641,6 +2663,8 @@ change_options_file (gc_component_t component, gc_backend_t backend, if (res < 0 && errno != ENOENT) { xfree (dest_filename); + xfree (src_filename); + xfree (orig_filename); return -1; } if (res < 0) @@ -2659,7 +2683,7 @@ change_options_file (gc_component_t component, gc_backend_t backend, fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644); if (fd < 0) return -1; - src_file = fdopen (fd, "w"); + src_file = gpgrt_fdopen (fd, "w"); res = errno; if (!src_file) { @@ -2673,11 +2697,11 @@ change_options_file (gc_component_t component, gc_backend_t backend, process. */ if (orig_filename) { - dest_file = fopen (dest_filename, "r"); + dest_file = gpgrt_fopen (dest_filename, "r"); if (!dest_file) goto change_file_one_err; - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0) { int disable = 0; char *start; @@ -2748,24 +2772,24 @@ change_options_file (gc_component_t component, gc_backend_t backend, { if (!in_marker) { - fprintf (src_file, + gpgrt_fprintf (src_file, "# %s disabled this option here at %s\n", GPGCONF_DISP_NAME, asctimestamp (gnupg_get_time ())); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_file_one_err; - fprintf (src_file, "# %s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "# %s", line); + if (gpgrt_ferror (src_file)) goto change_file_one_err; } } else { - fprintf (src_file, "%s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s", line); + if (gpgrt_ferror (src_file)) goto change_file_one_err; } } - if (length < 0 || ferror (dest_file)) + if (length < 0 || gpgrt_ferror (dest_file)) goto change_file_one_err; } @@ -2776,8 +2800,8 @@ change_options_file (gc_component_t component, gc_backend_t backend, proceed. Note that we first write a newline, this guards us against files which lack the newline at the end of the last line, while it doesn't hurt us in all other cases. */ - fprintf (src_file, "\n%s\n", marker); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "\n%s\n", marker); + if (gpgrt_ferror (src_file)) goto change_file_one_err; } @@ -2787,7 +2811,7 @@ change_options_file (gc_component_t component, gc_backend_t backend, followed by the rest of the original file. */ while (cur_arg) { - fprintf (src_file, "%s\n", cur_arg); + gpgrt_fprintf (src_file, "%s\n", cur_arg); /* Find next argument. */ if (arg) @@ -2812,52 +2836,52 @@ change_options_file (gc_component_t component, gc_backend_t backend, cur_arg = NULL; } - fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ())); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ())); + if (gpgrt_ferror (src_file)) goto change_file_one_err; if (!in_marker) { - fprintf (src_file, "# %s edited this configuration file.\n", + gpgrt_fprintf (src_file, "# %s edited this configuration file.\n", GPGCONF_DISP_NAME); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_file_one_err; - fprintf (src_file, "# It will disable options before this marked " + gpgrt_fprintf (src_file, "# It will disable options before this marked " "block, but it will\n"); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_file_one_err; - fprintf (src_file, "# never change anything below these lines.\n"); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "# never change anything below these lines.\n"); + if (gpgrt_ferror (src_file)) goto change_file_one_err; } if (dest_file) { - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0) { - fprintf (src_file, "%s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s", line); + if (gpgrt_ferror (src_file)) goto change_file_one_err; } - if (length < 0 || ferror (dest_file)) + if (length < 0 || gpgrt_ferror (dest_file)) goto change_file_one_err; } xfree (line); line = NULL; - res = fclose (src_file); + res = gpgrt_fclose (src_file); if (res) { res = errno; close (fd); if (dest_file) - fclose (dest_file); + gpgrt_fclose (dest_file); gpg_err_set_errno (res); return -1; } close (fd); if (dest_file) { - res = fclose (dest_file); + res = gpgrt_fclose (dest_file); if (res) return -1; } @@ -2868,11 +2892,11 @@ change_options_file (gc_component_t component, gc_backend_t backend, res = errno; if (src_file) { - fclose (src_file); + gpgrt_fclose (src_file); close (fd); } if (dest_file) - fclose (dest_file); + gpgrt_fclose (dest_file); gpg_err_set_errno (res); return -1; } @@ -2880,7 +2904,19 @@ change_options_file (gc_component_t component, gc_backend_t backend, /* Create and verify the new configuration file for the specified * backend and component. Returns 0 on success and -1 on error. If - * VERBATIM is set the profile mode is used. */ + * VERBATIM is set the profile mode is used. This function may store + * pointers to malloced strings in SRC_FILENAMEP, DEST_FILENAMEP, and + * ORIG_FILENAMEP. Those must be freed by the caller. The strings + * refer to three versions of the configuration file: + * + * SRC_FILENAME: The updated configuration is written to this file. + * DEST_FILENAME: Name of the configuration file read by the + * component. + * ORIG_FILENAME: A backup of the previous configuration file. + * + * To apply the configuration change, rename SRC_FILENAME to + * DEST_FILENAME. To revert to the previous configuration, rename + * ORIG_FILENAME to DEST_FILENAME. */ static int change_options_program (gc_component_t component, gc_backend_t backend, char **src_filenamep, char **dest_filenamep, @@ -2896,8 +2932,8 @@ change_options_program (gc_component_t component, gc_backend_t backend, ssize_t length; int res; int fd; - FILE *src_file = NULL; - FILE *dest_file = NULL; + gpgrt_stream_t src_file = NULL; + gpgrt_stream_t dest_file = NULL; char *src_filename; char *dest_filename; char *orig_filename; @@ -2939,7 +2975,7 @@ change_options_program (gc_component_t component, gc_backend_t backend, fd = open (src_filename, O_CREAT | O_EXCL | O_WRONLY, 0644); if (fd < 0) return -1; - src_file = fdopen (fd, "w"); + src_file = gpgrt_fdopen (fd, "w"); res = errno; if (!src_file) { @@ -2953,11 +2989,11 @@ change_options_program (gc_component_t component, gc_backend_t backend, process. */ if (orig_filename) { - dest_file = fopen (dest_filename, "r"); + dest_file = gpgrt_fopen (dest_filename, "r"); if (!dest_file) goto change_one_err; - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0) { int disable = 0; char *start; @@ -3004,24 +3040,24 @@ change_options_program (gc_component_t component, gc_backend_t backend, { if (!in_marker) { - fprintf (src_file, + gpgrt_fprintf (src_file, "# %s disabled this option here at %s\n", GPGCONF_DISP_NAME, asctimestamp (gnupg_get_time ())); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_one_err; - fprintf (src_file, "# %s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "# %s", line); + if (gpgrt_ferror (src_file)) goto change_one_err; } } else { - fprintf (src_file, "%s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s", line); + if (gpgrt_ferror (src_file)) goto change_one_err; } } - if (length < 0 || ferror (dest_file)) + if (length < 0 || gpgrt_ferror (dest_file)) goto change_one_err; } @@ -3032,8 +3068,8 @@ change_options_program (gc_component_t component, gc_backend_t backend, proceed. Note that we first write a newline, this guards us against files which lack the newline at the end of the last line, while it doesn't hurt us in all other cases. */ - fprintf (src_file, "\n%s\n", marker); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "\n%s\n", marker); + if (gpgrt_ferror (src_file)) goto change_one_err; } /* At this point, we have copied everything up to the end marker @@ -3044,7 +3080,7 @@ change_options_program (gc_component_t component, gc_backend_t backend, /* We have to turn on UTF8 strings for GnuPG. */ if (backend == GC_BACKEND_GPG && ! utf8strings_seen) - fprintf (src_file, "utf8-strings\n"); + gpgrt_fprintf (src_file, "utf8-strings\n"); option = gc_component[component].options; while (option->name) @@ -3059,16 +3095,16 @@ change_options_program (gc_component_t component, gc_backend_t backend, { if (*arg == '\0' || *arg == ',') { - fprintf (src_file, "%s\n", option->name); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s\n", option->name); + if (gpgrt_ferror (src_file)) goto change_one_err; } else if (gc_arg_type[option->arg_type].fallback == GC_ARG_TYPE_NONE) { assert (*arg == '1'); - fprintf (src_file, "%s\n", option->name); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s\n", option->name); + if (gpgrt_ferror (src_file)) goto change_one_err; arg++; @@ -3090,9 +3126,9 @@ change_options_program (gc_component_t component, gc_backend_t backend, else end = NULL; - fprintf (src_file, "%s %s\n", option->name, + gpgrt_fprintf (src_file, "%s %s\n", option->name, verbatim? arg : percent_deescape (arg)); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_one_err; if (end) @@ -3107,8 +3143,8 @@ change_options_program (gc_component_t component, gc_backend_t backend, if (end) *end = '\0'; - fprintf (src_file, "%s %s\n", option->name, arg); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s %s\n", option->name, arg); + if (gpgrt_ferror (src_file)) goto change_one_err; if (end) @@ -3125,52 +3161,52 @@ change_options_program (gc_component_t component, gc_backend_t backend, option++; } - fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ())); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s %s\n", marker, asctimestamp (gnupg_get_time ())); + if (gpgrt_ferror (src_file)) goto change_one_err; if (!in_marker) { - fprintf (src_file, "# %s edited this configuration file.\n", + gpgrt_fprintf (src_file, "# %s edited this configuration file.\n", GPGCONF_DISP_NAME); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_one_err; - fprintf (src_file, "# It will disable options before this marked " + gpgrt_fprintf (src_file, "# It will disable options before this marked " "block, but it will\n"); - if (ferror (src_file)) + if (gpgrt_ferror (src_file)) goto change_one_err; - fprintf (src_file, "# never change anything below these lines.\n"); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "# never change anything below these lines.\n"); + if (gpgrt_ferror (src_file)) goto change_one_err; } if (dest_file) { - while ((length = read_line (dest_file, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (dest_file, &line, &line_len, NULL)) > 0) { - fprintf (src_file, "%s", line); - if (ferror (src_file)) + gpgrt_fprintf (src_file, "%s", line); + if (gpgrt_ferror (src_file)) goto change_one_err; } - if (length < 0 || ferror (dest_file)) + if (length < 0 || gpgrt_ferror (dest_file)) goto change_one_err; } xfree (line); line = NULL; - res = fclose (src_file); + res = gpgrt_fclose (src_file); if (res) { res = errno; close (fd); if (dest_file) - fclose (dest_file); + gpgrt_fclose (dest_file); gpg_err_set_errno (res); return -1; } close (fd); if (dest_file) { - res = fclose (dest_file); + res = gpgrt_fclose (dest_file); if (res) return -1; } @@ -3181,11 +3217,11 @@ change_options_program (gc_component_t component, gc_backend_t backend, res = errno; if (src_file) { - fclose (src_file); + gpgrt_fclose (src_file); close (fd); } if (dest_file) - fclose (dest_file); + gpgrt_fclose (dest_file); gpg_err_set_errno (res); return -1; } @@ -3240,6 +3276,7 @@ gc_component_change_options (int component, estream_t in, estream_t out, int verbatim) { int err = 0; + int block = 0; int runtime[GC_BACKEND_NR]; char *src_filename[GC_BACKEND_NR]; char *dest_filename[GC_BACKEND_NR]; @@ -3326,6 +3363,8 @@ gc_component_change_options (int component, estream_t in, estream_t out, change_one_value (option, runtime, flags, new_value, 0); } + if (length < 0 || gpgrt_ferror (in)) + gc_error (1, errno, "error reading stream 'in'"); } /* Now that we have collected and locally verified the changes, @@ -3377,6 +3416,14 @@ gc_component_change_options (int component, estream_t in, estream_t out, option++; } + /* We are trying to atomically commit all changes. Unfortunately, + we cannot rely on gnupg_rename_file to manage the signals for us, + doing so would require us to pass NULL as BLOCK to any subsequent + call to it. Instead, we just manage the signal handling + manually. */ + block = 1; + gnupg_block_all_signals (); + if (! err && ! opt.dry_run) { int i; @@ -3390,20 +3437,13 @@ gc_component_change_options (int component, estream_t in, estream_t out, assert (dest_filename[i]); if (orig_filename[i]) - { -#ifdef HAVE_W32_SYSTEM - /* There is no atomic update on W32. */ - err = unlink (dest_filename[i]); -#endif /* HAVE_W32_SYSTEM */ - if (!err) - err = rename (src_filename[i], dest_filename[i]); - } + err = gnupg_rename_file (src_filename[i], dest_filename[i], NULL); else { #ifdef HAVE_W32_SYSTEM /* We skip the unlink if we expect the file not to be there. */ - err = rename (src_filename[i], dest_filename[i]); + err = gnupg_rename_file (src_filename[i], dest_filename[i], NULL); #else /* HAVE_W32_SYSTEM */ /* This is a bit safer than rename() because we expect DEST_FILENAME not to be there. If it @@ -3443,13 +3483,7 @@ gc_component_change_options (int component, estream_t in, estream_t out, a version of the file that is even newer than the one we just installed. */ if (orig_filename[i]) - { -#ifdef HAVE_W32_SYSTEM - /* There is no atomic update on W32. */ - unlink (dest_filename[i]); -#endif /* HAVE_W32_SYSTEM */ - rename (orig_filename[i], dest_filename[i]); - } + gnupg_rename_file (orig_filename[i], dest_filename[i], NULL); else unlink (dest_filename[i]); } @@ -3479,16 +3513,13 @@ gc_component_change_options (int component, estream_t in, estream_t out, backup_filename = xasprintf ("%s.%s.bak", dest_filename[backend], GPGCONF_NAME); - -#ifdef HAVE_W32_SYSTEM - /* There is no atomic update on W32. */ - unlink (backup_filename); -#endif /* HAVE_W32_SYSTEM */ - rename (orig_filename[backend], backup_filename); + gnupg_rename_file (orig_filename[backend], backup_filename, NULL); xfree (backup_filename); } leave: + if (block) + gnupg_unblock_all_signals (); xfree (line); for (backend = 0; backend < GC_BACKEND_NR; backend++) { @@ -3623,7 +3654,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, char *line = NULL; size_t line_len = 0; ssize_t length; - FILE *config; + gpgrt_stream_t config; int lineno = 0; int in_rule = 0; int got_match = 0; @@ -3640,7 +3671,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, for (backend_id = 0; backend_id < GC_BACKEND_NR; backend_id++) runtime[backend_id] = 0; - config = fopen (fname, "r"); + config = gpgrt_fopen (fname, "r"); if (!config) { /* Do not print an error if the file is not available, except @@ -3654,7 +3685,7 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, return result; } - while ((length = read_line (config, &line, &line_len, NULL)) > 0) + while ((length = gpgrt_read_line (config, &line, &line_len, NULL)) > 0) { char *key, *component, *option, *flags, *value; char *empty; @@ -3880,12 +3911,12 @@ gc_process_gpgconf_conf (const char *fname_arg, int update, int defaults, } } - if (length < 0 || ferror (config)) + if (length < 0 || gpgrt_ferror (config)) { gc_error (0, errno, "error reading from '%s'", fname); result = -1; } - if (fclose (config)) + if (gpgrt_fclose (config)) gc_error (0, errno, "error closing '%s'", fname); xfree (line); diff --git a/tools/gpgconf.c b/tools/gpgconf.c index a5ee188..a9f4607 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -109,7 +109,7 @@ static ARGPARSE_OPTS opts[] = }; -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage( int level ) { diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c index 8c9c4d4..b122097 100644 --- a/tools/gpgparsemail.c +++ b/tools/gpgparsemail.c @@ -463,7 +463,7 @@ show_event (rfc822parse_event_t event) /* This function is called by the parser to communicate events. This callback comminucates with the main program using a structure - passed in OPAQUE. Should retrun 0 or set errno and return -1. */ + passed in OPAQUE. Should return 0 or set errno and return -1. */ static int message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) { diff --git a/tools/gpgtar.c b/tools/gpgtar.c index 23176dc..3dff176 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -137,7 +137,7 @@ static ARGPARSE_OPTS tar_opts[] = { -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage( int level ) { @@ -507,7 +507,7 @@ main (int argc, char **argv) /* Read the next record from STREAM. RECORD is a buffer provided by the caller and must be at leadt of size RECORDSIZE. The function - return 0 on success and and error code on failure; a diagnostic + return 0 on success and error code on failure; a diagnostic printed as well. Note that there is no need for an EOF indicator because a tarball has an explicit EOF record. */ gpg_error_t diff --git a/tools/mail-signed-keys b/tools/mail-signed-keys index c63001a..3c564f1 100755 --- a/tools/mail-signed-keys +++ b/tools/mail-signed-keys @@ -41,7 +41,7 @@ if [ -z "$signedby" ]; then fi if [ "$dryrun" = "0" ]; then - echo "About to send the the keys signed by $signedby" >&2 + echo "About to send the keys signed by $signedby" >&2 echo -n "to their owners. Do you really want to do this? (y/N)" >&2 read [ "$REPLY" != "y" -a "$REPLY" != "Y" ] && exit 0 diff --git a/tools/mime-parser.c b/tools/mime-parser.c index 264353c..169ea2b 100644 --- a/tools/mime-parser.c +++ b/tools/mime-parser.c @@ -49,6 +49,9 @@ struct mime_parser_context_s { void *cookie; /* Cookie passed to all callbacks. */ + /* The callback to announce the transation from header to body. */ + gpg_error_t (*t2body) (void *cookie, int level); + /* The callback to announce a new part. */ gpg_error_t (*new_part) (void *cookie, const char *mediatype, @@ -224,6 +227,14 @@ parse_message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) ctx->want_part = 0; ctx->decode_part = 0; + + if (ctx->t2body) + { + rc = ctx->t2body (ctx->cookie, ctx->nesting_level); + if (rc) + goto t2body_leave; + } + field = rfc822parse_parse_field (msg, "Content-Type", -1); if (field) { @@ -412,6 +423,7 @@ parse_message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) } } + t2body_leave: ctx->show.header = 0; ctx->show.data = 1; ctx->show.n_skip = 1; @@ -541,6 +553,19 @@ mime_parser_set_verbose (mime_parser_t ctx, int level) } +/* Set a callback for the transition from header to body. LEVEL is + * the current nesting level, starting with 0. This callback can be + * used to evaluate headers before any other action is done. Note + * that if a new NEW_PART callback needs to be called it is done after + * this T2BODY callback. */ +void +mime_parser_set_t2body (mime_parser_t ctx, + gpg_error_t (*fnc) (void *cookie, int level)) +{ + ctx->t2body = fnc; +} + + /* Set the callback used to announce a new part. It will be called * with the media type and media subtype of the part. If no * Content-type header was given both values are the empty string. diff --git a/tools/mime-parser.h b/tools/mime-parser.h index 37a74a1..b9bb465 100644 --- a/tools/mime-parser.h +++ b/tools/mime-parser.h @@ -27,6 +27,8 @@ gpg_error_t mime_parser_new (mime_parser_t *r_ctx, void *cookie); void mime_parser_release (mime_parser_t ctx); void mime_parser_set_verbose (mime_parser_t ctx, int level); +void mime_parser_set_t2body (mime_parser_t ctx, + gpg_error_t (*fnc) (void *cookie, int level)); void mime_parser_set_new_part (mime_parser_t ctx, gpg_error_t (*fnc) (void *cookie, const char *mediatype, diff --git a/tools/symcryptrun.c b/tools/symcryptrun.c index dc680f5..a72b9cf 100644 --- a/tools/symcryptrun.c +++ b/tools/symcryptrun.c @@ -191,7 +191,7 @@ struct } opt; -/* Print usage information and and provide strings for help. */ +/* Print usage information and provide strings for help. */ static const char * my_strusage (int level) { @@ -997,7 +997,7 @@ main (int argc, char **argv) setup_libgcrypt_logging (); gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); - /* Tell simple-pwquery about the the standard socket name. */ + /* Tell simple-pwquery about the standard socket name. */ { char *tmp = make_filename (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL); simple_pw_set_socket (tmp); diff --git a/tools/wks-receive.c b/tools/wks-receive.c index 12ec089..94f8bc6 100644 --- a/tools/wks-receive.c +++ b/tools/wks-receive.c @@ -255,6 +255,38 @@ collect_signature (void *cookie, const char *data) } +/* The callback for the transition from header to body. We use it to + * look at some header values. */ +static gpg_error_t +t2body (void *cookie, int level) +{ + receive_ctx_t ctx = cookie; + rfc822parse_t msg; + char *value; + size_t valueoff; + + log_info ("t2body for level %d\n", level); + if (!level) + { + /* This is the outermost header. */ + msg = mime_parser_rfc822parser (ctx->parser); + if (msg) + { + value = rfc822parse_get_field (msg, "Wks-Draft-Version", + -1, &valueoff); + if (value) + { + if (atoi(value+valueoff) >= 2 ) + ctx->draft_version_2 = 1; + free (value); + } + } + } + + return 0; +} + + static gpg_error_t new_part (void *cookie, const char *mediatype, const char *mediasubtype) { @@ -275,22 +307,6 @@ new_part (void *cookie, const char *mediatype, const char *mediasubtype) } else { - rfc822parse_t msg = mime_parser_rfc822parser (ctx->parser); - if (msg) - { - char *value; - size_t valueoff; - - value = rfc822parse_get_field (msg, "Wks-Draft-Version", - -1, &valueoff); - if (value) - { - if (atoi(value+valueoff) >= 2 ) - ctx->draft_version_2 = 1; - free (value); - } - } - ctx->key_data = es_fopenmem (0, "w+b"); if (!ctx->key_data) { @@ -413,6 +429,7 @@ wks_receive (estream_t fp, goto leave; if (DBG_PARSER) mime_parser_set_verbose (parser, 1); + mime_parser_set_t2body (parser, t2body); mime_parser_set_new_part (parser, new_part); mime_parser_set_part_data (parser, part_data); mime_parser_set_collect_encrypted (parser, collect_encrypted); -- cgit v1.2.3