summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJinWang An <jinwang.an@samsung.com>2021-12-01 16:54:37 +0900
committerJinWang An <jinwang.an@samsung.com>2021-12-01 16:54:37 +0900
commit442a1386c9708114c2b721afea60d5593e36c423 (patch)
treed3b22c8ec8d6aaa40297028da6f9da358bb15f80 /src
parent214479142a766516e8770c3e1a3b0b0cc37c239e (diff)
downloadgpgme-442a1386c9708114c2b721afea60d5593e36c423.tar.gz
gpgme-442a1386c9708114c2b721afea60d5593e36c423.tar.bz2
gpgme-442a1386c9708114c2b721afea60d5593e36c423.zip
Imported Upstream version 1.10.0upstream/1.10.0
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in3
-rw-r--r--src/context.h3
-rw-r--r--src/conversion.c2
-rw-r--r--src/data.c4
-rw-r--r--src/debug.c2
-rw-r--r--src/decrypt-verify.c3
-rw-r--r--src/decrypt.c145
-rw-r--r--src/delete.c54
-rw-r--r--src/edit.c2
-rw-r--r--src/engine-assuan.c1
-rw-r--r--src/engine-backend.h6
-rw-r--r--src/engine-g13.c1
-rw-r--r--src/engine-gpg.c42
-rw-r--r--src/engine-gpgconf.c60
-rw-r--r--src/engine-gpgsm.c11
-rw-r--r--src/engine-spawn.c1
-rw-r--r--src/engine-uiserver.c6
-rw-r--r--src/engine.c23
-rw-r--r--src/engine.h8
-rw-r--r--src/genkey.c2
-rw-r--r--src/gpgconf.c21
-rw-r--r--src/gpgme-w32spawn.c1
-rw-r--r--src/gpgme.c8
-rw-r--r--src/gpgme.def5
-rw-r--r--src/gpgme.h.in45
-rw-r--r--src/import.c13
-rw-r--r--src/key.c2
-rw-r--r--src/keylist.c44
-rw-r--r--src/libgpgme.vers3
-rw-r--r--src/parsetlv.h2
-rw-r--r--src/posix-io.c110
-rw-r--r--src/status-table.c22
-rw-r--r--src/trustlist.c2
-rw-r--r--src/util.h26
-rw-r--r--src/verify.c4
35 files changed, 520 insertions, 167 deletions
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:<escaped uid string>
+
We want:
uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
*/
@@ -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);
}
@@ -984,6 +986,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,
gpgme_query_swdb_result_t result)
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 <ctype.h>
#include <sys/resource.h>
-#if __linux__
+#ifdef USE_LINUX_GETDENTS
+# include <sys/syscall.h>
# include <sys/types.h>
# include <dirent.h>
-#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;
}