diff options
author | JinWang An <jinwang.an@samsung.com> | 2023-01-30 13:26:32 +0900 |
---|---|---|
committer | JinWang An <jinwang.an@samsung.com> | 2023-01-30 13:26:32 +0900 |
commit | 7068c0ead0c25a9a1fd3ce0b486636d74350e7ca (patch) | |
tree | 732edf51b955fd198e4bb7ef46a0782fb3ea1d12 /src | |
parent | d19c360948ede5ffe5974de8abc9da44be617ca1 (diff) | |
download | gpgme-7068c0ead0c25a9a1fd3ce0b486636d74350e7ca.tar.gz gpgme-7068c0ead0c25a9a1fd3ce0b486636d74350e7ca.tar.bz2 gpgme-7068c0ead0c25a9a1fd3ce0b486636d74350e7ca.zip |
Imported Upstream version 1.17.0upstream/1.17.0
Diffstat (limited to 'src')
-rw-r--r-- | src/ath.c | 15 | ||||
-rw-r--r-- | src/ath.h | 13 | ||||
-rw-r--r-- | src/context.h | 6 | ||||
-rw-r--r-- | src/data.c | 6 | ||||
-rw-r--r-- | src/debug.h | 34 | ||||
-rw-r--r-- | src/dirinfo.c | 66 | ||||
-rw-r--r-- | src/engine-backend.h | 5 | ||||
-rw-r--r-- | src/engine-gpg.c | 59 | ||||
-rw-r--r-- | src/engine-gpgconf.c | 6 | ||||
-rw-r--r-- | src/engine-gpgsm.c | 22 | ||||
-rw-r--r-- | src/engine.c | 6 | ||||
-rw-r--r-- | src/engine.h | 5 | ||||
-rw-r--r-- | src/export.c | 88 | ||||
-rw-r--r-- | src/gpgme-tool.c | 5 | ||||
-rw-r--r-- | src/gpgme.c | 24 | ||||
-rw-r--r-- | src/gpgme.def | 3 | ||||
-rw-r--r-- | src/gpgme.h.in | 7 | ||||
-rw-r--r-- | src/gpgme.pc.in | 6 | ||||
-rw-r--r-- | src/import.c | 148 | ||||
-rw-r--r-- | src/libgpgme.vers | 3 | ||||
-rw-r--r-- | src/posix-io.c | 127 | ||||
-rw-r--r-- | src/w32-util.c | 21 |
22 files changed, 586 insertions, 89 deletions
@@ -26,11 +26,15 @@ #ifdef HAVE_UNISTD_H # include <unistd.h> #endif -#ifdef HAVE_SYS_SELECT_H -# include <sys/select.h> +#ifdef HAVE_POLL_H +# include <poll.h> #else -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif # endif #endif #ifdef HAVE_SYS_TYPES_H @@ -89,6 +93,7 @@ ath_write (int fd, const void *buf, size_t nbytes) } +#if !defined(HAVE_POLL_H) gpgme_ssize_t ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, struct timeval *timeout) @@ -99,7 +104,7 @@ ath_select (int nfd, fd_set *rset, fd_set *wset, fd_set *eset, return select (nfd, rset, wset, eset, timeout); #endif } - +#endif gpgme_ssize_t ath_waitpid (pid_t pid, int *status, int options) @@ -32,12 +32,15 @@ # include <io.h> #else /*!HAVE_W32_SYSTEM*/ - -# ifdef HAVE_SYS_SELECT_H -# include <sys/select.h> +# ifdef HAVE_POLL_H +# include <poll.h> # else -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif # endif # endif # ifdef HAVE_SYS_TYPES_H diff --git a/src/context.h b/src/context.h index 2792a16..e976ba3 100644 --- a/src/context.h +++ b/src/context.h @@ -177,6 +177,12 @@ struct gpgme_context /* The optional expiration date of a certification. */ char *cert_expire; + /* The optional key origin. */ + char *key_origin; + + /* The optional import filter. */ + char *import_filter; + /* The operation data hooked into the context. */ ctx_op_data_t op_data; @@ -391,7 +391,7 @@ gpgme_data_read (gpgme_data_t dh, void *buffer, size_t size) while (res < 0 && errno == EINTR); } - return TRACE_SYSRES ((int)res); + return TRACE_SYSRES_SSIZE_T (res); } @@ -419,7 +419,7 @@ gpgme_data_write (gpgme_data_t dh, const void *buffer, size_t size) res = (*dh->cbs->write) (dh, buffer, size); while (res < 0 && errno == EINTR); - return TRACE_SYSRES ((int)res); + return TRACE_SYSRES_SSIZE_T (res); } @@ -452,7 +452,7 @@ gpgme_data_seek (gpgme_data_t dh, gpgme_off_t offset, int whence) if (offset >= 0) dh->outbound_pending = 0; - return TRACE_SYSRES ((int)offset); + return TRACE_SYSRES_OFF_T (offset); } diff --git a/src/debug.h b/src/debug.h index fa0bfc6..7b823ee 100644 --- a/src/debug.h +++ b/src/debug.h @@ -141,7 +141,7 @@ _trace_err (gpg_error_t err, int lvl, const char *func, int line) return err; } -/* Trace a system call result and return it. */ +/* Trace a system call result of type int and return it. */ #define TRACE_SYSRES(res) \ _trace_sysres ((res), _gpgme_trace_level, _gpgme_trace_func, __LINE__) static inline int @@ -157,6 +157,38 @@ _trace_sysres (int res, int lvl, const char *func, int line) return res; } +/* Trace a system call result of type gpgme_off_t and return it. */ +#define TRACE_SYSRES_OFF_T(res) \ + _trace_sysres_off_t ((res), _gpgme_trace_level, _gpgme_trace_func, __LINE__) +static inline gpgme_off_t +_trace_sysres_off_t (gpgme_off_t res, int lvl, const char *func, int line) +{ + if (res >= 0) + _gpgme_debug (NULL, lvl, 3, func, NULL, NULL, "result=%ld", res); + else + _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL, + "%s:%d: error: %s (%d)\n", + func, line, strerror (errno), errno); + _gpgme_debug_frame_end (); + return res; +} + +/* Trace a system call result of type gpgme_ssize_t and return it. */ +#define TRACE_SYSRES_SSIZE_T(res) \ + _trace_sysres_ssize_t ((res), _gpgme_trace_level, _gpgme_trace_func, __LINE__) +static inline gpgme_ssize_t +_trace_sysres_ssize_t (gpgme_ssize_t res, int lvl, const char *func, int line) +{ + if (res >= 0) + _gpgme_debug (NULL, lvl, 3, func, NULL, NULL, "result=%zd", res); + else + _gpgme_debug (NULL, lvl, -1, NULL, NULL, NULL, + "%s:%d: error: %s (%d)\n", + func, line, strerror (errno), errno); + _gpgme_debug_frame_end (); + return res; +} + /* Trace a system call error and return it. */ #define TRACE_SYSERR(rc) \ _trace_syserr ((rc), _gpgme_trace_level, _gpgme_trace_func, __LINE__) diff --git a/src/dirinfo.c b/src/dirinfo.c index c4f0e4a..8ea15d8 100644 --- a/src/dirinfo.c +++ b/src/dirinfo.c @@ -44,6 +44,7 @@ enum WANT_LIBDIR, WANT_DATADIR, WANT_LOCALEDIR, + WANT_SOCKETDIR, WANT_AGENT_SOCKET, WANT_AGENT_SSH_SOCKET, WANT_DIRMNGR_SOCKET, @@ -52,6 +53,11 @@ enum WANT_GPG_NAME, WANT_GPGSM_NAME, WANT_G13_NAME, + WANT_KEYBOXD_NAME, + WANT_AGENT_NAME, + WANT_SCDAEMON_NAME, + WANT_DIRMNGR_NAME, + WANT_PINENTRY_NAME, WANT_GPG_WKS_CLIENT_NAME, WANT_GPG_ONE_MODE }; @@ -67,6 +73,7 @@ static struct { char *libdir; char *datadir; char *localedir; + char *socketdir; char *agent_socket; char *agent_ssh_socket; char *dirmngr_socket; @@ -75,6 +82,11 @@ static struct { char *gpg_name; char *gpgsm_name; char *g13_name; + char *keyboxd_name; + char *agent_name; + char *scdaemon_name; + char *dirmngr_name; + char *pinentry_name; char *gpg_wks_client_name; int gpg_one_mode; /* System is in gpg1 mode. */ } dirinfo; @@ -135,6 +147,16 @@ parse_output (char *line, int components) dirinfo.gpgsm_name = strdup (value); else if (!strcmp (line, "g13") && !dirinfo.g13_name) dirinfo.g13_name = strdup (value); + else if (!strcmp (line, "keyboxd") && !dirinfo.keyboxd_name) + dirinfo.keyboxd_name = strdup (value); + else if (!strcmp (line, "gpg-agent") && !dirinfo.agent_name) + dirinfo.agent_name = strdup (value); + else if (!strcmp (line, "scdaemon") && !dirinfo.scdaemon_name) + dirinfo.scdaemon_name = strdup (value); + else if (!strcmp (line, "dirmngr") && !dirinfo.dirmngr_name) + dirinfo.dirmngr_name = strdup (value); + else if (!strcmp (line, "pinentry") && !dirinfo.pinentry_name) + dirinfo.pinentry_name = strdup (value); } else { @@ -152,6 +174,8 @@ parse_output (char *line, int components) dirinfo.datadir = strdup (value); else if (!strcmp (line, "localedir") && !dirinfo.localedir) dirinfo.localedir = strdup (value); + else if (!strcmp (line, "socketdir") && !dirinfo.socketdir) + dirinfo.socketdir = strdup (value); else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket) { const char name[] = "S.uiserver"; @@ -306,10 +330,34 @@ get_gpgconf_item (int what) _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, "gpgme-dinfo: gpgsm='%s'\n", dirinfo.gpgsm_name); + if (dirinfo.keyboxd_name) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: keyboxd='%s'\n", + dirinfo.keyboxd_name); + if (dirinfo.agent_name) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: gpg-agent='%s'\n", + dirinfo.agent_name); + if (dirinfo.scdaemon_name) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: scdaemon='%s'\n", + dirinfo.scdaemon_name); + if (dirinfo.dirmngr_name) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: dirmngr='%s'\n", + dirinfo.dirmngr_name); + if (dirinfo.pinentry_name) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: pinentry='%s'\n", + dirinfo.pinentry_name); if (dirinfo.homedir) _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, "gpgme-dinfo: homedir='%s'\n", dirinfo.homedir); + if (dirinfo.socketdir) + _gpgme_debug (NULL, DEBUG_INIT, -1, NULL, NULL, NULL, + "gpgme-dinfo: sockdir='%s'\n", + dirinfo.socketdir); if (dirinfo.agent_socket) _gpgme_debug (NULL,DEBUG_INIT, -1, NULL, NULL, NULL, "gpgme-dinfo: agent='%s'\n", @@ -336,6 +384,7 @@ get_gpgconf_item (int what) case WANT_LIBDIR: result = dirinfo.libdir; break; case WANT_DATADIR: result = dirinfo.datadir; break; case WANT_LOCALEDIR: result = dirinfo.localedir; break; + case WANT_SOCKETDIR: result = dirinfo.socketdir; break; case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break; case WANT_AGENT_SSH_SOCKET: result = dirinfo.agent_ssh_socket; break; case WANT_DIRMNGR_SOCKET: result = dirinfo.dirmngr_socket; break; @@ -343,6 +392,11 @@ get_gpgconf_item (int what) case WANT_GPG_NAME: result = dirinfo.gpg_name; break; case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break; case WANT_G13_NAME: result = dirinfo.g13_name; break; + case WANT_KEYBOXD_NAME: result = dirinfo.keyboxd_name; break; + case WANT_AGENT_NAME: result = dirinfo.agent_name; break; + case WANT_SCDAEMON_NAME: result = dirinfo.scdaemon_name; break; + case WANT_DIRMNGR_NAME: result = dirinfo.dirmngr_name; break; + case WANT_PINENTRY_NAME: result = dirinfo.pinentry_name; break; case WANT_UISRV_SOCKET: result = dirinfo.uisrv_socket; break; case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break; case WANT_GPG_WKS_CLIENT_NAME: @@ -458,6 +512,16 @@ gpgme_get_dirinfo (const char *what) return get_gpgconf_item (WANT_GPGSM_NAME); else if (!strcmp (what, "g13-name")) return get_gpgconf_item (WANT_G13_NAME); + else if (!strcmp (what, "keyboxd-name")) + return get_gpgconf_item (WANT_KEYBOXD_NAME); + else if (!strcmp (what, "agent-name")) + return get_gpgconf_item (WANT_AGENT_NAME); + else if (!strcmp (what, "scdaemon-name")) + return get_gpgconf_item (WANT_SCDAEMON_NAME); + else if (!strcmp (what, "dirmngr-name")) + return get_gpgconf_item (WANT_DIRMNGR_NAME); + else if (!strcmp (what, "pinentry-name")) + return get_gpgconf_item (WANT_PINENTRY_NAME); else if (!strcmp (what, "gpg-wks-client-name")) return get_gpgconf_item (WANT_GPG_WKS_CLIENT_NAME); else if (!strcmp (what, "agent-ssh-socket")) @@ -476,6 +540,8 @@ gpgme_get_dirinfo (const char *what) return get_gpgconf_item (WANT_DATADIR); else if (!strcmp (what, "localedir")) return get_gpgconf_item (WANT_LOCALEDIR); + else if (!strcmp (what, "socketdir")) + return get_gpgconf_item (WANT_SOCKETDIR); else return NULL; } diff --git a/src/engine-backend.h b/src/engine-backend.h index 8f90b6c..9b755a3 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -95,7 +95,10 @@ struct engine_ops unsigned int extraflags, gpgme_data_t pubkey, gpgme_data_t seckey); gpgme_error_t (*import) (void *engine, gpgme_data_t keydata, - gpgme_key_t *keyarray); + gpgme_key_t *keyarray, + const char *keyids[], + const char *import_filter, + const char *key_origin); gpgme_error_t (*keylist) (void *engine, const char *pattern, int secret_only, gpgme_keylist_mode_t mode, int engine_flags); diff --git a/src/engine-gpg.c b/src/engine-gpg.c index b51ea17..88a248d 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -59,7 +59,7 @@ struct arg_and_data_s int print_fd; /* Print the fd number and not the special form of it. */ int *arg_locp; /* Write back the argv idx of this argument when building command line to this location. */ - char arg[1]; /* Used if data above is not used. */ + char arg[FLEXIBLE_ARRAY_MEMBER]; /* Used if data above is not used. */ }; @@ -233,7 +233,7 @@ _add_arg (engine_gpg_t gpg, const char *prefix, const char *arg, size_t arglen, assert (gpg); assert (arg); - a = malloc (sizeof *a + prefixlen + arglen); + a = malloc (offsetof (struct arg_and_data_s, arg) + prefixlen + arglen + 1); if (!a) return gpg_error_from_syserror (); @@ -307,7 +307,7 @@ add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound) assert (gpg); assert (data); - a = malloc (sizeof *a - 1); + a = malloc (offsetof (struct arg_and_data_s, arg)); if (!a) return gpg_error_from_syserror (); a->next = NULL; @@ -2354,7 +2354,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, if ((mode & ~(GPGME_EXPORT_MODE_EXTERN |GPGME_EXPORT_MODE_MINIMAL |GPGME_EXPORT_MODE_SSH - |GPGME_EXPORT_MODE_SECRET))) + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) return gpg_error (GPG_ERR_NOT_SUPPORTED); if ((mode & GPGME_EXPORT_MODE_MINIMAL)) @@ -2379,7 +2380,9 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, } else { - if ((mode & GPGME_EXPORT_MODE_SECRET)) + if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + err = add_arg (gpg, "--export-secret-subkeys"); + else if ((mode & GPGME_EXPORT_MODE_SECRET)) err = add_arg (gpg, "--export-secret-keys"); else err = add_arg (gpg, "--export"); @@ -2766,21 +2769,43 @@ string_from_data (gpgme_data_t data, int delim, static gpgme_error_t -gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) +gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray, + const char *keyids[], const char *import_filter, + const char *key_origin) { engine_gpg_t gpg = engine; gpgme_error_t err; int idx; gpgme_data_encoding_t dataenc; - if (keydata && keyarray) + if ((keydata && keyarray) || (keydata && keyids) || (keyarray && keyids)) return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */ dataenc = gpgme_data_get_encoding (keydata); - if (keyarray) + if (keyids) { err = add_arg (gpg, "--recv-keys"); + if (!err && import_filter && have_gpg_version (gpg, "2.1.14")) + { + err = add_arg (gpg, "--import-filter"); + if (!err) + err = add_arg (gpg, import_filter); + } + if (!err) + err = add_arg (gpg, "--"); + while (!err && *keyids && **keyids) + err = add_arg (gpg, *(keyids++)); + } + else if (keyarray) + { + err = add_arg (gpg, "--recv-keys"); + if (!err && import_filter && have_gpg_version (gpg, "2.1.14")) + { + err = add_arg (gpg, "--import-filter"); + if (!err) + err = add_arg (gpg, import_filter); + } if (!err) err = add_arg (gpg, "--"); for (idx=0; !err && keyarray[idx]; idx++) @@ -2812,6 +2837,12 @@ gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) should use an option to gpg to modify such commands (ala --multifile). */ err = add_arg (gpg, "--fetch-keys"); + if (!err && import_filter && have_gpg_version (gpg, "2.1.14")) + { + err = add_arg (gpg, "--import-filter"); + if (!err) + err = add_arg (gpg, import_filter); + } if (!err) err = add_arg (gpg, "--"); helpptr = NULL; @@ -2830,6 +2861,18 @@ gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) else { err = add_arg (gpg, "--import"); + if (!err && import_filter && have_gpg_version (gpg, "2.1.14")) + { + err = add_arg (gpg, "--import-filter"); + if (!err) + err = add_arg (gpg, import_filter); + } + if (!err && key_origin && have_gpg_version (gpg, "2.1.22")) + { + err = add_arg (gpg, "--key-origin"); + if (!err) + err = add_arg (gpg, key_origin); + } if (!err) err = add_arg (gpg, "--"); if (!err) diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c index 28f9115..caf4d78 100644 --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -445,8 +445,10 @@ gpgconf_parse_option (gpgme_conf_opt_t opt, case GPGME_CONF_PUB_KEY: case GPGME_CONF_SEC_KEY: case GPGME_CONF_ALIAS_LIST: - /* Skip quote character. */ - line++; + /* Skip quote character. It is required by specs but + * technically not always needed. */ + if (*line == '\"' && line[1]) + line++; err = _gpgme_decode_percent_string (line, &arg->value.string, 0, 0); diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index d5f0d7a..9ab0555 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1512,6 +1512,12 @@ gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); + if ((mode & ~(GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + if (!pattern) pattern = ""; @@ -1559,6 +1565,12 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); + if ((mode & ~(GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12))) + return gpg_error (GPG_ERR_NOT_SUPPORTED); + if (pattern && *pattern) { const char **pat = pattern; @@ -1696,16 +1708,24 @@ gpgsm_genkey (void *engine, static gpgme_error_t -gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray) +gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray, + const char *keyids[], const char *import_filter, + const char *key_origin) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err; gpgme_data_encoding_t dataenc; int idx; + (void)import_filter; + (void)key_origin; + if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); + if (keyids) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + if (keydata && keyarray) return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */ diff --git a/src/engine.c b/src/engine.c index 96b8d3a..db594cb 100644 --- a/src/engine.c +++ b/src/engine.c @@ -850,7 +850,8 @@ _gpgme_engine_op_tofu_policy (engine_t engine, gpgme_error_t _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata, - gpgme_key_t *keyarray) + gpgme_key_t *keyarray, const char *keyids[], + const char *import_filter, const char *key_origin) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -858,7 +859,8 @@ _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata, if (!engine->ops->import) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->import) (engine->engine, keydata, keyarray); + return (*engine->ops->import) (engine->engine, keydata, keyarray, keyids, + import_filter, key_origin); } diff --git a/src/engine.h b/src/engine.h index d7ff542..8b45e13 100644 --- a/src/engine.h +++ b/src/engine.h @@ -141,7 +141,10 @@ gpgme_error_t _gpgme_engine_op_tofu_policy (engine_t engine, gpgme_tofu_policy_t policy); gpgme_error_t _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata, - gpgme_key_t *keyarray); + gpgme_key_t *keyarray, + const char *keyids[], + const char *import_filter, + const char *key_origin); gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, const char *pattern, int secret_only, diff --git a/src/export.c b/src/export.c index 4cee0ef..155085f 100644 --- a/src/export.c +++ b/src/export.c @@ -105,7 +105,8 @@ export_status_handler (void *priv, gpgme_status_code_t code, char *args) return err; else if (opd->err) ; /* We only want to report the first error. */ - else if (!strcmp (loc, "keyserver_send")) + else if (!strcmp (loc, "keyserver_send") + || !strcmp (loc, "export_keys.secret")) opd->err = err; break; @@ -117,21 +118,29 @@ export_status_handler (void *priv, gpgme_status_code_t code, char *args) static gpgme_error_t -export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, - gpgme_export_mode_t mode, gpgme_data_t keydata) +check_mode (gpgme_export_mode_t mode, gpgme_protocol_t protocol, + gpgme_data_t keydata) { - gpgme_error_t err; - void *hook; - op_data_t opd; - if ((mode & ~(GPGME_EXPORT_MODE_EXTERN |GPGME_EXPORT_MODE_MINIMAL |GPGME_EXPORT_MODE_SECRET |GPGME_EXPORT_MODE_SSH |GPGME_EXPORT_MODE_RAW - |GPGME_EXPORT_MODE_PKCS12))) + |GPGME_EXPORT_MODE_PKCS12 + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ + if ((mode & GPGME_EXPORT_MODE_SSH)) + { + if ((mode & (GPGME_EXPORT_MODE_EXTERN + |GPGME_EXPORT_MODE_MINIMAL + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_RAW + |GPGME_EXPORT_MODE_PKCS12 + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + } + if ((mode & GPGME_EXPORT_MODE_SECRET)) { if ((mode & GPGME_EXPORT_MODE_EXTERN)) @@ -140,11 +149,17 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, && (mode & GPGME_EXPORT_MODE_PKCS12)) return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ - if (ctx->protocol != GPGME_PROTOCOL_CMS + if (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_SECRET_SUBKEY)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + } + if ((mode & GPGME_EXPORT_MODE_EXTERN)) { if (keydata) @@ -156,6 +171,22 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, return gpg_error (GPG_ERR_INV_VALUE); } + return 0; +} + + +static gpgme_error_t +export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, + gpgme_export_mode_t mode, gpgme_data_t keydata) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = check_mode (mode, ctx->protocol, keydata); + if (err) + return err; + err = _gpgme_op_reset (ctx, synchronous); if (err) return err; @@ -227,37 +258,9 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], void *hook; op_data_t opd; - if ((mode & ~(GPGME_EXPORT_MODE_EXTERN - |GPGME_EXPORT_MODE_MINIMAL - |GPGME_EXPORT_MODE_SECRET - |GPGME_EXPORT_MODE_SSH - |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) - return gpg_error (GPG_ERR_INV_VALUE); - } - else - { - if (!keydata) - return gpg_error (GPG_ERR_INV_VALUE); - } + err = check_mode (mode, ctx->protocol, keydata); + if (err) + return err; err = _gpgme_op_reset (ctx, synchronous); if (err) @@ -375,6 +378,11 @@ export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[], if (!keys) return gpg_error (GPG_ERR_INV_VALUE); + if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + { + return gpg_error (GPG_ERR_INV_FLAG); + } + /* Create a list of pattern from the keys. */ for (idx=nkeys=0; keys[idx]; idx++) if (keys[idx]->protocol == ctx->protocol) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index 0dbc4a9..e45ea12 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -2658,7 +2658,8 @@ cmd_import (assuan_context_t ctx, char *line) static const char hlp_export[] = - "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n" + "EXPORT [--extern] [--minimal]\n" + " [--secret [--pkcs12] [--raw]|--secret-subkey] [<pattern>]\n" "\n" "Export the keys described by PATTERN. Write the\n" "the output to the object set by the last OUTPUT command."; @@ -2688,6 +2689,8 @@ cmd_export (assuan_context_t ctx, char *line) mode |= GPGME_EXPORT_MODE_MINIMAL; if (has_option (line, "--secret")) mode |= GPGME_EXPORT_MODE_SECRET; + if (has_option (line, "--secret-subkey")) + mode |= GPGME_EXPORT_MODE_SECRET_SUBKEY; if (has_option (line, "--raw")) mode |= GPGME_EXPORT_MODE_RAW; if (has_option (line, "--pkcs12")) diff --git a/src/gpgme.c b/src/gpgme.c index 255d116..6a5232e 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -254,6 +254,8 @@ gpgme_release (gpgme_ctx_t ctx) free (ctx->auto_key_locate); free (ctx->trust_model); free (ctx->cert_expire); + free (ctx->key_origin); + free (ctx->import_filter); _gpgme_engine_info_release (ctx->engine_info); ctx->engine_info = NULL; DESTROY_LOCK (ctx->lock); @@ -586,6 +588,20 @@ gpgme_set_ctx_flag (gpgme_ctx_t ctx, const char *name, const char *value) if (!ctx->cert_expire) err = gpg_error_from_syserror (); } + else if (!strcmp (name, "key-origin")) + { + free (ctx->key_origin); + ctx->key_origin = strdup (value); + if (!ctx->key_origin) + err = gpg_error_from_syserror (); + } + else if (!strcmp (name, "import-filter")) + { + free (ctx->import_filter); + ctx->import_filter = strdup (value); + if (!ctx->import_filter) + err = gpg_error_from_syserror (); + } else err = gpg_error (GPG_ERR_UNKNOWN_NAME); @@ -659,6 +675,14 @@ gpgme_get_ctx_flag (gpgme_ctx_t ctx, const char *name) { return ctx->cert_expire? ctx->cert_expire : ""; } + else if (!strcmp (name, "key-origin")) + { + return ctx->key_origin? ctx->key_origin : ""; + } + else if (!strcmp (name, "import-filter")) + { + return ctx->import_filter? ctx->import_filter : ""; + } else return NULL; } diff --git a/src/gpgme.def b/src/gpgme.def index 6644cae..d8ccd4c 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -280,5 +280,8 @@ EXPORTS gpgme_op_revsig @207 gpgme_op_revsig_start @208 + gpgme_op_receive_keys @209 + gpgme_op_receive_keys_start @210 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5c74afd..0f7c361 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -407,6 +407,7 @@ gpgme_pinentry_mode_t; #define GPGME_EXPORT_MODE_RAW 32 #define GPGME_EXPORT_MODE_PKCS12 64 #define GPGME_EXPORT_MODE_SSH 256 +#define GPGME_EXPORT_MODE_SECRET_SUBKEY 512 typedef unsigned int gpgme_export_mode_t; @@ -1737,6 +1738,12 @@ gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata); 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[]); +/* Import the keys given by the array KEYIDS from a keyserver into the + * keyring. */ +gpgme_error_t gpgme_op_receive_keys_start (gpgme_ctx_t ctx, + const char *keyids[]); +gpgme_error_t gpgme_op_receive_keys (gpgme_ctx_t ctx, const char *keyids[]); + /* Export the keys found by PATTERN into KEYDATA. */ gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, diff --git a/src/gpgme.pc.in b/src/gpgme.pc.in index be288b8..80d59de 100644 --- a/src/gpgme.pc.in +++ b/src/gpgme.pc.in @@ -7,8 +7,8 @@ api_version=@GPGME_CONFIG_API_VERSION@ Name: gpgme Description: GnuPG Made Easy to access GnuPG -Requires: gpg-error, libassuan +Requires.private: gpg-error, libassuan Version: @PACKAGE_VERSION@ -Cflags: @GPGME_CONFIG_CFLAGS@ -Libs: @GPGME_CONFIG_LIBS@ +Cflags: -I${includedir} @GPGME_CONFIG_CFLAGS@ +Libs: -L${libdir} @GPGME_CONFIG_LIBS@ URL: https://www.gnupg.org/software/gpgme/index.html diff --git a/src/import.c b/src/import.c index 2834aec..85c459b 100644 --- a/src/import.c +++ b/src/import.c @@ -103,7 +103,7 @@ gpgme_op_import_result (gpgme_ctx_t ctx) while (impstat) { TRACE_LOG ("import[%i] for %s = 0x%x (%s)", - i, impstat->fpr, impstat->status, + i, impstat->fpr ? impstat->fpr : "null", impstat->status, gpgme_strerror (impstat->result)); impstat = impstat->next; i++; @@ -223,6 +223,49 @@ parse_import_res (char *args, gpgme_import_result_t result) } +/* Parses an error on a status line and adds a corresponding import status. + Currently, only supports "import.parsep12 11". */ +static gpgme_error_t +parse_error (char *args, gpgme_import_status_t *import_status) +{ + gpgme_import_status_t import; + char *tail; + long int nr; + + tail = strchr (args, ' '); + if (!tail) + return 0; + + *tail = '\0'; + if (strcmp( args, "import.parsep12" )) + return 0; + + args = tail + 1; + + gpg_err_set_errno (0); + nr = strtol (args, &tail, 0); + if (errno || args == tail || !(*tail == ' ' || !*tail)) + { + /* The crypto backend does not behave. */ + return trace_gpg_error (GPG_ERR_INV_ENGINE); + } + if (nr != GPG_ERR_BAD_PASSPHRASE) + return 0; + + import = malloc (sizeof (*import)); + if (!import) + return gpg_error_from_syserror (); + import->next = NULL; + + import->result = gpg_error (GPG_ERR_BAD_PASSPHRASE); + import->status = 0; + import->fpr = 0; + + *import_status = import; + return 0; +} + + static gpgme_error_t import_status_handler (void *priv, gpgme_status_code_t code, char *args) { @@ -252,6 +295,15 @@ import_status_handler (void *priv, gpgme_status_code_t code, char *args) err = parse_import_res (args, &opd->result); break; + case GPGME_STATUS_ERROR: + err = parse_error (args, opd->lastp); + if (err) + return err; + + if (*opd->lastp) + opd->lastp = &(*opd->lastp)->next; + break; + default: break; } @@ -282,7 +334,8 @@ _gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata) _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); - return _gpgme_engine_op_import (ctx->engine, keydata, NULL); + return _gpgme_engine_op_import (ctx->engine, keydata, NULL, NULL, + ctx->import_filter, ctx->key_origin); } @@ -365,7 +418,8 @@ _gpgme_op_import_keys_start (gpgme_ctx_t ctx, int synchronous, _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); - return _gpgme_engine_op_import (ctx->engine, NULL, keys); + return _gpgme_engine_op_import (ctx->engine, NULL, keys, NULL, + ctx->import_filter, ctx->key_origin); } @@ -438,6 +492,94 @@ gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t *keys) } +static gpgme_error_t +_gpgme_op_receive_keys_start (gpgme_ctx_t ctx, int synchronous, const char *keyids[]) +{ + gpgme_error_t err; + void *hook; + op_data_t opd; + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook, + sizeof (*opd), release_op_data); + opd = hook; + if (err) + return err; + opd->lastp = &opd->result.imports; + + if (!keyids || !*keyids) + return gpg_error (GPG_ERR_NO_DATA); + + _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); + + return _gpgme_engine_op_import (ctx->engine, NULL, NULL, keyids, + ctx->import_filter, ctx->key_origin); +} + + +/* Asynchronous version of gpgme_op_receive_keys. */ +gpgme_error_t +gpgme_op_receive_keys_start (gpgme_ctx_t ctx, const char *keyids[]) +{ + gpgme_error_t err; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_receive_keys_start", ctx, ""); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && keyids) + { + int i = 0; + + while (keyids[i] && *keyids[i]) + { + TRACE_LOG ("keyids[%i] = %s", i, keyids[i]); + i++; + } + } + + err = _gpgme_op_receive_keys_start (ctx, 1, keyids); + return TRACE_ERR (err); +} + + +/* Retrieve the keys from the array KEYIDS from a keyserver and import + them into the keyring. + + KEYIDS is a NULL terminated array of . The result + is the usual import result structure. */ +gpgme_error_t +gpgme_op_receive_keys (gpgme_ctx_t ctx, const char *keyids[]) +{ + gpgme_error_t err; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_receive_keys", ctx, ""); + + if (!ctx) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + if (_gpgme_debug_trace () && keyids) + { + int i = 0; + + while (keyids[i] && *keyids[i]) + { + TRACE_LOG ("keyids[%i] = %s", i, keyids[i]); + i++; + } + } + + err = _gpgme_op_receive_keys_start (ctx, 1, keyids); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} + + /* Deprecated interface. */ gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr) diff --git a/src/libgpgme.vers b/src/libgpgme.vers index 8e86e4e..86d2a5d 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -279,6 +279,9 @@ GPGME_1.0 { gpgme_op_revsig; gpgme_op_revsig_start; + gpgme_op_receive_keys; + gpgme_op_receive_keys_start; + local: *; diff --git a/src/posix-io.c b/src/posix-io.c index e712ef2..5c6cf1d 100644 --- a/src/posix-io.c +++ b/src/posix-io.c @@ -570,7 +570,7 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, if (fd_list[i].fd > fd) fd = fd_list[i].fd; fd++; -#if defined(__sun) || defined(__FreeBSD__) +#if defined(__sun) || defined(__FreeBSD__) || defined(__GLIBC__) closefrom (fd); max_fds = fd; #else /*!__sun */ @@ -691,8 +691,119 @@ _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags, /* Select on the list of fds. Returns: -1 = error, 0 = timeout or nothing to select, > 0 = number of signaled fds. */ -int -_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +#ifdef HAVE_POLL_H +static int +_gpgme_io_select_poll (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ + struct pollfd *poll_fds = NULL; + nfds_t poll_nfds; + /* Use a 1s timeout. */ + int timeout = 1000; + unsigned int i; + int any; + int count; + void *dbg_help = NULL; + TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_select", NULL, + "nfds=%zu, nonblock=%u", nfds, nonblock); + + + if (nonblock) + timeout = 0; + + poll_fds = malloc (sizeof (*poll_fds)*nfds); + if (!poll_fds) + return -1; + + poll_nfds = 0; + + TRACE_SEQ (dbg_help, "poll on [ "); + + any = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if (fds[i].for_read || fds[i].for_write) + { + poll_fds[poll_nfds].fd = fds[i].fd; + poll_fds[poll_nfds].events = 0; + poll_fds[poll_nfds].revents = 0; + if (fds[i].for_read) + { + poll_fds[poll_nfds].events |= POLLIN; + TRACE_ADD1 (dbg_help, "r=%d ", fds[i].fd); + } + if (fds[i].for_write) + { + poll_fds[poll_nfds].events |= POLLOUT; + TRACE_ADD1 (dbg_help, "w=%d ", fds[i].fd); + } + poll_nfds++; + any = 1; + } + fds[i].signaled = 0; + } + TRACE_END (dbg_help, "]"); + if (!any) + { + free (poll_fds); + return TRACE_SYSRES (0); + } + + do + count = poll (poll_fds, poll_nfds, timeout); + while (count < 0 && (errno == EINTR || errno == EAGAIN)); + if (count < 0) + { + int save_errno = errno; + free (poll_fds); + errno = save_errno; + return TRACE_SYSRES (-1); + } + + TRACE_SEQ (dbg_help, "poll OK [ "); + if (TRACE_ENABLED (dbg_help)) + { + poll_nfds = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if ((poll_fds[poll_nfds].revents & (POLLIN|POLLHUP))) + TRACE_ADD1 (dbg_help, "r=%d ", i); + if ((poll_fds[poll_nfds].revents & POLLOUT)) + TRACE_ADD1 (dbg_help, "w=%d ", i); + poll_nfds++; + } + TRACE_END (dbg_help, "]"); + } + + poll_nfds = 0; + for (i = 0; i < nfds; i++) + { + if (fds[i].fd == -1) + continue; + if (fds[i].for_read || fds[i].for_write) + { + short events_to_be_checked = 0; + + if (fds[i].for_read) + events_to_be_checked |= (POLLIN|POLLHUP); + if (fds[i].for_write) + events_to_be_checked |= POLLOUT; + if ((poll_fds[poll_nfds].revents & events_to_be_checked)) + fds[i].signaled = 1; + + poll_nfds++; + } + } + + free (poll_fds); + return TRACE_SYSRES (count); +} +#else +static int +_gpgme_io_select_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) { fd_set readfds; fd_set writefds; @@ -802,7 +913,17 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) } return TRACE_SYSRES (count); } +#endif +int +_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) +{ +#ifdef HAVE_POLL_H + return _gpgme_io_select_poll (fds, nfds, nonblock); +#else + return _gpgme_io_select_select (fds, nfds, nonblock); +#endif +} int _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags) diff --git a/src/w32-util.c b/src/w32-util.c index 2631ae7..e4757a2 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -841,16 +841,17 @@ _gpgme_access (const char *path, int mode) /* Like CreateProcessA but mapping the arguments to wchar API */ -int _gpgme_create_process_utf8 (const char *application_name_utf8, - char *command_line_utf8, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - void *lpEnvironment, - char *working_directory_utf8, - LPSTARTUPINFOA si, - LPPROCESS_INFORMATION lpProcessInformation) +int +_gpgme_create_process_utf8 (const char *application_name_utf8, + char *command_line_utf8, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + void *lpEnvironment, + char *working_directory_utf8, + LPSTARTUPINFOA si, + LPPROCESS_INFORMATION lpProcessInformation) { BOOL ret; wchar_t *application_name = utf8_to_wchar0 (application_name_utf8); |