From 0d28a696163677d6b34a802b6beddecd805d0fc7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 5 Jun 2015 14:25:59 +0200 Subject: [PATCH 01/13] Fix segv for userids with a backslash. * src/engine-gpg.c (gpg_keylist_preprocess): Increment SRC for a backslash. -- This bug is not exploitable because this bug fills up .data with backslashes and thus causes the segv. Signed-off-by: Werner Koch --- src/engine-gpg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 57aea8b0..e14fd8dd 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2194,6 +2194,7 @@ gpg_keylist_preprocess (char *line, char **r_line) { *dst++ = '\\'; *dst++ = '\\'; + src++; } else *(dst++) = *(src++); From 87d713ff41454bd08a345c63605f6fc7ac854dd4 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 18 Mar 2015 17:20:55 -0400 Subject: [PATCH 02/13] Set GPGME_SIGSUM_KEY_REVOKED also for gpg. * src/verify.c (calc_sig_summary): Handle GPG_ERR_CERT_REVOKED. -- parse_new_sig() handles a revoked key by setting sig->status to GPG_ERR_CERT_REVOKED, but then later calc_sig_summary() expects that code in sig->validity_reason. Additional comments added by wk. --- src/verify.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/verify.c b/src/verify.c index 37b2bd46..84487ee4 100644 --- a/src/verify.c +++ b/src/verify.c @@ -195,6 +195,10 @@ calc_sig_summary (gpgme_signature_t sig) sum |= GPGME_SIGSUM_KEY_MISSING; break; + case GPG_ERR_CERT_REVOKED: + sum |= GPGME_SIGSUM_KEY_REVOKED; + break; + case GPG_ERR_BAD_SIGNATURE: case GPG_ERR_NO_ERROR: break; @@ -213,6 +217,9 @@ calc_sig_summary (gpgme_signature_t sig) break; case GPG_ERR_CERT_REVOKED: + /* Note that this is a second way to set this flag. It may also + have been set due to a sig->status of STATUS_REVKEYSIG from + parse_new_sig. */ sum |= GPGME_SIGSUM_KEY_REVOKED; break; From a5b040cc57c65b3d105666b90c7eb59ee6ff3882 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 10:43:29 +0200 Subject: [PATCH 03/13] Fix test suite for GnuPG 2.1 which uses pubring.kbx. * tests/gpgsm/final.test: New. * tests/gpgsm/initial.test: New. * tests/gpg/start-stop-agent: Move to ../. * tests/gpgsm/Makefile.am (TESTS_ENVIRONMENT): Export top_srcdir. (TESTS): Add intial.test and final.test. (AM_LDFLAGS): Add -no-install. (clean-local): Use start-stop-agent (initial.test): Add dependency. * tests/gpg/Makefile.am (top_srcdir): Export top_srcdir. (AM_LDFLAGS): Add -no-install. (check-local): Depend on pubring-stamp instead of pubring.gpg. (initial.test): Depend on check-local. (./pubring-gpg): Replace by rule for ./pubring-stamp. -- There are also a couple of other changes which should make the tests a bit more robust and the gpg and gpgsm tests more similar. The -no-install avoids creating wrappers for test programs, which make debugging easier. The dependency on check-local guarantees that its rules are run before the first test. This is important because conf files are setup by this rule. Earlier automake versions seem to have run check-local always before the tests but today the order of execution is not defined. Signed-off-by: Werner Koch --- tests/Makefile.am | 2 +- tests/gpg/Makefile.am | 23 +++++++++++++++-------- tests/gpg/final.test | 2 +- tests/gpg/initial.test | 2 +- tests/gpgsm/Makefile.am | 20 +++++++++++++++----- tests/gpgsm/final.test | 5 +++++ tests/gpgsm/initial.test | 4 ++++ tests/{gpg => }/start-stop-agent | 0 8 files changed, 42 insertions(+), 16 deletions(-) create mode 100755 tests/gpgsm/final.test create mode 100755 tests/gpgsm/initial.test rename tests/{gpg => }/start-stop-agent (100%) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4b465d8e..94eddac5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -23,7 +23,7 @@ TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) TESTS = t-version t-data t-engine-info -EXTRA_DIST = t-data-1.txt t-data-2.txt ChangeLog-2011 +EXTRA_DIST = start-stop-agent t-data-1.txt t-data-2.txt ChangeLog-2011 AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ LDADD = ../src/libgpgme.la @GPG_ERROR_LIBS@ diff --git a/tests/gpg/Makefile.am b/tests/gpg/Makefile.am index 5f40dfe2..107397b4 100644 --- a/tests/gpg/Makefile.am +++ b/tests/gpg/Makefile.am @@ -22,7 +22,8 @@ GPG = gpg GPG_AGENT = gpg-agent -TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) # The keylist tests must come after the import and the edit test. noinst_HEADERS = t-support.h @@ -43,7 +44,7 @@ TESTS = initial.test $(c_tests) final.test CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \ - random_seed S.gpg-agent .gpg-v21-migrated + random_seed S.gpg-agent .gpg-v21-migrated pubring-stamp private_keys = \ 13CD0F3BDF24BE53FE192D62F18737256FF6E4FD \ @@ -53,11 +54,12 @@ private_keys = \ 7A030357C0F253A5BBCD282FFC4E521B37558F5C -EXTRA_DIST = start-stop-agent initial.test final.test \ +EXTRA_DIST = initial.test final.test \ pubdemo.asc secdemo.asc cipher-1.asc cipher-2.asc \ geheim.txt pubkey-1.asc seckey-1.asc pinentry $(private_keys) AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ +AM_LDFLAGS = -no-install LDADD = ../../src/libgpgme.la t_thread1_LDADD = ../../src/libgpgme-pthread.la -lpthread @@ -65,12 +67,16 @@ t_thread1_LDADD = ../../src/libgpgme-pthread.la -lpthread noinst_PROGRAMS = $(c_tests) t-genkey clean-local: - -$(srcdir)/start-stop-agent --stop + -$(top_srcdir)/tests/start-stop-agent --stop -rm -fR private-keys-v1.d -check-local: ./gpg.conf ./gpg-agent.conf ./pubring.gpg \ +check-local: ./gpg.conf ./gpg-agent.conf ./pubring-stamp \ ./private-keys-v1.d/gpg-sample.stamp +# To guarantee that check-local is run before any tests we +# add this dependency: +initial.test : check-local + export GNUPGHOME := $(abs_builddir) export GPG_AGENT_INFO := @@ -82,11 +88,12 @@ export GPG_AGENT_INFO := done echo x > ./private-keys-v1.d/gpg-sample.stamp -./pubring.gpg: $(srcdir)/pubdemo.asc - -$(GPG) --no-permission-warning \ - --import $(srcdir)/pubdemo.asc +./pubring-stamp: $(srcdir)/pubdemo.asc + $(GPG) --no-permission-warning \ + --import $(srcdir)/pubdemo.asc -$(GPG) --no-permission-warning \ --import $(srcdir)/secdemo.asc + touch ./pubring-stamp ./gpg.conf: # This is required for t-sig-notations. diff --git a/tests/gpg/final.test b/tests/gpg/final.test index 5148a34b..5289396f 100755 --- a/tests/gpg/final.test +++ b/tests/gpg/final.test @@ -1,4 +1,4 @@ #!/bin/sh -${srcdir}/start-stop-agent --stop +${top_srcdir}/tests/start-stop-agent --stop exit 0 diff --git a/tests/gpg/initial.test b/tests/gpg/initial.test index 1981c99d..93c8621a 100755 --- a/tests/gpg/initial.test +++ b/tests/gpg/initial.test @@ -1,4 +1,4 @@ #!/bin/sh -${srcdir}/start-stop-agent --start +${top_srcdir}/tests/start-stop-agent --start exit 0 diff --git a/tests/gpgsm/Makefile.am b/tests/gpgsm/Makefile.am index bf616d32..41645b6c 100644 --- a/tests/gpgsm/Makefile.am +++ b/tests/gpgsm/Makefile.am @@ -21,20 +21,26 @@ GPGSM = gpgsm -TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= +TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) LC_ALL=C GPG_AGENT_INFO= \ + top_srcdir=$(top_srcdir) noinst_HEADERS = t-support.h -TESTS = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export + +c_tests = t-import t-keylist t-encrypt t-verify t-decrypt t-sign t-export + + +TESTS = initial.test $(c_tests) final.test EXTRA_DIST = cert_dfn_pca01.der cert_dfn_pca15.der cert_g10code_test1.der \ - $(key_id) + $(key_id) initial.test final.test AM_CPPFLAGS = -I$(top_builddir)/src @GPG_ERROR_CFLAGS@ +AM_LDFLAGS = -no-install LDADD = ../../src/libgpgme.la # We don't run t-genkey in the test suite, because it takes too long # and needs a working pinentry. -noinst_PROGRAMS = $(TESTS) t-genkey cms-keylist cms-decrypt +noinst_PROGRAMS = $(c_tests) t-genkey cms-keylist cms-decrypt key_id = 32100C27173EF6E9C4E9A25D3D69F86D37A4F939 @@ -42,12 +48,16 @@ CLEANFILES = pubring.kbx pubring.kbx~ gpgsm.conf trustlist.txt \ random_seed S.gpg-agent clean-local: - -gpg-connect-agent KILLAGENT /bye + -$(top_srcdir)/tests/start-stop-agent --stop -rm -fR private-keys-v1.d check-local: ./pubring.kbx ./gpgsm.conf \ ./private-keys-v1.d/$(key_id).key ./trustlist.txt +# To guarantee that check-local is run before any tests we add this +# dependency: +initial.test : check-local + export GNUPGHOME := $(abs_builddir) export GPG_AGENT_INFO := diff --git a/tests/gpgsm/final.test b/tests/gpgsm/final.test new file mode 100755 index 00000000..d0567e3f --- /dev/null +++ b/tests/gpgsm/final.test @@ -0,0 +1,5 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --stop + +exit 0 diff --git a/tests/gpgsm/initial.test b/tests/gpgsm/initial.test new file mode 100755 index 00000000..93c8621a --- /dev/null +++ b/tests/gpgsm/initial.test @@ -0,0 +1,4 @@ +#!/bin/sh + +${top_srcdir}/tests/start-stop-agent --start +exit 0 diff --git a/tests/gpg/start-stop-agent b/tests/start-stop-agent similarity index 100% rename from tests/gpg/start-stop-agent rename to tests/start-stop-agent From 8b9f84828cd04a7dab37e219123edc1905da8e6b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 11:08:08 +0200 Subject: [PATCH 04/13] Fix compiler warnings about unused value in TRACE macros. * src/debug.h: Change macros to not have a literal 0 as last expression of the comma operator. * src/debug.c (_gpgme_debug_frame_end): Return 0. (_gpgme_debug): Return 0. -- Instead of using foo(), 0 for the trace macros we let foo() return 0 instead. Signed-off-by: Werner Koch --- src/debug.c | 19 ++++++++++++---- src/debug.h | 63 +++++++++++++++++++++++++---------------------------- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/debug.c b/src/debug.c index ca0bb21a..292db555 100644 --- a/src/debug.c +++ b/src/debug.c @@ -80,11 +80,12 @@ _gpgme_debug_frame_begin (void) #endif } -void _gpgme_debug_frame_end (void) +int _gpgme_debug_frame_end (void) { #ifdef FRAME_NR frame_nr--; #endif + return 0; } @@ -223,8 +224,17 @@ _gpgme_debug_subsystem_init (void) -/* Log the formatted string FORMAT at debug level LEVEL or higher. */ -void +/* Log the formatted string FORMAT at debug level LEVEL or higher. + * + * Returns: 0 + * + * Note that we always return 0 because the old TRACE macro evaluated + * to 0 which issues a warning with newer gcc version about an unused + * values. By using a return value of this function this can be + * avoided. Fixme: It might be useful to check whether the return + * value from the TRACE macros are actually used somewhere. + */ +int _gpgme_debug (int level, const char *format, ...) { va_list arg_ptr; @@ -232,7 +242,7 @@ _gpgme_debug (int level, const char *format, ...) saved_errno = errno; if (debug_level < level) - return; + return 0; va_start (arg_ptr, format); LOCK (debug_lock); @@ -273,6 +283,7 @@ _gpgme_debug (int level, const char *format, ...) fflush (errfp); gpg_err_set_errno (saved_errno); + return 0; } diff --git a/src/debug.h b/src/debug.h index d0db5736..6bde998f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -64,7 +64,7 @@ int _gpgme_debug_set_debug_envvar (const char *value); void _gpgme_debug_subsystem_init (void); /* Log the formatted string FORMAT at debug level LEVEL or higher. */ -void _gpgme_debug (int level, const char *format, ...); +int _gpgme_debug (int level, const char *format, ...); /* Start a new debug line in *LINE, logged at level LEVEL or higher, and starting with the formatted string FORMAT. */ @@ -82,7 +82,7 @@ void _gpgme_debug_buffer (int lvl, const char *const fmt, size_t len); void _gpgme_debug_frame_begin (void); -void _gpgme_debug_frame_end (void); +int _gpgme_debug_frame_end (void); static inline gpgme_error_t _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) @@ -108,82 +108,80 @@ _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) #define TRACE_BEG(lvl, name, tag) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_BEG0(lvl, name, tag, fmt) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_BEG1(lvl, name, tag, fmt, arg1) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1), 0 + arg1) #define TRACE_BEG2(lvl, name, tag, fmt, arg1, arg2) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2), 0 + arg1, arg2) #define TRACE_BEG3(lvl, name, tag, fmt, arg1, arg2, arg3) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3), 0 + arg1, arg2, arg3) #define TRACE_BEG4(lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4), 0 + arg1, arg2, arg3, arg4) #define TRACE_BEG5(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5), 0 + arg1, arg2, arg3, arg4, arg5) #define TRACE_BEG7(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ arg5, arg6, arg7) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7), 0 + arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define TRACE_BEG8(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \ arg5, arg6, arg7, arg8) \ _TRACE (lvl, name, tag); \ _gpgme_debug (_gpgme_trace_level, "%s: enter: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7, arg8), 0 + arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) #define TRACE(lvl, name, tag) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE0(lvl, name, tag, fmt) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE1(lvl, name, tag, fmt, arg1) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE2(lvl, name, tag, fmt, arg1, arg2) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ - arg2), _gpgme_debug_frame_end (), 0 + arg2), _gpgme_debug_frame_end () #define TRACE3(lvl, name, tag, fmt, arg1, arg2, arg3) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ - arg2, arg3), _gpgme_debug_frame_end (), 0 + arg2, arg3), _gpgme_debug_frame_end () #define TRACE6(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug_frame_begin (), \ _gpgme_debug (lvl, "%s: call: %s=%p, " fmt "\n", \ name, STRINGIFY (tag), (void *) (uintptr_t) tag, arg1, \ arg2, arg3, arg4, arg5, arg6), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_ERR(err) \ err == 0 ? (TRACE_SUC ()) : \ @@ -203,53 +201,52 @@ _gpgme_trace_gpgme_error (gpgme_error_t err, const char *file, int line) #define TRACE_SUC() \ _gpgme_debug (_gpgme_trace_level, "%s: leave\n", \ - _gpgme_trace_func), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func), _gpgme_debug_frame_end () #define TRACE_SUC0(fmt) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func), _gpgme_debug_frame_end () #define TRACE_SUC1(fmt, arg1) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func, arg1), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func, arg1), _gpgme_debug_frame_end () #define TRACE_SUC2(fmt, arg1, arg2) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ - _gpgme_trace_func, arg1, arg2), _gpgme_debug_frame_end (), 0 + _gpgme_trace_func, arg1, arg2), _gpgme_debug_frame_end () #define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_SUC6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug (_gpgme_trace_level, "%s: leave: " fmt "\n", \ _gpgme_trace_func, arg1, arg2, arg3, arg4, arg5, arg6), \ - _gpgme_debug_frame_end (), 0 + _gpgme_debug_frame_end () #define TRACE_LOG(fmt) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ - _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag), 0 + _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag) #define TRACE_LOG1(fmt, arg1) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1), 0 + arg1) #define TRACE_LOG2(fmt, arg1, arg2) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2), 0 + arg1, arg2) #define TRACE_LOG3(fmt, arg1, arg2, arg3) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3), 0 + arg1, arg2, arg3) #define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4), 0 + arg1, arg2, arg3, arg4) #define TRACE_LOG5(fmt, arg1, arg2, arg3, arg4, arg5) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5), 0 + arg1, arg2, arg3, arg4, arg5) #define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \ _gpgme_debug (_gpgme_trace_level, "%s: check: %s=%p, " fmt "\n", \ _gpgme_trace_func, _gpgme_trace_tagname, _gpgme_trace_tag, \ - arg1, arg2, arg3, arg4, arg5, \ - arg6), 0 + arg1, arg2, arg3, arg4, arg5, arg6) #define TRACE_LOGBUF(buf, len) \ _gpgme_debug_buffer (_gpgme_trace_level, "%s: check: %s", \ From 7addffc0826e7f36afcc7f66268e9ee2a37e2042 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 12:30:11 +0200 Subject: [PATCH 05/13] tests: Add option --secret to run-keylist. Signed-off-by: Werner Koch --- tests/run-keylist.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/run-keylist.c b/tests/run-keylist.c index c0c72022..07c6fa18 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -45,6 +45,7 @@ show_usage (int ex) " --verbose run in verbose mode\n" " --openpgp use the OpenPGP protocol (default)\n" " --cms use the CMS protocol\n" + " --secret list only secret keys\n" " --local use GPGME_KEYLIST_MODE_LOCAL\n" " --extern use GPGME_KEYLIST_MODE_EXTERN\n" " --sigs use GPGME_KEYLIST_MODE_SIGS\n" @@ -70,6 +71,7 @@ main (int argc, char **argv) gpgme_key_t keyarray[100]; int keyidx = 0; gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; + int only_secret = 0; if (argc) { argc--; argv++; } @@ -99,6 +101,11 @@ main (int argc, char **argv) protocol = GPGME_PROTOCOL_CMS; argc--; argv++; } + else if (!strcmp (*argv, "--secret")) + { + only_secret = 1; + argc--; argv++; + } else if (!strcmp (*argv, "--local")) { mode |= GPGME_KEYLIST_MODE_LOCAL; @@ -150,7 +157,7 @@ main (int argc, char **argv) gpgme_set_keylist_mode (ctx, mode); - err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, 0); + err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); fail_if_err (err); while (!(err = gpgme_op_keylist_next (ctx, &key))) From ddbd54ef881bd2c3481d62b89bef7241667b64ee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 12:34:49 +0200 Subject: [PATCH 06/13] Fix regression with gpgsm 2.0 due to "OPTION with-secret". * src/engine-gpgsm.c (gpgsm_assuan_simple_command): Do not terminate on a status lines. -- This bug has been with us since the support for gpgsm: If there is no status line handler but a status line is received anyway the command handling loop terminates and thus the command/answer order gets out of sync. In the case of the bug report this is triggered by sending an option which starts the agent and that starting emits a "PROGRESS" status line. The solution is not to stop reading after a status line but record a possible error code and return that only after OK or ERR. GnuPG-bug-id: 1795 Signed-off-by: Werner Koch --- src/engine-gpgsm.c | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 3a837577..ac6c5fc6 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -564,7 +564,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, engine_status_handler_t status_fnc, void *status_fnc_value) { - gpg_error_t err; + gpg_error_t err, cb_err; char *line; size_t linelen; @@ -572,6 +572,7 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (err) return err; + cb_err = 0; do { err = assuan_read_line (ctx, &line, &linelen); @@ -584,32 +585,45 @@ gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd, if (linelen >= 2 && line[0] == 'O' && line[1] == 'K' && (line[2] == '\0' || line[2] == ' ')) - return 0; + return cb_err; else if (linelen >= 4 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' && line[3] == ' ') - err = atoi (&line[4]); + { + /* We prefer a callback generated error because that one is + more related to gpgme and thus probably more important + than the error returned by the engine. */ + err = cb_err? cb_err : atoi (&line[4]); + } else if (linelen >= 2 && line[0] == 'S' && line[1] == ' ') { - char *rest; - gpgme_status_code_t r; + /* After an error from a status callback we skip all further + status lines. */ + if (!cb_err) + { + char *rest; + gpgme_status_code_t r; - rest = strchr (line + 2, ' '); - if (!rest) - rest = line + linelen; /* set to an empty string */ - else - *(rest++) = 0; + rest = strchr (line + 2, ' '); + if (!rest) + rest = line + linelen; /* set to an empty string */ + else + *(rest++) = 0; - r = _gpgme_parse_status (line + 2); + r = _gpgme_parse_status (line + 2); - if (r >= 0 && status_fnc) - err = status_fnc (status_fnc_value, r, rest); - else - err = gpg_error (GPG_ERR_GENERAL); + if (r >= 0 && status_fnc) + cb_err = status_fnc (status_fnc_value, r, rest); + } } else - err = gpg_error (GPG_ERR_GENERAL); + { + /* Invalid line or INQUIRY. We can't do anything else than + to stop. As with ERR we prefer a status callback + generated error code, though. */ + err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL); + } } while (!err); From 052a9e3c5671d1ab69551f7b0abd0bbf859d4aba Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 14:58:44 +0200 Subject: [PATCH 07/13] Release 1.5.5 --- AUTHORS | 2 +- NEWS | 8 +++++++- configure.ac | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 61974167..dd4b4928 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,7 +3,7 @@ Homepage: http://www.gnupg.org/related_software/gpgme/ Download: ftp://ftp.gnupg.org/gcrypt/gpgme/ Repository: git://git.gnupg.org/gpgme.git Maintainer: Werner Koch -Bug reports: http://bugs.gnupg.org (use category "gpgme") +Bug reports: https://bugs.gnupg.org (use category "gpgme") Security related bug reports: security@gnupg.org License (software): LGPLv2.1+ License (manual+tools): GPLv3+ diff --git a/NEWS b/NEWS index 09cc930d..8e9472a3 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ -Noteworthy changes in version 1.6.0 (unreleased) [C__/A__/R_] +Noteworthy changes in version 1.5.5 (2015-06-08) [C24/A13/R4] ------------------------------------------------ + * Fixed crash in key listings for user ids with a backslash. + + * Fixed regression for GPGSM use with GnuPG < 2.1. + + * Properly set signature summary for revoked OpenPGP keys. + Noteworthy changes in version 1.5.4 (2015-04-13) [C24/A13/R3] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 2f477195..7f03170e 100644 --- a/configure.ac +++ b/configure.ac @@ -28,8 +28,8 @@ min_automake_version="1.14" # commit and push so that the git magic is able to work. See below # for the LT versions. m4_define(mym4_version_major, [1]) -m4_define(mym4_version_minor, [6]) -m4_define(mym4_version_micro, [0]) +m4_define(mym4_version_minor, [5]) +m4_define(mym4_version_micro, [5]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag @@ -59,7 +59,7 @@ LIBGPGME_LT_CURRENT=24 # Subtract 2 from this value if you want to make the LFS transition an # ABI break. [Note to self: Remove this comment with the next regular break.] LIBGPGME_LT_AGE=13 -LIBGPGME_LT_REVISION=3 +LIBGPGME_LT_REVISION=4 # If the API is changed in an incompatible way: increment the next counter. GPGME_CONFIG_API_VERSION=1 From a5d9e018b8826e97c9fcc548c8e9e797bbc8d6db Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 8 Jun 2015 15:18:56 +0200 Subject: [PATCH 08/13] Post release updates -- --- NEWS | 4 ++++ configure.ac | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 8e9472a3..0e1e5009 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Noteworthy changes in version 1.6.0 (unreleased) [C24/A13/R_] +------------------------------------------------ + + Noteworthy changes in version 1.5.5 (2015-06-08) [C24/A13/R4] ------------------------------------------------ diff --git a/configure.ac b/configure.ac index 7f03170e..be36a420 100644 --- a/configure.ac +++ b/configure.ac @@ -28,8 +28,8 @@ min_automake_version="1.14" # commit and push so that the git magic is able to work. See below # for the LT versions. m4_define(mym4_version_major, [1]) -m4_define(mym4_version_minor, [5]) -m4_define(mym4_version_micro, [5]) +m4_define(mym4_version_minor, [6]) +m4_define(mym4_version_micro, [0]) # Below is m4 magic to extract and compute the revision number, the # decimalized short revision number, a beta version string, and a flag From c23f8897105ce2bb6e62d9c44ca0779fcc08a919 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 23 Jul 2015 11:40:09 +0200 Subject: [PATCH 09/13] Add option --lib-version to gpgme-tool. * src/gpgme-tool.c (options, parse_options): Add --lib-version (CMD_LIBVERSION): New. (main): Implement. --- src/gpgme-tool.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index d42179bd..94d11248 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -3728,6 +3728,7 @@ static char args_doc[] = "COMMAND [OPTIONS...]"; static struct argp_option options[] = { { "server", 's', 0, 0, "Server mode" }, { "gpg-binary", 501, "FILE", 0, "Use FILE for the GPG backend" }, + { "lib-version", 502, 0, 0, "Show library version" }, { 0 } }; @@ -3736,7 +3737,7 @@ static struct argp argp = { options, parse_options, args_doc, doc }; struct args { - enum { CMD_DEFAULT, CMD_SERVER } cmd; + enum { CMD_DEFAULT, CMD_SERVER, CMD_LIBVERSION } cmd; const char *gpg_binary; }; @@ -3762,6 +3763,11 @@ parse_options (int key, char *arg, struct argp_state *state) case 501: args->gpg_binary = arg; break; + + case 502: + args->cmd = CMD_LIBVERSION; + break; + #if 0 case ARGP_KEY_ARG: if (state->arg_num >= 2) @@ -3787,6 +3793,7 @@ main (int argc, char *argv[]) struct args args; struct gpgme_tool gt; gpg_error_t err; + int needgt = 1; #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); @@ -3804,7 +3811,10 @@ main (int argc, char *argv[]) argp_parse (&argp, argc, argv, 0, 0, &args); log_init (); - if (args.gpg_binary) + if (args.cmd == CMD_LIBVERSION) + needgt = 0; + + if (needgt && args.gpg_binary) { if (access (args.gpg_binary, X_OK)) err = gpg_error_from_syserror (); @@ -3816,7 +3826,8 @@ main (int argc, char *argv[]) args.gpg_binary); } - gt_init (>); + if (needgt) + gt_init (>); switch (args.cmd) { @@ -3824,9 +3835,17 @@ main (int argc, char *argv[]) case CMD_SERVER: gpgme_server (>); break; + + case CMD_LIBVERSION: + printf ("Version from header: %s (0x%06x)\n", + GPGME_VERSION, GPGME_VERSION_NUMBER); + printf ("Version from binary: %s\n", gpgme_check_version (NULL)); + printf ("Copyright blurb ...:%s\n", gpgme_check_version ("\x01\x01")); + break; } - gpgme_release (gt.ctx); + if (needgt) + gpgme_release (gt.ctx); #ifdef HAVE_W32CE_SYSTEM /* Give the buggy ssh server time to flush the output buffers. */ From 157c8be183153ff588f98874a3205aa483d0fd23 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Thu, 9 Jul 2015 17:11:33 +0200 Subject: [PATCH 10/13] build: ignore scissor line for the commit-msg hook * build-aux/git-hooks/commit-msg: Stop processing more lines when the scissor line is encountered. -- This allows the command `git commit -v` to work even if the code is longer than 72 characters. Note that comments are already ignored by the previous line. Signed-off-by: Peter Wu --- build-aux/git-hooks/commit-msg | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build-aux/git-hooks/commit-msg b/build-aux/git-hooks/commit-msg index 5a697c7a..3ca918b2 100755 --- a/build-aux/git-hooks/commit-msg +++ b/build-aux/git-hooks/commit-msg @@ -86,11 +86,17 @@ sub check_msg($$) 2 <= @line && length $line[1] and return 'second line must be empty'; + # See git-commit(1), this is the --cleanup=scissors option. Everything + # after and including this line gets ignored. + my $marker = '# ------------------------ >8 ------------------------'; + # Limit line length to allow for the ChangeLog's leading TAB. foreach my $line (@line) { 72 < length $line && $line =~ /^[^#]/ and return 'line longer than 72 characters'; + + last if $line eq $marker; } return ''; From 08086dd6901740e155e4361212b4e9cff8a47296 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Thu, 2 Jul 2015 10:19:04 +0200 Subject: [PATCH 11/13] Add offline mode support for CMS keylisting * doc/gpgme.texi: Document offline mode. * src/context.h (gpgme_context): Add offline. * src/engine-backend.h (keylist, keylist_ext): Add engine_flags. * src/engine.c, src/engine.h (_gpgme_engine_op_keylist): Ditto. (_gpgme_engine_op_keylist_ext): Ditto. * src/engine.h (GPGME_ENGINE_FLAG_OFFLINE): New. * src/engine-gpg.c (gpg_keylist, gpg_keylist_ext): Ditto. * src/engine-gpgsm.c (gpgsm_keylist): Handle engine_flags. (gpgsm_keylist_ext): Ditto. * src/gpgme.c (gpgme_set_offline, gpgme_get_offline): New. * src/gpgme.def (gpgme_set_offline, gpgme_get_offline): New. * src/gpgme.h.in (gpgme_set_offline, gpgme_get_offline): New. * src/libgpgme.vers (gpgme_set_offline, gpgme_get_offline): New. * src/keylist.c (gpgme_op_keylist_start): Set offline flag. (gpgme_op_keylist_ext_start): Ditto. * tests/run-keylist.c (show_usage, main): Add offline argument. -- The offline engine option was introduced with gpgsm 2.1.6 it is mainly useful for a full keylisting that includes the certificate validation but does not depend on external information that could take an indefinite amount of time to collect. Signed-off-by: Andre Heinecke --- doc/gpgme.texi | 33 +++++++++++++++++++++++++++++++++ src/context.h | 3 +++ src/engine-backend.h | 6 ++++-- src/engine-gpg.c | 4 ++-- src/engine-gpgsm.c | 15 ++++++++++++--- src/engine.c | 10 ++++++---- src/engine.h | 9 +++++++-- src/gpgme.c | 24 ++++++++++++++++++++++++ src/gpgme.def | 3 +++ src/gpgme.h.in | 6 ++++++ src/keylist.c | 13 +++++++++++-- src/libgpgme.vers | 3 +++ tests/run-keylist.c | 9 +++++++++ 13 files changed, 123 insertions(+), 15 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 45c359d0..ef4936dd 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -189,6 +189,7 @@ Context Attributes * Crypto Engine:: Configuring the crypto engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. +* Offline Mode:: Choosing offline mode. * Included Certificates:: Including a number of certificates. * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. @@ -2285,6 +2286,7 @@ started. In fact, these references are accessed through the * Crypto Engine:: Configuring the crypto engine. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. +* Offline Mode:: Choosing offline mode. * Included Certificates:: Including a number of certificates. * Key Listing Mode:: Selecting key listing mode. * Passphrase Callback:: Getting the passphrase from the user. @@ -2413,6 +2415,37 @@ valid pointer. @end deftypefun +@node Offline Mode +@subsection Offline Mode +@cindex context, offline mode +@cindex offline mode + +@deftypefun void gpgme_set_offline (@w{gpgme_ctx_t @var{ctx}}, @w{int @var{yes}}) +The function @code{gpgme_set_offline} specifies if offline mode +should be used. By default, offline mode is not used. + +The offline mode specifies if dirmngr should be used to do additional +validation that might require connections to external services. +(e.g. CRL / OCSP checks). + +Offline mode only affects the keylist mode @code{GPGME_KEYLIST_MODE_VALIDATE} +and is only relevant to the CMS crypto engine. Offline mode +is ignored otherwise. + +This option may be extended in the future to completely disable +the use of dirmngr for any engine. + +Offline mode is disabled if @var{yes} is zero, and enabled +otherwise. +@end deftypefun + +@deftypefun int gpgme_get_offline (@w{gpgme_ctx_t @var{ctx}}) +The function @code{gpgme_get_offline} returns 1 if offline +mode is enabled, and @code{0} if it is not, or if @var{ctx} is not a +valid pointer. +@end deftypefun + + @node Included Certificates @subsection Included Certificates @cindex certificates, included diff --git a/src/context.h b/src/context.h index 745ffa89..8cd86e9c 100644 --- a/src/context.h +++ b/src/context.h @@ -98,6 +98,9 @@ struct gpgme_context /* True if text mode should be used. */ unsigned int use_textmode : 1; + /* True if offline mode should be used. */ + unsigned int offline : 1; + /* Flags for keylist mode. */ gpgme_keylist_mode_t keylist_mode; diff --git a/src/engine-backend.h b/src/engine-backend.h index b3cc412a..4f4519c0 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -85,10 +85,12 @@ struct engine_ops gpgme_error_t (*import) (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray); gpgme_error_t (*keylist) (void *engine, const char *pattern, - int secret_only, gpgme_keylist_mode_t mode); + int secret_only, gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t (*sign) (void *engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, int use_textmode, int include_certs, diff --git a/src/engine-gpg.c b/src/engine-gpg.c index e14fd8dd..510dfd9d 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2279,7 +2279,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only, static gpgme_error_t gpg_keylist (void *engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { engine_gpg_t gpg = engine; gpgme_error_t err; @@ -2298,7 +2298,7 @@ gpg_keylist (void *engine, const char *pattern, int secret_only, static gpgme_error_t gpg_keylist_ext (void *engine, const char *pattern[], int secret_only, - int reserved, gpgme_keylist_mode_t mode) + int reserved, gpgme_keylist_mode_t mode, int engine_flags) { engine_gpg_t gpg = engine; gpgme_error_t err; diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index ac6c5fc6..37711574 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1542,7 +1542,7 @@ gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) static gpgme_error_t gpgsm_keylist (void *engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { engine_gpgsm_t gpgsm = engine; char *line; @@ -1599,6 +1599,11 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? + "OPTION offline=1": + "OPTION offline=0" , + NULL, NULL); /* Length is "LISTSECRETKEYS " + p + '\0'. */ @@ -1629,7 +1634,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, static gpgme_error_t gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, - int reserved, gpgme_keylist_mode_t mode) + int reserved, gpgme_keylist_mode_t mode, int engine_flags) { engine_gpgsm_t gpgsm = engine; char *line; @@ -1669,7 +1674,11 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, "OPTION with-secret=1": "OPTION with-secret=0" , NULL, NULL); - + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)? + "OPTION offline=1": + "OPTION offline=0" , + NULL, NULL); if (pattern && *pattern) { diff --git a/src/engine.c b/src/engine.c index ff015c00..8e84da95 100644 --- a/src/engine.c +++ b/src/engine.c @@ -726,7 +726,8 @@ _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata, gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, const char *pattern, - int secret_only, gpgme_keylist_mode_t mode) + int secret_only, gpgme_keylist_mode_t mode, + int engine_flags) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -734,14 +735,15 @@ _gpgme_engine_op_keylist (engine_t engine, const char *pattern, if (!engine->ops->keylist) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode); + return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode, + engine_flags); } gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode) + gpgme_keylist_mode_t mode, int engine_flags) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -750,7 +752,7 @@ _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only, - reserved, mode); + reserved, mode, engine_flags); } diff --git a/src/engine.h b/src/engine.h index bbf009d6..56fcc420 100644 --- a/src/engine.h +++ b/src/engine.h @@ -113,12 +113,14 @@ gpgme_error_t _gpgme_engine_op_import (engine_t engine, gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, const char *pattern, int secret_only, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[], int secret_only, int reserved, - gpgme_keylist_mode_t mode); + gpgme_keylist_mode_t mode, + int engine_flags); gpgme_error_t _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out, gpgme_sig_mode_t mode, int use_armor, int use_textmode, @@ -170,5 +172,8 @@ gpgme_error_t _gpgme_engine_op_spawn (engine_t engine, gpgme_data_t dataerr, unsigned int flags); +/* The available engine option flags. */ +#define GPGME_ENGINE_FLAG_OFFLINE 1 + #endif /* ENGINE_H */ diff --git a/src/gpgme.c b/src/gpgme.c index 628cdaee..c24b6200 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -472,6 +472,30 @@ gpgme_get_textmode (gpgme_ctx_t ctx) } +/* Enable offline mode for this context. In offline mode dirmngr + will be disabled. */ +void +gpgme_set_offline (gpgme_ctx_t ctx, int offline) +{ + TRACE2 (DEBUG_CTX, "gpgme_set_offline", ctx, "offline=%i (%s)", + offline, offline ? "yes" : "no"); + + if (!ctx) + return; + + ctx->offline = offline; +} + +/* Return the state of the offline flag. */ +int +gpgme_get_offline (gpgme_ctx_t ctx) +{ + TRACE2 (DEBUG_CTX, "gpgme_get_offline", ctx, "ctx->offline=%i (%s)", + ctx->offline, ctx->offline ? "yes" : "no"); + return ctx->offline; +} + + /* Set the number of certifications to include in an S/MIME message. The default is GPGME_INCLUDE_CERTS_DEFAULT. -1 means all certs, and -2 means all certs except the root cert. */ diff --git a/src/gpgme.def b/src/gpgme.def index dc189484..cf167b4f 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -217,5 +217,8 @@ EXPORTS gpgme_op_spawn_start @163 gpgme_op_spawn @164 + + gpgme_set_offline @165 + gpgme_get_offline @166 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 15ed8037..099cc8a5 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -887,6 +887,12 @@ void gpgme_set_textmode (gpgme_ctx_t ctx, int yes); /* Return non-zero if text mode is set in CTX. */ int gpgme_get_textmode (gpgme_ctx_t ctx); +/* If YES is non-zero, enable offline mode in CTX, disable it otherwise. */ +void gpgme_set_offline (gpgme_ctx_t ctx, int yes); + +/* Return non-zero if offline mode is set in CTX. */ +int gpgme_get_offline (gpgme_ctx_t ctx); + /* Use whatever the default of the backend crypto engine is. */ #define GPGME_INCLUDE_CERTS_DEFAULT -256 diff --git a/src/keylist.c b/src/keylist.c index 36ee3eaa..fcf574fc 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -889,6 +889,7 @@ gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) gpgme_error_t err; void *hook; op_data_t opd; + int flags = 0; TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_start", ctx, "pattern=%s, secret_only=%i", pattern, secret_only); @@ -913,8 +914,11 @@ gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only) if (err) return TRACE_ERR (err); + if (ctx->offline) + flags |= GPGME_ENGINE_FLAG_OFFLINE; + err = _gpgme_engine_op_keylist (ctx->engine, pattern, secret_only, - ctx->keylist_mode); + ctx->keylist_mode, flags); return TRACE_ERR (err); } @@ -929,6 +933,7 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], gpgme_error_t err; void *hook; op_data_t opd; + int flags = 0; TRACE_BEG2 (DEBUG_CTX, "gpgme_op_keylist_ext_start", ctx, "secret_only=%i, reserved=0x%x", secret_only, reserved); @@ -952,8 +957,12 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[], if (err) return TRACE_ERR (err); + if (ctx->offline) + flags |= GPGME_ENGINE_FLAG_OFFLINE; + err = _gpgme_engine_op_keylist_ext (ctx->engine, pattern, secret_only, - reserved, ctx->keylist_mode); + reserved, ctx->keylist_mode, + flags); return TRACE_ERR (err); } diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 39663c1c..fc2920f8 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -92,6 +92,9 @@ GPGME_1.1 { gpgme_op_spawn_start; gpgme_op_spawn; + + gpgme_set_offline; + gpgme_get_offline; }; diff --git a/tests/run-keylist.c b/tests/run-keylist.c index 07c6fa18..8abdf43d 100644 --- a/tests/run-keylist.c +++ b/tests/run-keylist.c @@ -53,6 +53,7 @@ show_usage (int ex) " --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n" " --validate use GPGME_KEYLIST_MODE_VALIDATE\n" " --import import all keys\n" + " --offline use offline mode\n" , stderr); exit (ex); } @@ -72,6 +73,7 @@ main (int argc, char **argv) int keyidx = 0; gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP; int only_secret = 0; + int offline = 0; if (argc) { argc--; argv++; } @@ -141,6 +143,11 @@ main (int argc, char **argv) import = 1; argc--; argv++; } + else if (!strcmp (*argv, "--offline")) + { + offline = 1; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -157,6 +164,8 @@ main (int argc, char **argv) gpgme_set_keylist_mode (ctx, mode); + gpgme_set_offline (ctx, offline); + err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, only_secret); fail_if_err (err); From 8f28e3caf95d7bc99e9271bfc2b44080166af31f Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Mon, 10 Aug 2015 21:23:02 -0400 Subject: [PATCH 12/13] Check the return value when starting gpg. * src/engine-gpg.c (gpg_decrypt, gpg_delete, gpg_passwd): Check return value of start(). --- src/engine-gpg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 510dfd9d..c3e36aeb 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1456,7 +1456,7 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) err = add_data (gpg, ciph, -1, 0); if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1479,7 +1479,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret) } if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1497,7 +1497,7 @@ gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags) if (!err) err = add_arg (gpg, key->subkeys->fpr); if (!err) - start (gpg); + err = start (gpg); return err; } From e07d38f5f9f3b94e403f1265ff7fd3d7009dd557 Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Wed, 12 Aug 2015 06:46:43 -0400 Subject: [PATCH 13/13] Also check the return code in gpg_sign(). * src/engine-gpg.c (gpg_sign): Check return value from start(). --- src/engine-gpg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine-gpg.c b/src/engine-gpg.c index c3e36aeb..d1385926 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2364,7 +2364,7 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, err = add_data (gpg, out, 1, 1); if (!err) - start (gpg); + err = start (gpg); return err; }