From 442a1386c9708114c2b721afea60d5593e36c423 Mon Sep 17 00:00:00 2001 From: JinWang An Date: Wed, 1 Dec 2021 16:54:37 +0900 Subject: Imported Upstream version 1.10.0 --- src/Makefile.in | 3 +- src/context.h | 3 ++ src/conversion.c | 2 +- src/data.c | 4 ++ src/debug.c | 2 +- src/decrypt-verify.c | 3 +- src/decrypt.c | 145 ++++++++++++++++++++++++++++++++++---------------- src/delete.c | 54 +++++++++++++++++-- src/edit.c | 2 +- src/engine-assuan.c | 1 + src/engine-backend.h | 6 ++- src/engine-g13.c | 1 + src/engine-gpg.c | 42 +++++++++++---- src/engine-gpgconf.c | 60 ++++++++++++++++++++- src/engine-gpgsm.c | 11 ++-- src/engine-spawn.c | 1 + src/engine-uiserver.c | 6 ++- src/engine.c | 23 ++++++-- src/engine.h | 8 ++- src/genkey.c | 2 +- src/gpgconf.c | 21 ++++++++ src/gpgme-w32spawn.c | 1 - src/gpgme.c | 8 +++ src/gpgme.def | 5 ++ src/gpgme.h.in | 45 ++++++++++++++-- src/import.c | 13 +++-- src/key.c | 2 +- src/keylist.c | 44 +++++++-------- src/libgpgme.vers | 3 ++ src/parsetlv.h | 2 +- src/posix-io.c | 110 +++++++++++++++++++++++++------------- src/status-table.c | 22 ++++---- src/trustlist.c | 2 +- src/util.h | 26 +++++++-- src/verify.c | 4 ++ 35 files changed, 520 insertions(+), 167 deletions(-) (limited to 'src') diff --git a/src/Makefile.in b/src/Makefile.in index 5f153a8..dfdf550 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -107,7 +107,7 @@ subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/build-aux/mkinstalldirs \ $(srcdir)/versioninfo.rc.in $(srcdir)/gpgme.h.in \ - $(srcdir)/gpgme-config.in stpcpy.c ttyname_r.c setenv.c \ + $(srcdir)/gpgme-config.in ttyname_r.c setenv.c stpcpy.c \ $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ @@ -423,7 +423,6 @@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_SITE_PKG = @PYTHON_SITE_PKG@ PYTHON_VERSION = @PYTHON_VERSION@ -PYTHON_VERSIONS = @PYTHON_VERSIONS@ QTCHOOSER = @QTCHOOSER@ RANLIB = @RANLIB@ RC = @RC@ diff --git a/src/context.h b/src/context.h index d0542d9..1e763d2 100644 --- a/src/context.h +++ b/src/context.h @@ -118,6 +118,9 @@ struct gpgme_context * flag is cleared with each operation. */ unsigned int redraw_suggested : 1; + /* True if the option --auto-key-retrieve shall be passed to gpg. */ + unsigned int auto_key_retrieve : 1; + /* Flags for keylist mode. */ gpgme_keylist_mode_t keylist_mode; diff --git a/src/conversion.c b/src/conversion.c index 92dd214..5b84f67 100644 --- a/src/conversion.c +++ b/src/conversion.c @@ -374,7 +374,7 @@ _gpgme_encode_percent_string (const char *src, char **destp, size_t len) /* Split a string into space delimited fields and remove leading and - * trailing spaces from each field. A pointer to the each field is + * trailing spaces from each field. A pointer to each field is * stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function * modifies STRING. The number of parsed fields is returned. */ diff --git a/src/data.c b/src/data.c index e4e9ee3..7ae5b32 100644 --- a/src/data.c +++ b/src/data.c @@ -46,6 +46,10 @@ _gpgme_data_new (gpgme_data_t *r_dh, struct _gpgme_data_cbs *cbs) return gpg_error (GPG_ERR_INV_VALUE); *r_dh = NULL; + + if (_gpgme_selftest) + return _gpgme_selftest; + dh = calloc (1, sizeof (*dh)); if (!dh) return gpg_error_from_syserror (); diff --git a/src/debug.c b/src/debug.c index e9bfc40..d7604a7 100644 --- a/src/debug.c +++ b/src/debug.c @@ -222,7 +222,7 @@ debug_init (void) -/* This should be called as soon as the locks are intialized. It is +/* This should be called as soon as the locks are initialized. It is required so that the assuan logging gets conncted to the gpgme log stream as early as possible. */ void diff --git a/src/decrypt-verify.c b/src/decrypt-verify.c index 66cfe94..17f79ac 100644 --- a/src/decrypt-verify.c +++ b/src/decrypt-verify.c @@ -86,7 +86,8 @@ decrypt_verify_start (gpgme_ctx_t ctx, int synchronous, flags, cipher, plain, ctx->export_session_keys, - ctx->override_session_key); + ctx->override_session_key, + ctx->auto_key_retrieve); } diff --git a/src/decrypt.c b/src/decrypt.c index f30f80f..8c2cd4d 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -1,6 +1,6 @@ /* decrypt.c - Decrypt function. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2017 g10 Code GmbH This file is part of GPGME. @@ -43,7 +43,18 @@ typedef struct gpg_error_t failure_code; int okay; + + /* A flag telling that the a decryption failed and an optional error + * code to further specify the failure. */ int failed; + gpg_error_t pkdecrypt_failed; + + /* At least one secret key is not available. gpg issues NO_SECKEY + * status lines for each key the message has been encrypted to but + * that secret key is not available. This can't be done for hidden + * recipients, though. We track it here to allow for a better error + * message that the general DECRYPTION_FAILED. */ + int any_no_seckey; /* A pointer to the next pointer of the last recipient in the list. This makes appending new invalid signers painless while @@ -124,7 +135,80 @@ gpgme_op_decrypt_result (gpgme_ctx_t ctx) return &opd->result; } + +/* Parse the ARGS of an error status line and record some error + * conditions at OPD. Returns 0 on success. */ +static gpgme_error_t +parse_status_error (char *args, op_data_t opd) +{ + gpgme_error_t err; + char *field[3]; + int nfields; + char *args2; + + if (!args) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + args2 = strdup (args); /* Split modifies the input string. */ + nfields = _gpgme_split_fields (args2, field, DIM (field)); + if (nfields < 1) + { + free (args2); + return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required arg missing. */ + } + err = nfields < 2 ? 0 : atoi (field[1]); + + if (!strcmp (field[0], "decrypt.algorithm")) + { + if (gpg_err_code (err) == GPG_ERR_UNSUPPORTED_ALGORITHM + && nfields > 2 + && strcmp (field[2], "?")) + { + opd->result.unsupported_algorithm = strdup (field[2]); + if (!opd->result.unsupported_algorithm) + { + free (args2); + return gpg_error_from_syserror (); + } + } + } + else if (!strcmp (field[0], "decrypt.keyusage")) + { + if (gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE) + opd->result.wrong_key_usage = 1; + } + else if (!strcmp (field[0], "pkdecrypt_failed")) + { + switch (gpg_err_code (err)) + { + case GPG_ERR_CANCELED: + case GPG_ERR_FULLY_CANCELED: + /* It is better to return with a cancel error code than the + * general decryption failed error code. */ + opd->pkdecrypt_failed = gpg_err_make (gpg_err_source (err), + GPG_ERR_CANCELED); + break; + + case GPG_ERR_BAD_PASSPHRASE: + /* A bad passphrase is severe enough that we return this + * error code. */ + opd->pkdecrypt_failed = err; + break; + + default: + /* For now all other error codes are ignored and the + * standard DECRYPT_FAILED is returned. */ + break; + } + } + + + free (args2); + return 0; +} + + static gpgme_error_t parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol) { @@ -206,7 +290,11 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, case GPGME_STATUS_EOF: /* FIXME: These error values should probably be attributed to the underlying crypto engine (as error source). */ - if (opd->failed) + if (opd->failed && opd->pkdecrypt_failed) + return opd->pkdecrypt_failed; + else if (opd->failed && opd->any_no_seckey) + return gpg_error (GPG_ERR_NO_SECKEY); + else if (opd->failed) return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); @@ -230,47 +318,9 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, /* Note that this is an informational status code which should not lead to an error return unless it is something not related to the backend. */ - { - const char d_alg[] = "decrypt.algorithm"; - const char k_alg[] = "decrypt.keyusage"; - - if (!strncmp (args, d_alg, sizeof (d_alg) - 1)) - { - args += sizeof (d_alg) - 1; - while (*args == ' ') - args++; - - if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM) - { - char *end; - - while (*args && *args != ' ') - args++; - while (*args == ' ') - args++; - - end = strchr (args, ' '); - if (end) - *end = '\0'; - - if (!(*args == '?' && *(args + 1) == '\0')) - { - opd->result.unsupported_algorithm = strdup (args); - if (!opd->result.unsupported_algorithm) - return gpg_error_from_syserror (); - } - } - } - else if (!strncmp (args, k_alg, sizeof (k_alg) - 1)) - { - args += sizeof (k_alg) - 1; - while (*args == ' ') - args++; - - if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE) - opd->result.wrong_key_usage = 1; - } - } + err = parse_status_error (args, opd); + if (err) + return err; break; case GPGME_STATUS_ENC_TO: @@ -290,7 +340,6 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, case GPGME_STATUS_NO_SECKEY: { gpgme_recipient_t rec = opd->result.recipients; - while (rec) { if (!strcmp (rec->keyid, args)) @@ -303,6 +352,7 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, /* FIXME: Is this ok? */ if (!rec) return trace_gpg_error (GPG_ERR_INV_ENGINE); + opd->any_no_seckey = 1; } break; @@ -321,6 +371,10 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, } break; + case GPGME_STATUS_DECRYPTION_COMPLIANCE_MODE: + PARSE_COMPLIANCE_FLAGS (args, &opd->result); + break; + default: break; } @@ -398,7 +452,8 @@ _gpgme_decrypt_start (gpgme_ctx_t ctx, int synchronous, flags, cipher, plain, ctx->export_session_keys, - ctx->override_session_key); + ctx->override_session_key, + ctx->auto_key_retrieve); } diff --git a/src/delete.c b/src/delete.c index fc99aac..1bf1cb4 100644 --- a/src/delete.c +++ b/src/delete.c @@ -108,7 +108,7 @@ delete_status_handler (void *priv, gpgme_status_code_t code, char *args) static gpgme_error_t delete_start (gpgme_ctx_t ctx, int synchronous, const gpgme_key_t key, - int allow_secret) + unsigned int flags) { gpgme_error_t err; @@ -118,7 +118,7 @@ delete_start (gpgme_ctx_t ctx, int synchronous, const gpgme_key_t key, _gpgme_engine_set_status_handler (ctx->engine, delete_status_handler, ctx); - return _gpgme_engine_op_delete (ctx->engine, key, allow_secret); + return _gpgme_engine_op_delete (ctx->engine, key, flags); } @@ -130,7 +130,7 @@ gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, { gpgme_error_t err; - TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete", ctx, + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete_start", ctx, "key=%p (%s), allow_secret=%i", key, (key->subkeys && key->subkeys->fpr) ? key->subkeys->fpr : "invalid", allow_secret); @@ -138,7 +138,8 @@ gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - err = delete_start (ctx, 0, key, allow_secret); + err = delete_start (ctx, 0, key, + allow_secret ? GPGME_DELETE_ALLOW_SECRET : 0); return TRACE_ERR (err); } @@ -158,7 +159,50 @@ gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret) if (!ctx) return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); - err = delete_start (ctx, 1, key, allow_secret); + err = delete_start (ctx, 1, key, + allow_secret ? GPGME_DELETE_ALLOW_SECRET : 0); + if (!err) + err = _gpgme_wait_one (ctx); + return err; +} + + +/* Delete KEY from the keyring. */ +gpgme_error_t +gpgme_op_delete_ext_start (gpgme_ctx_t ctx, const gpgme_key_t key, + unsigned int flags) +{ + gpgme_error_t err; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete_ext_start", ctx, + "key=%p (%s), flags=0x%x", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", flags); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = delete_start (ctx, 0, key, flags); + return TRACE_ERR (err); +} + + +/* Delete KEY from the keyring. */ +gpgme_error_t +gpgme_op_delete_ext (gpgme_ctx_t ctx, const gpgme_key_t key, + unsigned int flags) +{ + gpgme_error_t err; + + TRACE_BEG3 (DEBUG_CTX, "gpgme_op_delete_ext", ctx, + "key=%p (%s), flags=0x%x", key, + (key->subkeys && key->subkeys->fpr) ? + key->subkeys->fpr : "invalid", flags); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + err = delete_start (ctx, 1, key, flags); if (!err) err = _gpgme_wait_one (ctx); return err; diff --git a/src/edit.c b/src/edit.c index 887af73..ca4d595 100644 --- a/src/edit.c +++ b/src/edit.c @@ -194,7 +194,7 @@ gpgme_op_interact (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags, -/* The deprectated interface. */ +/* The deprecated interface. */ static gpgme_error_t edit_start (gpgme_ctx_t ctx, int synchronous, int type, gpgme_key_t key, gpgme_edit_cb_t fnc, void *fnc_value, gpgme_data_t out) diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 68bdaa6..bb2290a 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -796,6 +796,7 @@ struct engine_ops _gpgme_engine_ops_assuan = llass_transact, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ llass_set_io_cbs, llass_io_event, diff --git a/src/engine-backend.h b/src/engine-backend.h index 53af662..421eb16 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -65,8 +65,9 @@ struct engine_ops gpgme_decrypt_flags_t flags, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key, - const char *override_session_key); - gpgme_error_t (*delete) (void *engine, gpgme_key_t key, int allow_secret); + const char *override_session_key, + int auto_key_retrieve); + gpgme_error_t (*delete) (void *engine, gpgme_key_t key, unsigned int flags); gpgme_error_t (*edit) (void *engine, int type, gpgme_key_t key, gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */); gpgme_error_t (*encrypt) (void *engine, gpgme_key_t recp[], @@ -128,6 +129,7 @@ struct engine_ops gpgme_error_t (*conf_load) (void *engine, gpgme_conf_comp_t *conf_p); gpgme_error_t (*conf_save) (void *engine, gpgme_conf_comp_t conf); + gpgme_error_t (*conf_dir) (void *engine, const char *what, char **result); gpgme_error_t (*query_swdb) (void *engine, const char *name, const char *iversion, diff --git a/src/engine-g13.c b/src/engine-g13.c index 02951e8..f8f3178 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -811,6 +811,7 @@ struct engine_ops _gpgme_engine_ops_g13 = g13_transact, NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ g13_set_io_cbs, g13_io_event, diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 0c3a63e..bfe7d13 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1562,7 +1562,8 @@ static gpgme_error_t gpg_decrypt (void *engine, gpgme_decrypt_flags_t flags, gpgme_data_t ciph, gpgme_data_t plain, - int export_session_key, const char *override_session_key) + int export_session_key, const char *override_session_key, + int auto_key_retrieve) { engine_gpg_t gpg = engine; gpgme_error_t err; @@ -1580,6 +1581,9 @@ gpg_decrypt (void *engine, if (!err && export_session_key) err = add_arg (gpg, "--show-session-key"); + if (!err && auto_key_retrieve) + err = add_arg (gpg, "--auto-key-retrieve"); + if (!err && override_session_key && *override_session_key) { if (have_gpg_version (gpg, "2.1.16")) @@ -1628,13 +1632,18 @@ gpg_decrypt (void *engine, } static gpgme_error_t -gpg_delete (void *engine, gpgme_key_t key, int allow_secret) +gpg_delete (void *engine, gpgme_key_t key, unsigned int flags) { engine_gpg_t gpg = engine; - gpgme_error_t err; + gpgme_error_t err = 0; + int allow_secret = flags & GPGME_DELETE_ALLOW_SECRET; + int force = flags & GPGME_DELETE_FORCE; - err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key" - : "--delete-key"); + if (force) + err = add_arg (gpg, "--yes"); + if (!err) + err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key" + : "--delete-key"); if (!err) err = add_arg (gpg, "--"); if (!err) @@ -1869,7 +1878,7 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, if (!err && (flags & GPGME_ENCRYPT_WRAP)) { - /* gpg is current not abale to detect already compressed + /* gpg is current not able to detect already compressed * packets. Thus when using * gpg --unwrap -d | gpg --no-literal -e * the encryption would add an additional compression layer. @@ -2585,6 +2594,9 @@ gpg_keylist_preprocess (char *line, char **r_line) as defined in 5.2. Machine Readable Indexes of the OpenPGP HTTP Keyserver Protocol (draft). + For an ldap keyserver the format is: + uid: + We want: uid:o::::::::: */ @@ -2626,9 +2638,17 @@ gpg_keylist_preprocess (char *line, char **r_line) } *dst = '\0'; - if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:", - field[4], field[2], field[3], uid) < 0) - return gpg_error_from_syserror (); + if (fields < 4) + { + if (gpgrt_asprintf (r_line, "uid:o::::::::%s:", uid) < 0) + return gpg_error_from_syserror (); + } + else + { + if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:", + field[4], field[2], field[3], uid) < 0) + return gpg_error_from_syserror (); + } } return 0; @@ -2992,6 +3012,9 @@ gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, gpgme_error_t err; err = append_args_from_sender (gpg, ctx); + if (!err && ctx->auto_key_retrieve) + err = add_arg (gpg, "--auto-key-retrieve"); + if (err) ; else if (plaintext) @@ -3088,6 +3111,7 @@ struct engine_ops _gpgme_engine_ops_gpg = NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ gpg_set_io_cbs, gpg_io_event, diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index 6f7c8ac..94ae67f 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -399,7 +399,7 @@ gpgconf_parse_option (gpgme_conf_opt_t opt, gpgme_conf_arg_t *arg_p, char *line) { gpgme_error_t err; - char *mark; + char *mark = NULL; if (!line[0]) return 0; @@ -408,7 +408,8 @@ gpgconf_parse_option (gpgme_conf_opt_t opt, { gpgme_conf_arg_t arg; - mark = strchr (line, ','); + if (opt->type != GPGME_CONF_STRING) + mark = strchr (line, ','); if (mark) *mark = '\0'; @@ -985,6 +986,60 @@ gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp) } +struct gpgconf_config_dir_s +{ + const char *what; + char *result; +}; + +/* Called for each line in the gpgconf --list-dirs output. Searches + for the desired line and returns the result, indicating success by + a special error value GPG_ERR_USER_1 (which terminates the + operation immediately). */ +static gpgme_error_t +gpgconf_config_dir_cb (void *hook, char *line) +{ + /* This is an input- and output-parameter. */ + struct gpgconf_config_dir_s *data = (struct gpgconf_config_dir_s *) hook; + int len = strlen(data->what); + + if (!strncmp(line, data->what, len) && line[len] == ':') + { + char *result = strdup(&line[len + 1]); + if (!result) + return gpg_error_from_syserror (); + data->result = result; + return gpg_error(GPG_ERR_USER_1); + } + return 0; +} + + +/* Like gpgme_get_dirinfo, but uses the home directory of ENGINE and + does not cache the result. */ +static gpgme_error_t +gpgconf_conf_dir (void *engine, const char *what, char **result) +{ + gpgme_error_t err; + struct gpgconf_config_dir_s data; + + data.what = what; + data.result = NULL; + err = gpgconf_read (engine, "--list-dirs", NULL, + gpgconf_config_dir_cb, &data); + if (gpg_err_code (err) == GPG_ERR_USER_1) + { + /* This signals to us that a result was found. */ + *result = data.result; + return 0; + } + + if (!err) + err = gpg_error(GPG_ERR_NOT_FOUND); + return 0; +} + + /* Parse a line received from gpgconf --query-swdb. This function may * modify LINE. The result is stored at RESUL. */ static gpg_error_t @@ -1253,6 +1308,7 @@ struct engine_ops _gpgme_engine_ops_gpgconf = NULL, /* opassuan_transact */ gpgconf_conf_load, gpgconf_conf_save, + gpgconf_conf_dir, gpgconf_query_swdb, gpgconf_set_io_cbs, NULL, /* io_event */ diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index c3d5427..e337fed 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1130,7 +1130,8 @@ static gpgme_error_t gpgsm_decrypt (void *engine, gpgme_decrypt_flags_t flags, gpgme_data_t ciph, gpgme_data_t plain, - int export_session_key, const char *override_session_key) + int export_session_key, const char *override_session_key, + int auto_key_retrieve) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err; @@ -1142,6 +1143,9 @@ gpgsm_decrypt (void *engine, (void)export_session_key; (void)override_session_key; + /* --auto-key-retrieve is also not supported. */ + (void)auto_key_retrieve; + if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); @@ -1162,7 +1166,7 @@ gpgsm_decrypt (void *engine, static gpgme_error_t -gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret) +gpgsm_delete (void *engine, gpgme_key_t key, unsigned int flags) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err; @@ -1171,7 +1175,7 @@ gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret) char *line; int length = 8; /* "DELKEYS " */ - (void)allow_secret; + (void)flags; if (!fpr) return gpg_error (GPG_ERR_INV_VALUE); @@ -2119,6 +2123,7 @@ struct engine_ops _gpgme_engine_ops_gpgsm = NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ gpgsm_set_io_cbs, gpgsm_io_event, diff --git a/src/engine-spawn.c b/src/engine-spawn.c index 9d587cc..7044781 100644 --- a/src/engine-spawn.c +++ b/src/engine-spawn.c @@ -469,6 +469,7 @@ struct engine_ops _gpgme_engine_ops_spawn = NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ engspawn_set_io_cbs, engspawn_io_event, /* io_event */ diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index 20a8abf..bc3f3fb 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -962,7 +962,8 @@ static gpgme_error_t uiserver_decrypt (void *engine, gpgme_decrypt_flags_t flags, gpgme_data_t ciph, gpgme_data_t plain, - int export_session_key, const char *override_session_key) + int export_session_key, const char *override_session_key, + int auto_key_retrieve) { engine_uiserver_t uiserver = engine; gpgme_error_t err; @@ -972,6 +973,8 @@ uiserver_decrypt (void *engine, (void)override_session_key; /* Fixme: We need to see now to add this * to the UI server protocol */ + (void)auto_key_retrieve; /* Not yet supported. */ + if (!uiserver) return gpg_error (GPG_ERR_INV_VALUE); @@ -1386,6 +1389,7 @@ struct engine_ops _gpgme_engine_ops_uiserver = NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ + NULL, /* conf_dir */ NULL, /* query_swdb */ uiserver_set_io_cbs, uiserver_io_event, diff --git a/src/engine.c b/src/engine.c index 278916d..28ba9fd 100644 --- a/src/engine.c +++ b/src/engine.c @@ -656,7 +656,8 @@ _gpgme_engine_op_decrypt (engine_t engine, gpgme_decrypt_flags_t flags, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key, - const char *override_session_key) + const char *override_session_key, + int auto_key_retrieve) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -665,13 +666,14 @@ _gpgme_engine_op_decrypt (engine_t engine, return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return (*engine->ops->decrypt) (engine->engine, flags, ciph, plain, - export_session_key, override_session_key); + export_session_key, override_session_key, + auto_key_retrieve); } gpgme_error_t _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key, - int allow_secret) + unsigned int flags) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -679,7 +681,7 @@ _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key, if (!engine->ops->delete) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->delete) (engine->engine, key, allow_secret); + return (*engine->ops->delete) (engine->engine, key, flags); } @@ -983,6 +985,19 @@ _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf) } +gpgme_error_t +_gpgme_engine_op_conf_dir (engine_t engine, const char *what, char **result) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->conf_dir) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->conf_dir) (engine->engine, what, result); +} + + gpgme_error_t _gpgme_engine_op_query_swdb (engine_t engine, const char *name, const char *iversion, diff --git a/src/engine.h b/src/engine.h index dd0ef9c..0bf1bb2 100644 --- a/src/engine.h +++ b/src/engine.h @@ -88,9 +88,10 @@ gpgme_error_t _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph, gpgme_data_t plain, int export_session_key, - const char *override_session_key); + const char *override_session_key, + int auto_key_retrieve); gpgme_error_t _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key, - int allow_secret); + unsigned int flags); gpgme_error_t _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key, gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */); @@ -176,6 +177,9 @@ gpgme_error_t _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p); gpgme_error_t _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf); +gpgme_error_t _gpgme_engine_op_conf_dir (engine_t engine, + const char *what, + char **result); gpgme_error_t _gpgme_engine_op_query_swdb (engine_t engine, const char *name, diff --git a/src/genkey.c b/src/genkey.c index 710b58f..16484ec 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -650,7 +650,7 @@ gpgme_op_set_uid_flag_start (gpgme_ctx_t ctx, } -/* See set_uid_flag. Thsi is the synchronous variant. */ +/* See set_uid_flag. This is the synchronous variant. */ gpgme_error_t gpgme_op_set_uid_flag (gpgme_ctx_t ctx, gpgme_key_t key, const char *userid, diff --git a/src/gpgconf.c b/src/gpgconf.c index b1b84a6..ce6ace4 100644 --- a/src/gpgconf.c +++ b/src/gpgconf.c @@ -108,3 +108,24 @@ gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp) ctx->protocol = proto; return err; } + + +gpgme_error_t +gpgme_op_conf_dir (gpgme_ctx_t ctx, const char *what, char **result) +{ + gpgme_error_t err; + gpgme_protocol_t proto; + + if (!ctx) + return gpg_error (GPG_ERR_INV_VALUE); + + proto = ctx->protocol; + ctx->protocol = GPGME_PROTOCOL_GPGCONF; + err = _gpgme_op_reset (ctx, 1); + if (err) + return err; + + err = _gpgme_engine_op_conf_dir (ctx->engine, what, result); + ctx->protocol = proto; + return err; +} diff --git a/src/gpgme-w32spawn.c b/src/gpgme-w32spawn.c index 003b9b0..d86c850 100644 --- a/src/gpgme-w32spawn.c +++ b/src/gpgme-w32spawn.c @@ -205,7 +205,6 @@ my_spawn (char **argv, struct spawn_fd_item_s *fd_list, unsigned int flags) } cr_flags |= CREATE_SUSPENDED; - cr_flags |= DETACHED_PROCESS; if (!CreateProcessA (argv[0], arg_string, &sec_attr, /* process security attributes */ diff --git a/src/gpgme.c b/src/gpgme.c index 2b196a2..d0a5afe 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -531,6 +531,10 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) if (!ctx->override_session_key) err = gpg_error_from_syserror (); } + else if (!strcmp (name, "auto-key-retrieve")) + { + ctx->auto_key_retrieve = abool; + } else err = gpg_error (GPG_ERR_UNKNOWN_NAME); @@ -568,6 +572,10 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name) { return ctx->override_session_key? ctx->override_session_key : ""; } + else if (!strcmp (name, "auto-key-retrieve")) + { + return ctx->auto_key_retrieve? "1":""; + } else return NULL; } diff --git a/src/gpgme.def b/src/gpgme.def index 51053cd..cad30f6 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -262,5 +262,10 @@ EXPORTS gpgme_op_decrypt_ext @195 gpgme_op_decrypt_ext_start @196 + gpgme_op_delete_ext @197 + gpgme_op_delete_ext_start @198 + + gpgme_op_conf_dir @199 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 24b21e7..31a9060 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -330,6 +330,21 @@ typedef enum gpgme_tofu_policy_t; +/* The key origin values. */ +typedef enum + { + GPGME_KEYORG_UNKNOWN = 0, + GPGME_KEYORG_KS = 1, + GPGME_KEYORG_DANE = 3, + GPGME_KEYORG_WKD = 4, + GPGME_KEYORG_URL = 5, + GPGME_KEYORG_FILE = 6, + GPGME_KEYORG_SELF = 7, + GPGME_KEYORG_OTHER = 31 + } +gpgme_keyorg_t; + + /* The available protocols. */ typedef enum { @@ -697,7 +712,7 @@ struct _gpgme_user_id /* The malloced TOFU information or NULL. */ gpgme_tofu_info_t tofu; - /* Time of the last refresh of thsi user id. 0 if unknown. */ + /* Time of the last refresh of this user id. 0 if unknown. */ unsigned long last_update; }; typedef struct _gpgme_user_id *gpgme_user_id_t; @@ -1312,8 +1327,12 @@ struct _gpgme_op_decrypt_result /* Key should not have been used for encryption. */ unsigned int wrong_key_usage : 1; + /* True if the message was encrypted in compliance to the de-vs + * mode. */ + unsigned int is_de_vs : 1; + /* Internal to GPGME, do not use. */ - int _unused : 31; + int _unused : 30; gpgme_recipient_t recipients; @@ -1490,8 +1509,11 @@ struct _gpgme_signature /* Validity has been verified using the chain model. */ unsigned int chain_model : 1; + /* True if the signature is in compliance to the de-vs mode. */ + unsigned int is_de_vs : 1; + /* Internal to GPGME, do not use. */ - int _unused : 28; + int _unused : 27; gpgme_validity_t validity; gpgme_error_t validity_reason; @@ -1781,6 +1803,15 @@ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, gpgme_error_t gpgme_op_delete (gpgme_ctx_t ctx, const gpgme_key_t key, int allow_secret); +/* Flags for the key delete functions. */ +#define GPGME_DELETE_ALLOW_SECRET (1 << 0) /* Also delete secret key. */ +#define GPGME_DELETE_FORCE (1 << 1) /* Do not ask user to confirm. */ + +gpgme_error_t gpgme_op_delete_ext_start (gpgme_ctx_t ctx, const gpgme_key_t key, + unsigned int flags); +gpgme_error_t gpgme_op_delete_ext (gpgme_ctx_t ctx, const gpgme_key_t key, + unsigned int flags); + /* * Key signing interface @@ -2224,6 +2255,10 @@ gpgme_error_t gpgme_op_conf_load (gpgme_ctx_t ctx, gpgme_conf_comp_t *conf_p); follow chained components! */ gpgme_error_t gpgme_op_conf_save (gpgme_ctx_t ctx, gpgme_conf_comp_t comp); +/* Retrieve the configured directory. */ +gpgme_error_t gpgme_op_conf_dir(gpgme_ctx_t ctx, const char *what, + char **result); + /* Information about software versions. * This structure shall be considered read-only and an application @@ -2468,7 +2503,9 @@ typedef enum GPGME_STATUS_TOFU_USER = 95, GPGME_STATUS_TOFU_STATS = 96, GPGME_STATUS_TOFU_STATS_LONG = 97, - GPGME_STATUS_NOTATION_FLAGS = 98 + GPGME_STATUS_NOTATION_FLAGS = 98, + GPGME_STATUS_DECRYPTION_COMPLIANCE_MODE = 99, + GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE = 100 } gpgme_status_code_t; diff --git a/src/import.c b/src/import.c index 4173fe9..386ca72 100644 --- a/src/import.c +++ b/src/import.c @@ -392,13 +392,12 @@ gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys) } -/* Import the keys from the array KEYS into the keyring. This - function allows to move a key from one engine to another as long as - they are compatible. In particular it is used to actually import - keys retrieved from an external source (i.e. using - GPGME_KEYLIST_MODE_EXTERN). It replaces the old workaround of - exporting and then importing a key as used to make an X.509 key - permanent. This function automagically does the right thing. +/* Import the keys from the array KEYS into the keyring. In + particular it is used to actually import keys retrieved from an + external source (i.e. using GPGME_KEYLIST_MODE_EXTERN). It + replaces the old workaround of exporting and then importing a key + as used to make an X.509 key permanent. This function + automagically does the right thing. KEYS is a NULL terminated array of gpgme key objects. The result is the usual import result structure. Only keys matching the diff --git a/src/key.c b/src/key.c index e2e30db..bb4d5fd 100644 --- a/src/key.c +++ b/src/key.c @@ -292,7 +292,7 @@ _gpgme_key_add_sig (gpgme_key_t key, char *src) &sig->comment, dst); } else - sig->uid = '\0'; + sig->uid[0] = '\0'; if (!uid->signatures) uid->signatures = sig; diff --git a/src/keylist.c b/src/keylist.c index e16ba4d..24a9b0b 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -376,6 +376,25 @@ set_ownertrust (gpgme_key_t key, const char *src) } +static gpgme_keyorg_t +parse_keyorg (const char *string) +{ + switch (atoi (string)) + { + case 0: return GPGME_KEYORG_UNKNOWN; + case 1: + case 2: + return GPGME_KEYORG_KS; + case 3: return GPGME_KEYORG_DANE; + case 4: return GPGME_KEYORG_WKD; + case 5: return GPGME_KEYORG_URL; + case 6: return GPGME_KEYORG_FILE; + case 7: return GPGME_KEYORG_SELF; + default: return GPGME_KEYORG_OTHER; + } +} + + /* Parse field 15 of a secret key or subkey. This fields holds a reference to smartcards. FIELD is the content of the field and we are allowed to modify it. */ @@ -416,23 +435,6 @@ parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field) } -/* Parse the compliance field. */ -static void -parse_pub_field18 (gpgme_subkey_t subkey, char *field) -{ - char *p, *endp; - unsigned long ul; - - for (p = field; p && (ul = strtoul (p, &endp, 10)) && p != endp; p = endp) - { - switch (ul) - { - case 23: subkey->is_de_vs = 1; break; - } - } -} - - /* Parse a tfs record. */ static gpg_error_t parse_tfs_record (gpgme_user_id_t uid, char **field, int nfield) @@ -731,12 +733,12 @@ keylist_colon_handler (void *priv, char *line) /* Field 18 has the compliance flags. */ if (fields >= 17 && *field[17]) - parse_pub_field18 (subkey, field[17]); + PARSE_COMPLIANCE_FLAGS (field[17], subkey); if (fields >= 20) { key->last_update = _gpgme_parse_timestamp_ul (field[18]); - key->origin = 0; /* Fixme: Not yet defined in gpg. */ + key->origin = parse_keyorg (field[19]); } break; @@ -814,7 +816,7 @@ keylist_colon_handler (void *priv, char *line) /* Field 18 has the compliance flags. */ if (fields >= 17 && *field[17]) - parse_pub_field18 (subkey, field[17]); + PARSE_COMPLIANCE_FLAGS (field[17], subkey); break; @@ -831,7 +833,7 @@ keylist_colon_handler (void *priv, char *line) if (fields >= 20) { opd->tmp_uid->last_update = _gpgme_parse_timestamp_ul (field[18]); - opd->tmp_uid->origin = 0; /* Fixme: Not yet defined in gpg. */ + opd->tmp_uid->origin = parse_keyorg (field[19]); } } break; diff --git a/src/libgpgme.vers b/src/libgpgme.vers index adc8d7d..a95befb 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -46,6 +46,7 @@ GPGME_1.1 { gpgme_conf_opt_change; gpgme_op_conf_load; gpgme_op_conf_save; + gpgme_op_conf_dir; gpgme_cancel_async; @@ -209,6 +210,8 @@ GPGME_1.0 { gpgme_op_decrypt_verify_start; gpgme_op_delete; gpgme_op_delete_start; + gpgme_op_delete_ext; + gpgme_op_delete_ext_start; gpgme_op_edit; gpgme_op_edit_start; gpgme_op_encrypt; diff --git a/src/parsetlv.h b/src/parsetlv.h index bea03d4..2c04190 100644 --- a/src/parsetlv.h +++ b/src/parsetlv.h @@ -1,4 +1,4 @@ -/* parsetlv.h - TLV functions defintions +/* parsetlv.h - TLV functions definitions * Copyright (C) 2012 g10 Code GmbH * * This file is free software; you can redistribute it and/or modify diff --git a/src/posix-io.c b/src/posix-io.c index a351806..0448d29 100644 --- a/src/posix-io.c +++ b/src/posix-io.c @@ -47,10 +47,11 @@ #include #include -#if __linux__ +#ifdef USE_LINUX_GETDENTS +# include # include # include -#endif /*__linux__ */ +#endif /*USE_LINUX_GETDENTS*/ #include "util.h" @@ -59,6 +60,7 @@ #include "ath.h" #include "debug.h" + void _gpgme_io_subsystem_init (void) @@ -279,6 +281,22 @@ _gpgme_io_set_nonblocking (int fd) } +#ifdef USE_LINUX_GETDENTS +/* This is not declared in public headers; getdents64(2) says that we must + * define it ourselves. */ +struct linux_dirent64 +{ + ino64_t d_ino; + off64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[]; +}; + +# define DIR_BUF_SIZE 1024 +#endif /*USE_LINUX_GETDENTS*/ + + static long int get_max_fds (void) { @@ -291,39 +309,57 @@ get_max_fds (void) * than for example doing 4096 close calls where almost all of them * will fail. * - * Unfortunately we can't call opendir between fork and exec in a - * multi-threaded process because opendir uses malloc and thus a - * mutex which may deadlock with a malloc in another thread. Thus - * the code is not used until we can have a opendir variant which - * does not use malloc. */ -/* #ifdef __linux__ */ -/* { */ -/* DIR *dir = NULL; */ -/* struct dirent *dir_entry; */ -/* const char *s; */ -/* int x; */ - -/* dir = opendir ("/proc/self/fd"); */ -/* if (dir) */ -/* { */ -/* while ((dir_entry = readdir (dir))) */ -/* { */ -/* s = dir_entry->d_name; */ -/* if ( *s < '0' || *s > '9') */ -/* continue; */ -/* x = atoi (s); */ -/* if (x > fds) */ -/* fds = x; */ -/* } */ -/* closedir (dir); */ -/* } */ -/* if (fds != -1) */ -/* { */ -/* fds++; */ -/* source = "/proc"; */ -/* } */ -/* } */ -/* #endif /\* __linux__ *\/ */ + * We can't use the normal opendir/readdir/closedir interface between + * fork and exec in a multi-threaded process because opendir uses + * malloc and thus a mutex which may deadlock with a malloc in another + * thread. However, the underlying getdents system call is safe. */ +#ifdef USE_LINUX_GETDENTS + { + int dir_fd; + char dir_buf[DIR_BUF_SIZE]; + struct linux_dirent64 *dir_entry; + int r, pos; + const char *s; + int x; + + dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY); + if (dir_fd != -1) + { + for (;;) + { + r = syscall(SYS_getdents64, dir_fd, dir_buf, DIR_BUF_SIZE); + if (r == -1) + { + /* Fall back to other methods. */ + fds = -1; + break; + } + if (r == 0) + break; + + for (pos = 0; pos < r; pos += dir_entry->d_reclen) + { + dir_entry = (struct linux_dirent64 *) (dir_buf + pos); + s = dir_entry->d_name; + if (*s < '0' || *s > '9') + continue; + /* atoi is not guaranteed to be async-signal-safe. */ + for (x = 0; *s >= '0' && *s <= '9'; s++) + x = x * 10 + (*s - '0'); + if (!*s && x > fds && x != dir_fd) + fds = x; + } + } + + close (dir_fd); + } + if (fds != -1) + { + fds++; + source = "/proc"; + } + } +#endif /*USE_LINUX_GETDENTS*/ #ifdef RLIMIT_NOFILE if (fds == -1) @@ -473,7 +509,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, * have closefrom(2) we first figure out the highest fd we * do not want to close, then call closefrom, and on success * use the regular code to close all fds up to the start - * point of closefrom. Note that Solaris' closefrom does + * point of closefrom. Note that Solaris' and FreeBSD's closefrom do * not return errors. */ #ifdef HAVE_CLOSEFROM { @@ -482,7 +518,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, if (fd_list[i].fd > fd) fd = fd_list[i].fd; fd++; -#ifdef __sun +#if defined(__sun) || defined(__FreeBSD__) closefrom (fd); max_fds = fd; #else /*!__sun */ diff --git a/src/status-table.c b/src/status-table.c index c9bf357..afc7eab 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -43,10 +43,10 @@ static struct status_table_s status_table[] = { "ALREADY_SIGNED", GPGME_STATUS_ALREADY_SIGNED }, { "ATTRIBUTE", GPGME_STATUS_ATTRIBUTE }, { "BACKUP_KEY_CREATED", GPGME_STATUS_BACKUP_KEY_CREATED }, - { "BAD_PASSPHRASE", GPGME_STATUS_BAD_PASSPHRASE }, { "BADARMOR", GPGME_STATUS_BADARMOR }, { "BADMDC", GPGME_STATUS_BADMDC }, { "BADSIG", GPGME_STATUS_BADSIG }, + { "BAD_PASSPHRASE", GPGME_STATUS_BAD_PASSPHRASE }, { "BEGIN_DECRYPTION", GPGME_STATUS_BEGIN_DECRYPTION }, { "BEGIN_ENCRYPTION", GPGME_STATUS_BEGIN_ENCRYPTION }, { "BEGIN_SIGNING", GPGME_STATUS_BEGIN_SIGNING }, @@ -56,6 +56,7 @@ static struct status_table_s status_table[] = { "DECRYPTION_INFO", GPGME_STATUS_DECRYPTION_INFO }, { "DECRYPTION_OKAY", GPGME_STATUS_DECRYPTION_OKAY }, { "DELETE_PROBLEM", GPGME_STATUS_DELETE_PROBLEM }, + { "DECRYPTION_COMPLIANCE_MODE", GPGME_STATUS_DECRYPTION_COMPLIANCE_MODE }, { "ENC_TO", GPGME_STATUS_ENC_TO }, { "END_DECRYPTION", GPGME_STATUS_END_DECRYPTION }, { "END_ENCRYPTION", GPGME_STATUS_END_ENCRYPTION }, @@ -73,22 +74,22 @@ static struct status_table_s status_table[] = { "GET_BOOL", GPGME_STATUS_GET_BOOL }, { "GET_HIDDEN", GPGME_STATUS_GET_HIDDEN }, { "GET_LINE", GPGME_STATUS_GET_LINE }, - { "GOOD_PASSPHRASE", GPGME_STATUS_GOOD_PASSPHRASE }, { "GOODMDC", GPGME_STATUS_GOODMDC }, { "GOODSIG", GPGME_STATUS_GOODSIG }, + { "GOOD_PASSPHRASE", GPGME_STATUS_GOOD_PASSPHRASE }, { "GOT_IT", GPGME_STATUS_GOT_IT }, + { "IMPORTED", GPGME_STATUS_IMPORTED }, { "IMPORT_OK", GPGME_STATUS_IMPORT_OK }, { "IMPORT_PROBLEM", GPGME_STATUS_IMPORT_PROBLEM }, { "IMPORT_RES", GPGME_STATUS_IMPORT_RES }, - { "IMPORTED", GPGME_STATUS_IMPORTED }, { "INQUIRE_MAXLEN", GPGME_STATUS_INQUIRE_MAXLEN }, { "INV_RECP", GPGME_STATUS_INV_RECP }, { "INV_SGNR", GPGME_STATUS_INV_SGNR }, + { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED }, + { "KEYREVOKED", GPGME_STATUS_KEYREVOKED }, { "KEY_CONSIDERED", GPGME_STATUS_KEY_CONSIDERED }, { "KEY_CREATED", GPGME_STATUS_KEY_CREATED }, { "KEY_NOT_CREATED", GPGME_STATUS_KEY_NOT_CREATED }, - { "KEYEXPIRED", GPGME_STATUS_KEYEXPIRED }, - { "KEYREVOKED", GPGME_STATUS_KEYREVOKED }, { "LEAVE", GPGME_STATUS_LEAVE }, { "MISSING_PASSPHRASE", GPGME_STATUS_MISSING_PASSPHRASE }, { "MOUNTPOINT", GPGME_STATUS_MOUNTPOINT }, @@ -96,14 +97,14 @@ static struct status_table_s status_table[] = { "NEED_PASSPHRASE_PIN", GPGME_STATUS_NEED_PASSPHRASE_PIN }, { "NEED_PASSPHRASE_SYM", GPGME_STATUS_NEED_PASSPHRASE_SYM }, { "NEWSIG", GPGME_STATUS_NEWSIG }, - { "NO_PUBKEY", GPGME_STATUS_NO_PUBKEY }, - { "NO_RECP", GPGME_STATUS_NO_RECP }, - { "NO_SECKEY", GPGME_STATUS_NO_SECKEY }, - { "NO_SGNR", GPGME_STATUS_NO_SGNR }, { "NODATA", GPGME_STATUS_NODATA }, { "NOTATION_DATA", GPGME_STATUS_NOTATION_DATA }, { "NOTATION_FLAGS", GPGME_STATUS_NOTATION_FLAGS }, { "NOTATION_NAME", GPGME_STATUS_NOTATION_NAME }, + { "NO_PUBKEY", GPGME_STATUS_NO_PUBKEY }, + { "NO_RECP", GPGME_STATUS_NO_RECP }, + { "NO_SECKEY", GPGME_STATUS_NO_SECKEY }, + { "NO_SGNR", GPGME_STATUS_NO_SGNR }, { "PINENTRY_LAUNCHED", GPGME_STATUS_PINENTRY_LAUNCHED}, { "PKA_TRUST_BAD", GPGME_STATUS_PKA_TRUST_BAD }, { "PKA_TRUST_GOOD", GPGME_STATUS_PKA_TRUST_GOOD }, @@ -120,10 +121,10 @@ static struct status_table_s status_table[] = { "SHM_GET_BOOL", GPGME_STATUS_SHM_GET_BOOL }, { "SHM_GET_HIDDEN", GPGME_STATUS_SHM_GET_HIDDEN }, { "SHM_INFO", GPGME_STATUS_SHM_INFO }, + { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED }, { "SIG_CREATED", GPGME_STATUS_SIG_CREATED }, { "SIG_ID", GPGME_STATUS_SIG_ID }, { "SIG_SUBPACKET", GPGME_STATUS_SIG_SUBPACKET }, - { "SIGEXPIRED", GPGME_STATUS_SIGEXPIRED }, { "SUCCESS", GPGME_STATUS_SUCCESS }, { "TOFU_STATS", GPGME_STATUS_TOFU_STATS }, { "TOFU_STATS_LONG", GPGME_STATUS_TOFU_STATS_LONG }, @@ -137,6 +138,7 @@ static struct status_table_s status_table[] = { "UNEXPECTED", GPGME_STATUS_UNEXPECTED }, { "USERID_HINT", GPGME_STATUS_USERID_HINT }, { "VALIDSIG", GPGME_STATUS_VALIDSIG }, + { "VERIFICATION_COMPLIANCE_MODE", GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE }, {NULL, 0} }; diff --git a/src/trustlist.c b/src/trustlist.c index c85ef87..d7eb4c6 100644 --- a/src/trustlist.c +++ b/src/trustlist.c @@ -66,7 +66,7 @@ trustlist_status_handler (void *priv, gpgme_status_code_t code, char *args) K for a key The RECNO is either the one of the dir record or the one of the uid record. OT is the the usual trust letter and only availabel on K - lines. VAL is the calcualted validity MC is the marginal trust + lines. VAL is the calculated validity MC is the marginal trust counter and only available on U lines CC is the same for the complete count NAME ist the username and only printed on U lines. */ diff --git a/src/util.h b/src/util.h index 7b7924c..b4043ed 100644 --- a/src/util.h +++ b/src/util.h @@ -45,10 +45,6 @@ #define DIM(v) (sizeof(v)/sizeof((v)[0])) -#if GPG_ERROR_VERSION_NUMBER < 0x011500 /* 1.21 */ -# define GPG_ERR_FALSE 256 -#endif - #if GPG_ERROR_VERSION_NUMBER < 0x011900 /* 1.25 */ # define GPG_ERR_ENGINE_TOO_OLD 300 # define GPG_ERR_TOO_OLD 308 @@ -224,4 +220,26 @@ extern struct assuan_malloc_hooks _gpgme_assuan_malloc_hooks; int _gpgme_assuan_log_cb (assuan_context_t ctx, void *hook, unsigned int cat, const char *msg); + + +/* Parse the compliance field. */ +#define PARSE_COMPLIANCE_FLAGS(flags, result) \ + do { \ + char *comp_p, *comp_endp; \ + unsigned long comp_ul; \ + \ + for (comp_p = (flags); \ + comp_p \ + && (comp_ul = strtoul (comp_p, &comp_endp, 10)) \ + && comp_p != comp_endp; \ + comp_p = comp_endp) \ + { \ + switch (comp_ul) \ + { \ + case 23: (result)->is_de_vs = 1; break; \ + } \ + } \ + } while (0) + + #endif /* UTIL_H */ diff --git a/src/verify.c b/src/verify.c index 900f925..ee730a3 100644 --- a/src/verify.c +++ b/src/verify.c @@ -1078,6 +1078,10 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) if (err) return err; + case GPGME_STATUS_VERIFICATION_COMPLIANCE_MODE: + PARSE_COMPLIANCE_FLAGS (args, opd->current_sig); + break; + default: break; } -- cgit v1.2.3