diff options
author | JinWang An <jinwang.an@samsung.com> | 2021-12-01 16:54:35 +0900 |
---|---|---|
committer | JinWang An <jinwang.an@samsung.com> | 2021-12-01 16:54:35 +0900 |
commit | fd5caec0dccd1229c2b9dd5220c8e2b1ef966d0e (patch) | |
tree | 9a62094ccb327ef754b15997559dc60fd9b3cc25 /src | |
parent | 1c25bd8f2d05ddcc1502bc0d59e23e038dfa6d60 (diff) | |
download | gpgme-fd5caec0dccd1229c2b9dd5220c8e2b1ef966d0e.tar.gz gpgme-fd5caec0dccd1229c2b9dd5220c8e2b1ef966d0e.tar.bz2 gpgme-fd5caec0dccd1229c2b9dd5220c8e2b1ef966d0e.zip |
Imported Upstream version 1.6.0upstream/1.6.0
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 4 | ||||
-rw-r--r-- | src/context.h | 7 | ||||
-rw-r--r-- | src/debug.c | 12 | ||||
-rw-r--r-- | src/decrypt.c | 19 | ||||
-rw-r--r-- | src/encrypt.c | 9 | ||||
-rw-r--r-- | src/engine-assuan.c | 10 | ||||
-rw-r--r-- | src/engine-backend.h | 6 | ||||
-rw-r--r-- | src/engine-g13.c | 10 | ||||
-rw-r--r-- | src/engine-gpg.c | 33 | ||||
-rw-r--r-- | src/engine-gpgsm.c | 58 | ||||
-rw-r--r-- | src/engine-uiserver.c | 10 | ||||
-rw-r--r-- | src/engine.c | 10 | ||||
-rw-r--r-- | src/engine.h | 9 | ||||
-rw-r--r-- | src/export.c | 35 | ||||
-rw-r--r-- | src/genkey.c | 26 | ||||
-rw-r--r-- | src/gpgme-tool.c | 35 | ||||
-rw-r--r-- | src/gpgme.c | 65 | ||||
-rw-r--r-- | src/gpgme.def | 6 | ||||
-rw-r--r-- | src/gpgme.h.in | 485 | ||||
-rw-r--r-- | src/keylist.c | 13 | ||||
-rw-r--r-- | src/libgpgme.vers | 6 | ||||
-rw-r--r-- | src/op-support.c | 24 | ||||
-rw-r--r-- | src/ops.h | 4 | ||||
-rw-r--r-- | src/passphrase.c | 43 | ||||
-rw-r--r-- | src/passwd.c | 9 | ||||
-rw-r--r-- | src/sign.c | 15 | ||||
-rw-r--r-- | src/status-table.c | 2 | ||||
-rw-r--r-- | src/sys-util.h | 4 | ||||
-rw-r--r-- | src/verify.c | 9 | ||||
-rw-r--r-- | src/versioninfo.rc.in | 2 | ||||
-rw-r--r-- | src/w32-util.c | 132 |
31 files changed, 781 insertions, 331 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index bdfcaf2..ec839e4 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -107,8 +107,8 @@ 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 setenv.c funopen.c stpcpy.c \ - vasprintf.c ttyname_r.c $(top_srcdir)/build-aux/depcomp + $(srcdir)/gpgme-config.in stpcpy.c funopen.c vasprintf.c \ + setenv.c ttyname_r.c $(top_srcdir)/build-aux/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/glib-2.0.m4 \ $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/gnupg-ttyname.m4 \ diff --git a/src/context.h b/src/context.h index 745ffa8..757d9b4 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; @@ -132,6 +135,10 @@ struct gpgme_context gpgme_progress_cb_t progress_cb; void *progress_cb_value; + /* The user provided status callback and its hook value. */ + gpgme_status_cb_t status_cb; + void *status_cb_value; + /* A list of file descriptors in active use by the current operation. */ struct fd_table fdt; diff --git a/src/debug.c b/src/debug.c index 292db55..1dd3723 100644 --- a/src/debug.c +++ b/src/debug.c @@ -46,6 +46,7 @@ #include "util.h" #include "ath.h" #include "sema.h" +#include "sys-util.h" #include "debug.h" @@ -207,7 +208,16 @@ debug_init (void) UNLOCK (debug_lock); if (debug_level > 0) - _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level); + { + _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level); +#ifdef HAVE_W32_SYSTEM + { + const char *name = _gpgme_get_inst_dir (); + _gpgme_debug (DEBUG_INIT, "gpgme_debug: gpgme='%s'\n", + name? name: "?"); + } +#endif + } } diff --git a/src/decrypt.c b/src/decrypt.c index 4742060..4db68a1 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_decrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int okay; int failed; @@ -192,6 +195,10 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: These error values should probably be attributed to the underlying crypto engine (as error source). */ @@ -199,6 +206,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); + else if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_DECRYPTION_INFO: @@ -291,6 +300,16 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; + break; + + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); + if (err) + return err; + } + break; default: break; diff --git a/src/encrypt.c b/src/encrypt.c index 792c25c..9f5134d 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -36,6 +36,9 @@ typedef struct { struct _gpgme_op_encrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid recipient in the list. This makes appending new invalid recipients painless while preserving the order. */ @@ -114,9 +117,15 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (opd->result.invalid_recipients) return gpg_error (GPG_ERR_UNUSABLE_PUBKEY); + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_INV_RECP: diff --git a/src/engine-assuan.c b/src/engine-assuan.c index 663b2ea..9902467 100644 --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -282,12 +282,10 @@ llass_new (void **engine, const char *file_name, const char *home_dir) char *dft_ttytype = NULL; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine-backend.h b/src/engine-backend.h index b3cc412..4f4519c 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-g13.c b/src/engine-g13.c index a9717ee..4a7b75c 100644 --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -286,12 +286,10 @@ g13_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine-gpg.c b/src/engine-gpg.c index e14fd8d..9efced2 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -513,6 +513,8 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) rc = add_arg (gpg, dft_display); free (dft_display); + if (rc) + goto leave; } if (isatty (1)) @@ -520,9 +522,10 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) int err; err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (err) - rc = gpg_error_from_errno (err); - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!err) { if (*dft_ttyname) { @@ -547,9 +550,9 @@ gpg_new (void **engine, const char *file_name, const char *home_dir) free (dft_ttytype); } + if (rc) + goto leave; } - if (rc) - goto leave; } leave: @@ -1456,7 +1459,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 +1482,7 @@ gpg_delete (void *engine, gpgme_key_t key, int allow_secret) } if (!err) - start (gpg); + err = start (gpg); return err; } @@ -1497,7 +1500,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; } @@ -1793,7 +1796,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, gpgme_error_t err = 0; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET))) return gpg_error (GPG_ERR_NOT_SUPPORTED); if ((mode & GPGME_EXPORT_MODE_MINIMAL)) @@ -1807,7 +1811,10 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, } else { - err = add_arg (gpg, "--export"); + if ((mode & GPGME_EXPORT_MODE_SECRET)) + err = add_arg (gpg, "--export-secret-keys"); + else + err = add_arg (gpg, "--export"); if (!err && use_armor) err = add_arg (gpg, "--armor"); if (!err) @@ -2279,7 +2286,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 +2305,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; @@ -2364,7 +2371,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; } diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index ac6c5fc..476e9ef 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -408,12 +408,10 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { @@ -1289,17 +1287,23 @@ gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - if (mode) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - if (!pattern) pattern = ""; - cmd = malloc (7 + strlen (pattern) + 1); + cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1); if (!cmd) return gpg_error_from_syserror (); + strcpy (cmd, "EXPORT "); - strcpy (&cmd[7], pattern); + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + strcat (cmd, "--secret "); + if ((mode & GPGME_EXPORT_MODE_RAW)) + strcat (cmd, "--raw "); + else if ((mode & GPGME_EXPORT_MODE_PKCS12)) + strcat (cmd, "--pkcs12 "); + } + strcat (cmd, pattern); gpgsm->output_cb.data = keydata; err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor" @@ -1323,16 +1327,13 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, engine_gpgsm_t gpgsm = engine; gpgme_error_t err = 0; char *line; - /* Length is "EXPORT " + p + '\0'. */ - int length = 7 + 1; + /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'. */ + int length = 7 + 9 + 9 + 1; char *linep; if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - if (mode) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - if (pattern && *pattern) { const char **pat = pattern; @@ -1357,7 +1358,15 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, return gpg_error_from_syserror (); strcpy (line, "EXPORT "); - linep = &line[7]; + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + strcat (line, "--secret "); + if ((mode & GPGME_EXPORT_MODE_RAW)) + strcat (line, "--raw "); + else if ((mode & GPGME_EXPORT_MODE_PKCS12)) + strcat (line, "--pkcs12 "); + } + linep = &line[strlen (line)]; if (pattern && *pattern) { @@ -1542,7 +1551,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 +1608,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 +1643,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 +1683,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-uiserver.c b/src/engine-uiserver.c index a7184b7..e4fd47c 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -326,12 +326,10 @@ uiserver_new (void **engine, const char *file_name, const char *home_dir) int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); - if (rc) - { - err = gpg_error_from_errno (rc); - goto leave; - } - else + + /* Even though isatty() returns 1, ttyname_r() may fail in many + ways, e.g., when /dev/pts is not accessible under chroot. */ + if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { diff --git a/src/engine.c b/src/engine.c index ff015c0..8e84da9 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 bbf009d..56fcc42 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/export.c b/src/export.c index 8930aa6..a29fbde 100644 --- a/src/export.c +++ b/src/export.c @@ -120,9 +120,24 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + if ((mode & GPGME_EXPORT_MODE_RAW) + && (mode & GPGME_EXPORT_MODE_PKCS12)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + + if (ctx->protocol != GPGME_PROTOCOL_CMS + && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_INV_FLAG); /* Only supported for X.509. */ + } if ((mode & GPGME_EXPORT_MODE_EXTERN)) { @@ -199,9 +214,25 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], op_data_t opd; if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL))) + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ + if ((mode & GPGME_EXPORT_MODE_SECRET)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + if ((mode & GPGME_EXPORT_MODE_RAW) + && (mode & GPGME_EXPORT_MODE_PKCS12)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + + if (ctx->protocol != GPGME_PROTOCOL_CMS + && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_INV_FLAG); /* Only supported for X.509. */ + } + if ((mode & GPGME_EXPORT_MODE_EXTERN)) { if (keydata) diff --git a/src/genkey.c b/src/genkey.c index fd6685e..3afd3b4 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -37,6 +37,9 @@ typedef struct { struct _gpgme_op_genkey_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* The key parameters passed to the crypto engine. */ gpgme_data_t key_parameter; } *op_data_t; @@ -118,10 +121,25 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) } break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: Should return some more useful error value. */ if (!opd->result.primary && !opd->result.sub) return gpg_error (GPG_ERR_GENERAL); + else if (opd->failure_code) + return opd->failure_code; + break; + + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); + if (err) + return err; + } break; default: @@ -186,6 +204,14 @@ genkey_start (gpgme_ctx_t ctx, int synchronous, const char *parms, _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx); + if (ctx->passphrase_cb) + { + err = _gpgme_engine_set_command_handler + (ctx->engine, _gpgme_passphrase_command_handler, ctx, NULL); + if (err) + return err; + } + return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter, ctx->use_armor, pubkey, seckey); } diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index d42179b..e5e5707 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -3054,7 +3054,7 @@ cmd_import (assuan_context_t ctx, char *line) static const char hlp_export[] = - "EXPORT [--extern] [--minimal] [<pattern>]\n" + "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n" "\n" "Export the keys described by PATTERN. Write the\n" "the output to the object set by the last OUTPUT command."; @@ -3082,6 +3082,12 @@ cmd_export (assuan_context_t ctx, char *line) mode |= GPGME_EXPORT_MODE_EXTERN; if (has_option (line, "--minimal")) mode |= GPGME_EXPORT_MODE_MINIMAL; + if (has_option (line, "--secret")) + mode |= GPGME_EXPORT_MODE_SECRET; + if (has_option (line, "--raw")) + mode |= GPGME_EXPORT_MODE_RAW; + if (has_option (line, "--pkcs12")) + mode |= GPGME_EXPORT_MODE_PKCS12; line = skip_options (line); @@ -3728,6 +3734,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 +3743,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 +3769,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 +3799,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 +3817,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 +3832,8 @@ main (int argc, char *argv[]) args.gpg_binary); } - gt_init (>); + if (needgt) + gt_init (>); switch (args.cmd) { @@ -3824,9 +3841,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. */ diff --git a/src/gpgme.c b/src/gpgme.c index 628cdae..0cf999a 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. */ @@ -632,6 +656,47 @@ gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *r_cb, } +/* This function sets a callback function to be used as a status + message forwarder. */ +void +gpgme_set_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t cb, void *cb_value) +{ + TRACE2 (DEBUG_CTX, "gpgme_set_status_cb", ctx, "status_cb=%p/%p", + cb, cb_value); + + if (!ctx) + return; + + ctx->status_cb = cb; + ctx->status_cb_value = cb_value; +} + + +/* This function returns the callback function to be used as a + status message forwarder. */ +void +gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *r_cb, + void **r_cb_value) +{ + TRACE2 (DEBUG_CTX, "gpgme_get_status_cb", ctx, "ctx->status_cb=%p/%p", + ctx ? ctx->status_cb : NULL, ctx ? ctx->status_cb_value : NULL); + + if (r_cb) + *r_cb = NULL; + + if (r_cb_value) + *r_cb_value = NULL; + + if (!ctx || !ctx->status_cb) + return; + + if (r_cb) + *r_cb = ctx->status_cb; + if (r_cb_value) + *r_cb_value = ctx->status_cb_value; +} + + /* Set the I/O callback functions for CTX to IO_CBS. */ void gpgme_set_io_cbs (gpgme_ctx_t ctx, gpgme_io_cbs_t io_cbs) diff --git a/src/gpgme.def b/src/gpgme.def index dc18948..a3f5fb4 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -217,5 +217,11 @@ EXPORTS gpgme_op_spawn_start @163 gpgme_op_spawn @164 + + gpgme_set_offline @165 + gpgme_get_offline @166 + + gpgme_set_status_cb @167 + gpgme_get_status_cb @168 ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 15ed803..6cea2c7 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1,36 +1,28 @@ /* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*- - Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 - 2010, 2011, 2012, 2013, 2014 g10 Code GmbH - - This file is part of GPGME. - - GPGME is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - GPGME is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, see <http://www.gnu.org/licenses/>. - - Generated from gpgme.h.in for @GPGME_CONFIG_HOST@. */ + * Copyright (C) 2000 Werner Koch (dd9jn) + * Copyright (C) 2001-2015 g10 Code GmbH + * + * This file is part of GPGME. + * + * GPGME is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * GPGME is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Generated from gpgme.h.in for @GPGME_CONFIG_HOST@. + */ #ifndef GPGME_H #define GPGME_H -#ifdef __GNUC__ -#define _GPGME_INLINE __inline__ -#elif __STDC_VERSION__ >= 199901L -#define _GPGME_INLINE inline -#else -#define _GPGME_INLINE -#endif - /* Include stdio.h for the FILE type definition. */ #include <stdio.h> #include <time.h> @@ -38,29 +30,60 @@ #ifdef __cplusplus extern "C" { -#if 0 /* just to make Emacs auto-indent happy */ +#if 0 /*(Make Emacsen's auto-indent happy.)*/ } #endif #endif /* __cplusplus */ + +/* The version of this header should match the one of the library. Do + not use this symbol in your application, use gpgme_check_version + instead. The purpose of this macro is to let autoconf (using the + AM_PATH_GPGME macro) check that this header matches the installed + library. */ +#define GPGME_VERSION "@PACKAGE_VERSION@" + +/* The version number of this header. It may be used to handle minor + API incompatibilities. */ +#define GPGME_VERSION_NUMBER @VERSION_NUMBER@ + + +/* System specific typedefs. */ @INSERT__TYPEDEFS_FOR_GPGME_H@ + -/* Check for compiler features. */ -#if __GNUC__ -#define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - -#if _GPGME_GCC_VERSION > 30100 -#define _GPGME_DEPRECATED __attribute__ ((__deprecated__)) -#endif +/* + * Check for compiler features. + */ +#ifdef GPGRT_INLINE +# define _GPGME_INLINE GPGRT_INLINE +#elif defined(__GNUC__) +# define _GPGME_INLINE __inline__ +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define _GPGME_INLINE inline +#else +# define _GPGME_INLINE #endif -#ifndef _GPGME_DEPRECATED -#define _GPGME_DEPRECATED + +#ifdef GPGRT_ATTR_DEPRECATED +# define _GPGME_DEPRECATED GPGRT_ATTR_DEPRECATED +#elif defined(__GNUC__) +# define _GPGME_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + +# if _GPGME_GCC_VERSION > 30100 +# define _GPGME_DEPRECATED __attribute__ ((__deprecated__)) +# else +# define _GPGME_DEPRECATED +# endif +#else +# define _GPGME_DEPRECATED #endif + /* The macro _GPGME_DEPRECATED_OUTSIDE_GPGME suppresses warnings for fields we must access in GPGME for ABI compatibility. */ #ifdef _GPGME_IN_GPGME @@ -69,17 +92,6 @@ extern "C" { #define _GPGME_DEPRECATED_OUTSIDE_GPGME _GPGME_DEPRECATED #endif - -/* The version of this header should match the one of the library. Do - not use this symbol in your application, use gpgme_check_version - instead. The purpose of this macro is to let autoconf (using the - AM_PATH_GPGME macro) check that this header matches the installed - library. */ -#define GPGME_VERSION "@PACKAGE_VERSION@" - -/* The version number of this header. It may be used to handle minor - API incompatibilities. */ -#define GPGME_VERSION_NUMBER @VERSION_NUMBER@ /* Check for a matching _FILE_OFFSET_BITS definition. */ #if @NEED__FILE_OFFSET_BITS@ @@ -94,7 +106,9 @@ extern "C" { -/* Some opaque data types used by GPGME. */ +/* + * Some opaque data types used by GPGME. + */ /* The context holds some global state and configuration options, as well as the results of a crypto operation. */ @@ -105,8 +119,11 @@ typedef struct gpgme_context *gpgme_ctx_t; struct gpgme_data; typedef struct gpgme_data *gpgme_data_t; + -/* Wrappers for the libgpg-error library. */ +/* + * Wrappers for the libgpg-error library. + */ typedef gpg_error_t gpgme_error_t; typedef gpg_err_code_t gpgme_err_code_t; @@ -196,7 +213,12 @@ gpgme_error_from_syserror (void) return gpgme_error (gpgme_err_code_from_syserror ()); } + +/* + * Various constants and types + */ + /* The possible encoding mode of gpgme_data_t objects. */ typedef enum { @@ -210,6 +232,7 @@ typedef enum } gpgme_data_encoding_t; + /* Known data types. */ typedef enum { @@ -226,7 +249,7 @@ typedef enum } gpgme_data_type_t; - + /* Public key algorithms. */ typedef enum { @@ -264,7 +287,7 @@ typedef enum } gpgme_hash_algo_t; - + /* The possible signature stati. Deprecated, use error value in sig status. */ typedef enum @@ -292,7 +315,7 @@ typedef enum } gpgme_sig_mode_t; - + /* The available key and signature attributes. Deprecated, use the individual result structures instead. */ typedef enum @@ -333,7 +356,7 @@ typedef enum _gpgme_attr_t; typedef _gpgme_attr_t gpgme_attr_t _GPGME_DEPRECATED; - + /* The available validities for a trust item or key. */ typedef enum { @@ -346,7 +369,7 @@ typedef enum } gpgme_validity_t; - + /* The available protocols. */ typedef enum { @@ -364,7 +387,7 @@ gpgme_protocol_t; /* Convenience macro for the surprisingly mixed spelling. */ #define GPGME_PROTOCOL_OPENPGP GPGME_PROTOCOL_OpenPGP - + /* The available keylist mode flags. */ #define GPGME_KEYLIST_MODE_LOCAL 1 #define GPGME_KEYLIST_MODE_EXTERN 2 @@ -376,7 +399,7 @@ gpgme_protocol_t; typedef unsigned int gpgme_keylist_mode_t; - + /* The pinentry modes. */ typedef enum { @@ -388,59 +411,21 @@ typedef enum } gpgme_pinentry_mode_t; - + /* The available export mode flags. */ #define GPGME_EXPORT_MODE_EXTERN 2 #define GPGME_EXPORT_MODE_MINIMAL 4 +#define GPGME_EXPORT_MODE_SECRET 16 +#define GPGME_EXPORT_MODE_RAW 32 +#define GPGME_EXPORT_MODE_PKCS12 64 typedef unsigned int gpgme_export_mode_t; - + /* Flags for the audit log functions. */ #define GPGME_AUDITLOG_HTML 1 #define GPGME_AUDITLOG_WITH_HELP 128 - -/* Signature notations. */ - -/* The available signature notation flags. */ -#define GPGME_SIG_NOTATION_HUMAN_READABLE 1 -#define GPGME_SIG_NOTATION_CRITICAL 2 - -typedef unsigned int gpgme_sig_notation_flags_t; - -struct _gpgme_sig_notation -{ - struct _gpgme_sig_notation *next; - - /* If NAME is a null pointer, then VALUE contains a policy URL - rather than a notation. */ - char *name; - - /* The value of the notation data. */ - char *value; - - /* The length of the name of the notation data. */ - int name_len; - - /* The length of the value of the notation data. */ - int value_len; - - /* The accumulated flags. */ - gpgme_sig_notation_flags_t flags; - - /* Notation data is human-readable. */ - unsigned int human_readable : 1; - - /* Notation data is critical. */ - unsigned int critical : 1; - - /* Internal to GPGME, do not use. */ - int _unused : 30; -}; -typedef struct _gpgme_sig_notation *gpgme_sig_notation_t; - - /* The possible stati for the edit operation. */ typedef enum { @@ -544,11 +529,56 @@ typedef enum GPGME_STATUS_PINENTRY_LAUNCHED = 88, GPGME_STATUS_ATTRIBUTE = 89, GPGME_STATUS_BEGIN_SIGNING = 90, - GPGME_STATUS_KEY_NOT_CREATED = 91 + GPGME_STATUS_KEY_NOT_CREATED = 91, + GPGME_STATUS_INQUIRE_MAXLEN = 92, + GPGME_STATUS_FAILURE = 93 } gpgme_status_code_t; + +/* The available signature notation flags. */ +#define GPGME_SIG_NOTATION_HUMAN_READABLE 1 +#define GPGME_SIG_NOTATION_CRITICAL 2 + +typedef unsigned int gpgme_sig_notation_flags_t; + +struct _gpgme_sig_notation +{ + struct _gpgme_sig_notation *next; + + /* If NAME is a null pointer, then VALUE contains a policy URL + rather than a notation. */ + char *name; + + /* The value of the notation data. */ + char *value; + + /* The length of the name of the notation data. */ + int name_len; + + /* The length of the value of the notation data. */ + int value_len; + + /* The accumulated flags. */ + gpgme_sig_notation_flags_t flags; + + /* Notation data is human-readable. */ + unsigned int human_readable : 1; + + /* Notation data is critical. */ + unsigned int critical : 1; + + /* Internal to GPGME, do not use. */ + int _unused : 30; +}; +typedef struct _gpgme_sig_notation *gpgme_sig_notation_t; + + +/* + * Public structures. + */ + /* The engine information structure. */ struct _gpgme_engine_info { @@ -571,7 +601,7 @@ struct _gpgme_engine_info }; typedef struct _gpgme_engine_info *gpgme_engine_info_t; - + /* A subkey from a key. */ struct _gpgme_subkey { @@ -826,8 +856,20 @@ struct _gpgme_key typedef struct _gpgme_key *gpgme_key_t; +/* An invalid key object. */ +struct _gpgme_invalid_key +{ + struct _gpgme_invalid_key *next; + char *fpr; + gpgme_error_t reason; +}; +typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; + + -/* Types for callback functions. */ +/* + * Types for callback functions. + */ /* Request a passphrase from the user. */ typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook, @@ -839,6 +881,11 @@ typedef gpgme_error_t (*gpgme_passphrase_cb_t) (void *hook, typedef void (*gpgme_progress_cb_t) (void *opaque, const char *what, int type, int current, int total); +/* Status messages from gpg. */ +typedef gpgme_error_t (*gpgme_status_cb_t) (void *opaque, const char *keyword, + const char *args); + + /* Interact with the user about an edit operation. */ typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque, gpgme_status_code_t status, @@ -847,7 +894,9 @@ typedef gpgme_error_t (*gpgme_edit_cb_t) (void *opaque, -/* Context management functions. */ +/* + * Context management functions. + */ /* Create a new context and return it in CTX. */ gpgme_error_t gpgme_new (gpgme_ctx_t *ctx); @@ -887,6 +936,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 @@ -930,6 +985,16 @@ void gpgme_set_progress_cb (gpgme_ctx_t c, gpgme_progress_cb_t cb, void gpgme_get_progress_cb (gpgme_ctx_t ctx, gpgme_progress_cb_t *cb, void **hook_value); +/* Set the status callback function in CTX to CB. HOOK_VALUE is + passed as first argument to thes status callback function. */ +void gpgme_set_status_cb (gpgme_ctx_t c, gpgme_status_cb_t cb, + void *hook_value); + +/* Get the current status callback function in *CB and the current + hook value in *HOOK_VALUE. */ +void gpgme_get_status_cb (gpgme_ctx_t ctx, gpgme_status_cb_t *cb, + void **hook_value); + /* This function sets the locale for the context CTX, or the default locale if CTX is a null pointer. */ gpgme_error_t gpgme_set_locale (gpgme_ctx_t ctx, int category, @@ -947,16 +1012,6 @@ gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, const char *file_name, const char *home_dir); - -/* Return a statically allocated string with the name of the public - key algorithm ALGO, or NULL if that name is not known. */ -const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo); - -/* Return a statically allocated string with the name of the hash - algorithm ALGO, or NULL if that name is not known. */ -const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo); - - /* Delete all signers from CTX. */ void gpgme_signers_clear (gpgme_ctx_t ctx); @@ -995,7 +1050,7 @@ const char *gpgme_get_sig_string_attr (gpgme_ctx_t c, int idx, gpgme_error_t gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key) _GPGME_DEPRECATED; - + /* Clear all notation data from the context. */ void gpgme_sig_notation_clear (gpgme_ctx_t ctx); @@ -1011,8 +1066,11 @@ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, /* Get the sig notations for this context. */ gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx); + -/* Run control. */ +/* + * Run control. + */ /* The type of an I/O callback function. */ typedef gpgme_error_t (*gpgme_io_cb_t) (void *data, int fd); @@ -1085,8 +1143,17 @@ gpgme_ctx_t gpgme_wait (gpgme_ctx_t ctx, gpgme_error_t *status, int hang); gpgme_ctx_t gpgme_wait_ext (gpgme_ctx_t ctx, gpgme_error_t *status, gpgme_error_t *op_err, int hang); +/* Cancel a pending asynchronous operation. */ +gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx); + +/* Cancel a pending operation asynchronously. */ +gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx); + + -/* Functions to handle data objects. */ +/* + * Functions to handle data objects. + */ /* Read up to SIZE bytes into buffer BUFFER from the data object with the handle HANDLE. Return the number of characters read, 0 on EOF @@ -1209,14 +1276,20 @@ gpgme_error_t gpgme_data_new_from_filepart (gpgme_data_t *r_dh, gpgme_data_seek instead. */ gpgme_error_t gpgme_data_rewind (gpgme_data_t dh) _GPGME_DEPRECATED; + -/* Key and trust functions. */ +/* + * Key and trust functions. + */ /* Get the key with the fingerprint FPR from the crypto backend. If SECRET is true, get the secret key. */ gpgme_error_t gpgme_get_key (gpgme_ctx_t ctx, const char *fpr, gpgme_key_t *r_key, int secret); +/* Create a dummy key to specify an email address. */ +gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name); + /* Acquire a reference to KEY. */ void gpgme_key_ref (gpgme_key_t key); @@ -1259,26 +1332,12 @@ unsigned long gpgme_key_sig_get_ulong_attr (gpgme_key_t key, int uid_idx, const void *reserved, int idx) _GPGME_DEPRECATED; - -/* Crypto Operations. */ - -/* Cancel a pending asynchronous operation. */ -gpgme_error_t gpgme_cancel (gpgme_ctx_t ctx); - -/* Cancel a pending operation asynchronously. */ -gpgme_error_t gpgme_cancel_async (gpgme_ctx_t ctx); -struct _gpgme_invalid_key -{ - struct _gpgme_invalid_key *next; - char *fpr; - gpgme_error_t reason; -}; -typedef struct _gpgme_invalid_key *gpgme_invalid_key_t; +/* + * Encryption. + */ - -/* Encryption. */ struct _gpgme_op_encrypt_result { /* The list of invalid recipients. */ @@ -1322,7 +1381,9 @@ gpgme_error_t gpgme_op_encrypt_sign (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_data_t plain, gpgme_data_t cipher); -/* Decryption. */ +/* + * Decryption. + */ struct _gpgme_recipient { @@ -1379,7 +1440,10 @@ gpgme_error_t gpgme_op_decrypt_verify (gpgme_ctx_t ctx, gpgme_data_t cipher, gpgme_data_t plain); -/* Signing. */ +/* + * Signing. + */ + struct _gpgme_new_signature { struct _gpgme_new_signature *next; @@ -1435,7 +1499,9 @@ gpgme_error_t gpgme_op_sign (gpgme_ctx_t ctx, gpgme_sig_mode_t mode); -/* Verify. */ +/* + * Verify. + */ /* Flags used for the SUMMARY field in a gpgme_signature_t. */ typedef enum @@ -1524,22 +1590,15 @@ gpgme_error_t gpgme_op_verify (gpgme_ctx_t ctx, gpgme_data_t sig, gpgme_data_t plaintext); -/* Import. */ - -/* The key was new. */ -#define GPGME_IMPORT_NEW 1 - -/* The key contained new user IDs. */ -#define GPGME_IMPORT_UID 2 - -/* The key contained new signatures. */ -#define GPGME_IMPORT_SIG 4 - -/* The key contained new sub keys. */ -#define GPGME_IMPORT_SUBKEY 8 +/* + * Import/Export + */ -/* The key contained a secret key. */ -#define GPGME_IMPORT_SECRET 16 +#define GPGME_IMPORT_NEW 1 /* The key was new. */ +#define GPGME_IMPORT_UID 2 /* The key contained new user IDs. */ +#define GPGME_IMPORT_SIG 4 /* The key contained new signatures. */ +#define GPGME_IMPORT_SUBKEY 8 /* The key contained new sub keys. */ +#define GPGME_IMPORT_SECRET 16 /* The key contained a secret key. */ struct _gpgme_import_status @@ -1560,7 +1619,7 @@ struct _gpgme_import_status }; typedef struct _gpgme_import_status *gpgme_import_status_t; -/* Import. */ +/* Import result object. */ struct _gpgme_op_import_result { /* Number of considered keys. */ @@ -1624,7 +1683,6 @@ gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]); gpgme_error_t gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t keys[]); - /* Export the keys found by PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, gpgme_export_mode_t mode, @@ -1653,7 +1711,10 @@ gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx, -/* Key generation. */ +/* + * Key generation. + */ + struct _gpgme_op_genkey_result { /* A primary key was generated. */ @@ -1681,7 +1742,7 @@ gpgme_error_t gpgme_op_genkey (gpgme_ctx_t ctx, const char *parms, /* Retrieve a pointer to the result of the genkey operation. */ gpgme_genkey_result_t gpgme_op_genkey_result (gpgme_ctx_t ctx); - + /* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret keys are also deleted. */ gpgme_error_t gpgme_op_delete_start (gpgme_ctx_t ctx, const gpgme_key_t key, @@ -1689,7 +1750,12 @@ 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); + +/* + * Key Edit interface + */ + /* Edit the key KEY. Send status and command requests to FNC and output of edit commands to OUT. */ gpgme_error_t gpgme_op_edit_start (gpgme_ctx_t ctx, gpgme_key_t key, @@ -1709,27 +1775,11 @@ gpgme_error_t gpgme_op_card_edit (gpgme_ctx_t ctx, gpgme_key_t key, gpgme_data_t out); -/* Flags for the spawn operations. */ -#define GPGME_SPAWN_DETACHED 1 -#define GPGME_SPAWN_ALLOW_SET_FG 2 - - -/* Run the command FILE with the arguments in ARGV. Connect stdin to - DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data - streams is NULL, connect to /dev/null instead. */ -gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx, - const char *file, const char *argv[], - gpgme_data_t datain, - gpgme_data_t dataout, gpgme_data_t dataerr, - unsigned int flags); -gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx, - const char *file, const char *argv[], - gpgme_data_t datain, - gpgme_data_t dataout, gpgme_data_t dataerr, - unsigned int flags); - -/* Key management functions. */ +/* + * Key listing + */ + struct _gpgme_op_keylist_result { unsigned int truncated : 1; @@ -1766,7 +1816,9 @@ gpgme_error_t gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, -/* Trust items and operations. */ +/* + * Trust items and operations. + */ struct _gpgme_trust_item { @@ -1841,7 +1893,12 @@ int gpgme_trust_item_get_int_attr (gpgme_trust_item_t item, _gpgme_attr_t what, const void *reserved, int idx) _GPGME_DEPRECATED; + +/* + * Audit log + */ + /* Return the auditlog for the current session. This may be called after a successful or failed operation. If no audit log is available GPG_ERR_NO_DATA is returned. */ @@ -1852,7 +1909,33 @@ gpgme_error_t gpgme_op_getauditlog (gpgme_ctx_t ctx, gpgme_data_t output, -/* Low-level Assuan protocol access. */ +/* + * Spawn interface + */ + +/* Flags for the spawn operations. */ +#define GPGME_SPAWN_DETACHED 1 +#define GPGME_SPAWN_ALLOW_SET_FG 2 + + +/* Run the command FILE with the arguments in ARGV. Connect stdin to + DATAIN, stdout to DATAOUT, and STDERR to DATAERR. If one the data + streams is NULL, connect to /dev/null instead. */ +gpgme_error_t gpgme_op_spawn_start (gpgme_ctx_t ctx, + const char *file, const char *argv[], + gpgme_data_t datain, + gpgme_data_t dataout, gpgme_data_t dataerr, + unsigned int flags); +gpgme_error_t gpgme_op_spawn (gpgme_ctx_t ctx, + const char *file, const char *argv[], + gpgme_data_t datain, + gpgme_data_t dataout, gpgme_data_t dataerr, + unsigned int flags); + + +/* + * Low-level Assuan protocol access. + */ typedef gpgme_error_t (*gpgme_assuan_data_cb_t) (void *opaque, const void *data, size_t datalen); @@ -1911,7 +1994,10 @@ gpgme_op_assuan_transact (gpgme_ctx_t ctx, void *status_cb_value) _GPGME_DEPRECATED; -/* Crypto container support. */ +/* + * Crypto container support. + */ + struct _gpgme_op_vfs_mount_result { char *mount_dir; @@ -1932,7 +2018,9 @@ gpgme_error_t gpgme_op_vfs_create (gpgme_ctx_t ctx, gpgme_key_t recp[], unsigned int flags, gpgme_error_t *op_err); -/* Interface to gpgconf(1). */ +/* + * Interface to gpgconf(1). + */ /* The expert level at which a configuration option or group of options should be displayed. See the gpgconf(1) documentation for @@ -2096,15 +2184,11 @@ 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); - -/* UIServer support. */ - -/* Create a dummy key to specify an email address. */ -gpgme_error_t gpgme_key_from_uid (gpgme_key_t *key, const char *name); - -/* Various functions. */ +/* + * Various functions. + */ /* Set special global flags; consult the manual before use. */ int gpgme_set_global_flag (const char *name, const char *value); @@ -2139,19 +2223,28 @@ gpgme_error_t gpgme_set_engine_info (gpgme_protocol_t proto, const char *file_name, const char *home_dir); - -/* Engine support functions. */ - /* Verify that the engine implementing PROTO is installed and available. */ gpgme_error_t gpgme_engine_check_version (gpgme_protocol_t proto); - + +/* Reference counting for result objects. */ void gpgme_result_ref (void *result); void gpgme_result_unref (void *result); +/* Return a statically allocated string with the name of the public + key algorithm ALGO, or NULL if that name is not known. */ +const char *gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo); + +/* Return a statically allocated string with the name of the hash + algorithm ALGO, or NULL if that name is not known. */ +const char *gpgme_hash_algo_name (gpgme_hash_algo_t algo); + + -/* Deprecated types. */ +/* + * Deprecated types. + */ typedef gpgme_ctx_t GpgmeCtx _GPGME_DEPRECATED; typedef gpgme_data_t GpgmeData _GPGME_DEPRECATED; typedef gpgme_error_t GpgmeError _GPGME_DEPRECATED; diff --git a/src/keylist.c b/src/keylist.c index 36ee3ea..fcf574f 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 39663c1..6687571 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -92,6 +92,12 @@ GPGME_1.1 { gpgme_op_spawn_start; gpgme_op_spawn; + + gpgme_set_offline; + gpgme_get_offline; + + gpgme_set_status_cb; + gpgme_get_status_cb; }; diff --git a/src/op-support.c b/src/op-support.c index 2bcb3a3..02940ef 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -337,3 +337,27 @@ _gpgme_parse_plaintext (char *args, char **filenamep) } return 0; } + + +/* Parse a FAILURE status line and return the error code. ARGS is + modified to contain the location part. */ +gpgme_error_t +_gpgme_parse_failure (char *args) +{ + char *where, *which; + + where = strchr (args, ' '); + if (!where) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + + return atoi (which); +} @@ -65,6 +65,10 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key); FILENAMEP. */ gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep); +/* Parse a FAILURE status line and return the error code. ARGS is + modified to contain the location part. */ +gpgme_error_t _gpgme_parse_failure (char *args); + /* From verify.c. */ diff --git a/src/passphrase.c b/src/passphrase.c index 00e9d99..c88e57d 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -41,6 +41,7 @@ typedef struct char *uid_hint; char *passphrase_info; int bad_passphrase; + char *maxlen; } *op_data_t; @@ -53,6 +54,7 @@ release_op_data (void *hook) free (opd->passphrase_info); if (opd->uid_hint) free (opd->uid_hint); + free (opd->maxlen); } @@ -73,6 +75,11 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_INQUIRE_MAXLEN: + free (opd->maxlen); + if (!(opd->maxlen = strdup (args))) + return gpg_error_from_syserror (); + break; case GPGME_STATUS_USERID_HINT: if (opd->uid_hint) free (opd->uid_hint); @@ -109,6 +116,31 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, return gpg_error (GPG_ERR_BAD_PASSPHRASE); break; + case GPGME_STATUS_ERROR: + /* We abuse this status handler to forward ERROR status codes to + the caller. This should better be done in a generic handler, + but for now this is sufficient. */ + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "ERROR", args); + if (err) + return err; + } + break; + + case GPGME_STATUS_FAILURE: + /* We abuse this status handler to forward FAILURE status codes + to the caller. This should better be done in a generic + handler, but for now this is sufficient. */ + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args); + if (err) + return err; + } + break; + + default: /* Ignore all other codes. */ break; @@ -141,9 +173,14 @@ _gpgme_passphrase_command_handler (void *priv, gpgme_status_code_t code, if (processed) *processed = 1; - err = ctx->passphrase_cb (ctx->passphrase_cb_value, - opd->uid_hint, opd->passphrase_info, - opd->bad_passphrase, fd); + if (ctx->status_cb && opd->maxlen) + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", + opd->maxlen); + + if (!err) + err = ctx->passphrase_cb (ctx->passphrase_cb_value, + opd->uid_hint, opd->passphrase_info, + opd->bad_passphrase, fd); /* Reset bad passphrase flag, in case it is correct now. */ opd->bad_passphrase = 0; diff --git a/src/passwd.c b/src/passwd.c index e832026..ff30df0 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -30,6 +30,9 @@ typedef struct { + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int success_seen; int error_seen; } *op_data_t; @@ -92,6 +95,10 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->success_seen = 1; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* In case the OpenPGP engine does not properly implement the passwd command we won't get a success status back and thus we @@ -102,6 +109,8 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) if (ctx->protocol == GPGME_PROTOCOL_OpenPGP && !opd->error_seen && !opd->success_seen) err = gpg_error (GPG_ERR_NOT_SUPPORTED); + else if (opd->failure_code) + err = opd->failure_code; break; default: @@ -39,6 +39,9 @@ typedef struct { struct _gpgme_op_sign_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid signer in the list. This makes appending new invalid signers painless while preserving the order. */ @@ -327,6 +330,10 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->last_signer_p = &(*opd->last_signer_p)->next; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* The UI server does not send information about the created signature. This is irrelevant for this protocol and thus we @@ -335,7 +342,12 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); else if (!opd->sig_created_seen && ctx->protocol != GPGME_PROTOCOL_UISERVER) - err = gpg_error (GPG_ERR_GENERAL); + err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL); + break; + + case GPGME_STATUS_INQUIRE_MAXLEN: + if (ctx->status_cb) + err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); break; default: @@ -369,6 +381,7 @@ sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp) opd = hook; if (err) return err; + opd->failure_code = 0; opd->last_signer_p = &opd->result.invalid_signers; opd->last_sig_p = &opd->result.signatures; opd->ignore_inv_recp = !!ignore_inv_recp; diff --git a/src/status-table.c b/src/status-table.c index b936997..6d428d7 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -66,6 +66,7 @@ static struct status_table_s status_table[] = { "ERRSIG", GPGME_STATUS_ERRSIG }, { "EXPKEYSIG", GPGME_STATUS_EXPKEYSIG }, { "EXPSIG", GPGME_STATUS_EXPSIG }, + { "FAILURE", GPGME_STATUS_FAILURE }, { "FILE_DONE", GPGME_STATUS_FILE_DONE }, { "FILE_ERROR", GPGME_STATUS_FILE_ERROR }, { "FILE_START", GPGME_STATUS_FILE_START }, @@ -80,6 +81,7 @@ static struct status_table_s status_table[] = { "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 }, { "KEY_CREATED", GPGME_STATUS_KEY_CREATED }, diff --git a/src/sys-util.h b/src/sys-util.h index 7180fca..589634b 100644 --- a/src/sys-util.h +++ b/src/sys-util.h @@ -27,4 +27,8 @@ int _gpgme_set_default_gpgconf_name (const char *name); char *_gpgme_get_gpg_path (void); char *_gpgme_get_gpgconf_path (void); +#ifdef HAVE_W32_SYSTEM +const char *_gpgme_get_inst_dir (void); +#endif + #endif /* SYS_UTIL_H */ diff --git a/src/verify.c b/src/verify.c index 84487ee..75914e2 100644 --- a/src/verify.c +++ b/src/verify.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_verify_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + gpgme_signature_t current_sig; int did_prepare_new_sig; int only_newsig_seen; @@ -769,6 +772,10 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) error code if we are not ready to process this status. */ return parse_error (sig, args, !!sig ); + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); @@ -795,6 +802,8 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->current_sig = NULL; } opd->only_newsig_seen = 0; + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_PLAINTEXT: diff --git a/src/versioninfo.rc.in b/src/versioninfo.rc.in index a4ab0af..7f19b30 100644 --- a/src/versioninfo.rc.in +++ b/src/versioninfo.rc.in @@ -39,7 +39,7 @@ BEGIN VALUE "FileDescription", "GPGME - GnuPG Made Easy\0" VALUE "FileVersion", "@LIBGPGME_LT_CURRENT@.@LIBGPGME_LT_AGE@.@LIBGPGME_LT_REVISION@.@BUILD_REVISION@\0" VALUE "InternalName", "gpgme\0" - VALUE "LegalCopyright", "Copyright © 2001-2013 g10 Code GmbH\0" + VALUE "LegalCopyright", "Copyright © 2001-2015 g10 Code GmbH\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "gpgme.dll\0" VALUE "PrivateBuild", "\0" diff --git a/src/w32-util.c b/src/w32-util.c index daf3bd2..9aba26f 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -398,40 +398,6 @@ find_program_in_dir (const char *dir, const char *name) static char * -find_program_in_inst_dir (const char *inst_dir, const char *name) -{ - char *result; - char *dir; - - /* If an installation directory has been passed, this overrides a - location given by the registry. The idea here is that we prefer - a program installed alongside with gpgme. We don't want the - registry to override this to have a better isolation of an gpgme - aware applications for other effects. Note that the "Install - Directory" registry item has been used for ages in Gpg4win and - earlier GnuPG windows installers. It is technically not anymore - required. */ - if (inst_dir) - { - result = find_program_in_dir (inst_dir, name); - if (result) - return result; - } - - dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", - "Software\\GNU\\GnuPG", - "Install Directory"); - if (dir) - { - result = find_program_in_dir (dir, name); - free (dir); - return result; - } - return NULL; -} - - -static char * find_program_at_standard_place (const char *name) { char path[MAX_PATH]; @@ -491,29 +457,50 @@ _gpgme_set_default_gpgconf_name (const char *name) /* Return the full file name of the GPG binary. This function is used - if gpgconf was not found and thus it can be assumed that gpg2 is + iff gpgconf was not found and thus it can be assumed that gpg2 is not installed. This function is only called by get_gpgconf_item and may not be called concurrently. */ char * _gpgme_get_gpg_path (void) { - char *gpg; - const char *inst_dir, *name; + char *gpg = NULL; + const char *name, *inst_dir; + + name = default_gpg_name? get_basename (default_gpg_name) : "gpg.exe"; + /* 1. Try to find gpg.exe in the installation directory of gpgme. */ inst_dir = _gpgme_get_inst_dir (); - gpg = find_program_in_inst_dir - (inst_dir, - default_gpg_name? get_basename (default_gpg_name) : "gpg.exe"); + if (inst_dir) + { + gpg = find_program_in_dir (inst_dir, name); + } + + /* 2. Try to find gpg.exe using that ancient registry key. */ if (!gpg) { - name = (default_gpg_name? default_gpg_name - /* */ : "GNU\\GnuPG\\gpg.exe"); + char *dir; + + dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", + "Software\\GNU\\GnuPG", + "Install Directory"); + if (dir) + { + gpg = find_program_in_dir (dir, name); + free (dir); + } + } + + /* 3. Try to find gpg.exe below CSIDL_PROGRAM_FILES. */ + if (!gpg) + { + name = default_gpg_name? default_gpg_name : "GNU\\GnuPG\\gpg.exe"; gpg = find_program_at_standard_place (name); - if (!gpg) - _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", - name); } + /* 4. Print a debug message if not found. */ + if (!gpg) + _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpg_path: '%s' not found", name); + return gpg; } @@ -523,22 +510,52 @@ _gpgme_get_gpg_path (void) char * _gpgme_get_gpgconf_path (void) { - char *gpgconf; + char *gpgconf = NULL; const char *inst_dir, *name; + name = default_gpgconf_name? get_basename(default_gpgconf_name):"gpgconf.exe"; + + /* 1. Try to find gpgconf.exe in the installation directory of gpgme. */ inst_dir = _gpgme_get_inst_dir (); - gpgconf = find_program_in_inst_dir - (inst_dir, - default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe"); + if (inst_dir) + { + gpgconf = find_program_in_dir (inst_dir, name); + } + + /* 2. Try to find gpgconf.exe from GnuPG >= 2.1 below CSIDL_PROGRAM_FILES. */ + if (!gpgconf) + { + const char *name2 = (default_gpgconf_name ? default_gpgconf_name + /**/ : "GnuPG\\bin\\gpgconf.exe"); + gpgconf = find_program_at_standard_place (name2); + } + + /* 3. Try to find gpgconf.exe using that ancient registry key. This + should eventually be removed. */ + if (!gpgconf) + { + char *dir; + + dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", + "Software\\GNU\\GnuPG", + "Install Directory"); + if (dir) + { + gpgconf = find_program_in_dir (dir, name); + free (dir); + } + } + + /* 4. Try to find gpgconf.exe from Gpg4win below CSIDL_PROGRAM_FILES. */ if (!gpgconf) { - name = (default_gpgconf_name? default_gpgconf_name - /* */ : "GNU\\GnuPG\\gpgconf.exe"); - gpgconf = find_program_at_standard_place (name); - if (!gpgconf) - _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found", - name); + gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe"); } + + /* 5. Print a debug message if not found. */ + if (!gpgconf) + _gpgme_debug (DEBUG_ENGINE, "_gpgme_get_gpgconf_path: '%s' not found",name); + return gpgconf; } @@ -552,10 +569,7 @@ _gpgme_get_w32spawn_path (void) inst_dir = _gpgme_get_inst_dir (); LOCK (get_path_lock); if (!w32spawn_program) - w32spawn_program = find_program_in_inst_dir (inst_dir,"gpgme-w32spawn.exe"); - if (!w32spawn_program) - w32spawn_program - = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe"); + w32spawn_program = find_program_in_dir (inst_dir, "gpgme-w32spawn.exe"); UNLOCK (get_path_lock); return w32spawn_program; } |