From 6564e5e78e8c6e5a120675a5699b5b75248cfbc7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 6 Jan 2014 17:16:52 +0100 Subject: [PATCH] Add global flags disable-gpgconf, gpgconf-name, and gpg-name. * src/gpgme.c (gpgme_set_global_flag): Add names "disable-gpgconf", "gpgconf-name", and "gpg-name". * src/dirinfo.c (_gpgme_dirinfo_disable_gpgconf): New. (get_gpgconf_item): Minor debug info change. * src/posix-util.c (default_gpg_name, default_gpgconf_name): Add vars. (_gpgme_set_default_gpg_name): New. (_gpgme_set_default_gpgconf_name): New. (_gpgme_get_gpg_path, _gpgme_get_gpgconf_path): Use new vars. (walk_path): Add debug output on failure. * src/w32-util.c (default_gpg_name, default_gpgconf_name): Add vars. (replace_slashes): New. (get_basename): New. (_gpgme_set_default_gpg_name): New. (_gpgme_set_default_gpgconf_name): New. (_gpgme_get_gpg_path, _gpgme_get_gpgconf_path): Use new vars. * tests/t-engine-info.c (main): Add --verbose and --set-global-flag options. -- Note that the Windows part has not been tested. --- doc/gpgme.texi | 47 +++++++++++++++----- src/dirinfo.c | 28 ++++++++---- src/gpgme.c | 10 +++++ src/posix-util.c | 47 +++++++++++++++++++- src/sys-util.h | 3 ++ src/util.h | 2 + src/w32-util.c | 100 +++++++++++++++++++++++++++++++++++++++--- tests/t-engine-info.c | 61 +++++++++++++++++++++++++- 8 files changed, 268 insertions(+), 30 deletions(-) diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 18b3c946..3f314921 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -1,5 +1,5 @@ -\input texinfo @c -*- mode: texinfo; coding: latin-1; -*- -@documentencoding ISO-8859-1 +\input texinfo @c -*- mode: texinfo; coding: utf-8; -*- +@documentencoding UTF-8 @setfilename gpgme.info @settitle The `GnuPG Made Easy' Reference Manual @@ -14,7 +14,7 @@ @copying Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007, -2008, 2010, 2012, 2013 g10 Code GmbH. +2008, 2010, 2012, 2013, 2014 g10 Code GmbH. @quotation Permission is granted to copy, distribute and/or modify this document @@ -72,7 +72,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED}, of @center for version @value{VERSION} @page @vskip 0pt plus 1filll -Published by g10 Code GmbH@* Hüttenstr. 61@* 40699 Erkrath, Germany +Published by g10 Code GmbH@* Hüttenstr. 61@* 40699 Erkrath, Germany @insertcopying @end titlepage @@ -648,14 +648,39 @@ does not return a detailed error code). On some systems it is not easy to set environment variables and thus hard to use @acronym{GPGME}'s internal trace facility for debugging. This function has been introduced as an alternative way to enable -debugging. It is important to assure that only one thread accesses -@acronym{GPGME} functions between a call to this function and after -the return from the call to @code{gpgme_check_version}. +debugging and for a couple of other rarely used tweaks. It is +important to assure that only one thread accesses @acronym{GPGME} +functions between a call to this function and after the return from +the call to @code{gpgme_check_version}. -To enable debugging, you need to call this function as early as -possible --- even before @code{gpgme_check_version} --- with the -string ``debug'' for @var{name} and @var{value} identical to the value -used with the environment variable @code{GPGME_DEBUG}. +All currently supported features require that this function is called +as early as possible --- even before @code{gpgme_check_version}. The +features are identified by the following values for @var{name}: + +@table @code +@item "debug" +To enable debugging use the string ``debug'' for @var{name} and +@var{value} identical to the value used with the environment variable +@code{GPGME_DEBUG}. + +@item "disable-gpgconf" +Using this feature with any @var{value} disables the detection of the +gpgconf program and thus forces GPGME to fallback into the simple +OpenPGP only mode. It may be used to force the use of GnuPG-1 on +systems which have both GPG versions installed. Note that in general +the use of @code{gpgme_set_engine_info} is a better way to select a +specific engine version. + +@item "gpgconf-name" +@itemx "gpg-name" +Set the name of the gpgconf respective gpg binary. The defaults are +@code{GNU/GnuPG/gpgconf} and @code{GNU/GnuPG/gpg}. Under Unix the +leading directory part is ignored. Under Windows the leading +directory part is used as the default installation directory; the +@code{.exe} suffix is added by GPGME. Use forward slashed even under +Windows. + +@end table This function returns @code{0} on success. In contrast to other functions the non-zero return value on failure does not convey any diff --git a/src/dirinfo.c b/src/dirinfo.c index 2e387fa1..eb29c6bd 100644 --- a/src/dirinfo.c +++ b/src/dirinfo.c @@ -48,6 +48,7 @@ enum /* Values retrieved via gpgconf and cached here. */ static struct { int valid; /* Cached information is valid. */ + int disable_gpgconf; char *homedir; char *agent_socket; char *gpgconf_name; @@ -58,6 +59,15 @@ static struct { } dirinfo; + +/* Helper function to be used only by gpgme_set_global_flag. */ +void +_gpgme_dirinfo_disable_gpgconf (void) +{ + dirinfo.disable_gpgconf = 1; +} + + /* Parse the output of "gpgconf --list-dirs". This function expects that DIRINFO_LOCK is held by the caller. If COMPONENTS is set, the output of --list-components is expected. */ @@ -198,16 +208,16 @@ get_gpgconf_item (int what) { char *pgmname; - pgmname = _gpgme_get_gpgconf_path (); + pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path (); if (pgmname && access (pgmname, F_OK)) { _gpgme_debug (DEBUG_INIT, - "gpgme_dinfo: gpgconf='%s' [not installed]\n", pgmname); + "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname); free (pgmname); pgmname = NULL; /* Not available. */ } else - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgconf='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n", pgmname? pgmname : "[null]"); if (!pgmname) { @@ -231,22 +241,22 @@ get_gpgconf_item (int what) allocated. */ dirinfo.valid = 1; if (dirinfo.gpg_name) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpg='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpg='%s'\n", dirinfo.gpg_name); if (dirinfo.g13_name) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: g13='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: g13='%s'\n", dirinfo.g13_name); if (dirinfo.gpgsm_name) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: gpgsm='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgsm='%s'\n", dirinfo.gpgsm_name); if (dirinfo.homedir) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: homedir='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n", dirinfo.homedir); if (dirinfo.agent_socket) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: agent='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: agent='%s'\n", dirinfo.agent_socket); if (dirinfo.uisrv_socket) - _gpgme_debug (DEBUG_INIT, "gpgme_dinfo: uisrv='%s'\n", + _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: uisrv='%s'\n", dirinfo.uisrv_socket); } switch (what) diff --git a/src/gpgme.c b/src/gpgme.c index a8de64b4..4a8afa96 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -37,6 +37,7 @@ #include "wait.h" #include "debug.h" #include "priv-io.h" +#include "sys-util.h" /* The default locale. */ @@ -65,6 +66,15 @@ gpgme_set_global_flag (const char *name, const char *value) return -1; else if (!strcmp (name, "debug")) return _gpgme_debug_set_debug_envvar (value); + else if (!strcmp (name, "disable-gpgconf")) + { + _gpgme_dirinfo_disable_gpgconf (); + return 0; + } + else if (!strcmp (name, "gpgconf-name")) + return _gpgme_set_default_gpgconf_name (value); + else if (!strcmp (name, "gpg-name")) + return _gpgme_set_default_gpg_name (value); else return -1; } diff --git a/src/posix-util.c b/src/posix-util.c index d4e4e3f4..5bfc4865 100644 --- a/src/posix-util.c +++ b/src/posix-util.c @@ -29,6 +29,46 @@ #include "util.h" #include "sys-util.h" +#include "debug.h" + +/* These variables store the malloced name of alternative default + binaries. The are set only once by gpgme_set_global_flag. */ +static char *default_gpg_name; +static char *default_gpgconf_name; + +/* Set the default name for the gpg binary. This function may only be + called by gpgme_set_global_flag. Returns 0 on success. Leading + directories are removed from NAME. */ +int +_gpgme_set_default_gpg_name (const char *name) +{ + const char *s; + + s = strrchr (name, '/'); + if (s) + name = s + 1; + + if (!default_gpg_name) + default_gpg_name = strdup (name); + return !default_gpg_name; +} + +/* Set the default name for the gpgconf binary. This function may + only be called by gpgme_set_global_flag. Returns 0 on success. + Leading directories are removed from NAME. */ +int +_gpgme_set_default_gpgconf_name (const char *name) +{ + const char *s; + + s = strrchr (name, '/'); + if (s) + name = s + 1; + + if (!default_gpgconf_name) + default_gpgconf_name = strdup (name); + return !default_gpgconf_name; +} /* Find an executable program PGM along the envvar PATH. */ @@ -60,6 +100,9 @@ walk_path (const char *pgm) path = s + 1; } + _gpgme_debug (DEBUG_ENGINE, "gpgme-walk_path: '%s' not found in '%s'", + pgm, path); + free (fname); return NULL; } @@ -72,7 +115,7 @@ walk_path (const char *pgm) char * _gpgme_get_gpg_path (void) { - return walk_path ("gpg"); + return walk_path (default_gpg_name? default_gpg_name : "gpg"); } @@ -81,7 +124,7 @@ _gpgme_get_gpg_path (void) char * _gpgme_get_gpgconf_path (void) { - return walk_path ("gpgconf"); + return walk_path (default_gpgconf_name? default_gpgconf_name : "gpgconf"); } /* See w32-util.c */ diff --git a/src/sys-util.h b/src/sys-util.h index 3686f897..7180fca3 100644 --- a/src/sys-util.h +++ b/src/sys-util.h @@ -21,6 +21,9 @@ #define SYS_UTIL_H /*-- {posix,w32}-util.c --*/ +int _gpgme_set_default_gpg_name (const char *name); +int _gpgme_set_default_gpgconf_name (const char *name); + char *_gpgme_get_gpg_path (void); char *_gpgme_get_gpgconf_path (void); diff --git a/src/util.h b/src/util.h index 57c8b138..c0934e16 100644 --- a/src/util.h +++ b/src/util.h @@ -51,6 +51,8 @@ int _gpgme_get_conf_int (const char *key, int *value); void _gpgme_allow_set_foreground_window (pid_t pid); /*-- dirinfo.c --*/ +void _gpgme_dirinfo_disable_gpgconf (void); + const char *_gpgme_get_default_homedir (void); const char *_gpgme_get_default_agent_socket (void); const char *_gpgme_get_default_gpg_name (void); diff --git a/src/w32-util.c b/src/w32-util.c index 31a58bbd..3884b40d 100644 --- a/src/w32-util.c +++ b/src/w32-util.c @@ -81,6 +81,11 @@ DEFINE_STATIC_LOCK (get_path_lock); file name of the DLL or executable which contains the gpgme code. */ static HMODULE my_hmodule; +/* These variables store the malloced name of alternative default + binaries. The are set only once by gpgme_set_global_flag. */ +static char *default_gpg_name; +static char *default_gpgconf_name; + #ifdef HAVE_ALLOW_SET_FOREGROUND_WINDOW @@ -151,6 +156,32 @@ wchar_to_utf8 (const wchar_t *string) } +/* Replace all forward slashes by backslashes. */ +static void +replace_slashes (char *string) +{ + for (; *string; string++) + if (*string == '/') + *string = '\\'; +} + + +/* Get the base name of NAME. Returns a pointer into NAME right after + the last slash or backslash or to NAME if no slash or backslash + exists. */ +static const char * +get_basename (const char *name) +{ + const char *mark, *s; + + for (mark=NULL, s=name; *s; s++) + if (*s == '/' || *s == '\\') + mark = s; + + return mark? mark+1 : name; +} + + void _gpgme_allow_set_foreground_window (pid_t pid) { @@ -373,7 +404,7 @@ find_program_in_inst_dir (const char *inst_dir, const char *name) char *dir; /* If an installation directory has been passed, this overrides a - location given bu the registry. The idea here is that we prefer + 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 @@ -424,6 +455,41 @@ find_program_at_standard_place (const char *name) } +/* Set the default name for the gpg binary. This function may only be + called by gpgme_set_global_flag. Returns 0 on success. */ +int +_gpgme_set_default_gpg_name (const char *name) +{ + if (!default_gpg_name) + { + default_gpg_name = malloc (strlen (name) + 5); + if (default_gpg_name) + { + strcpy (stpcpy (default_gpg_name, name), ".exe"); + replace_slashes (default_gpg_name); + } + } + return !default_gpg_name; +} + +/* Set the default name for the gpgconf binary. This function may only be + called by gpgme_set_global_flag. Returns 0 on success. */ +int +_gpgme_set_default_gpgconf_name (const char *name) +{ + if (!default_gpgconf_name) + { + default_gpgconf_name = malloc (strlen (name) + 5); + if (default_gpgconf_name) + { + strcpy (stpcpy (default_gpgconf_name, name), ".exe"); + replace_slashes (default_gpgconf_name); + } + } + return !default_gpgconf_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 not installed. This function is only called by get_gpgconf_item @@ -432,27 +498,47 @@ char * _gpgme_get_gpg_path (void) { char *gpg; - const char *inst_dir; + const char *inst_dir, *name; inst_dir = _gpgme_get_inst_dir (); - gpg = find_program_in_inst_dir (inst_dir, "gpg.exe"); + gpg = find_program_in_inst_dir + (inst_dir, + default_gpg_name? get_basename (default_gpg_name) : "gpg.exe"); if (!gpg) - gpg = find_program_at_standard_place ("GNU\\GnuPG\\gpg.exe"); + { + 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); + } + return gpg; } + /* This function is only called by get_gpgconf_item and may not be called concurrently. */ char * _gpgme_get_gpgconf_path (void) { char *gpgconf; - const char *inst_dir; + const char *inst_dir, *name; inst_dir = _gpgme_get_inst_dir (); - gpgconf = find_program_in_inst_dir (inst_dir, "gpgconf.exe"); + gpgconf = find_program_in_inst_dir + (inst_dir, + default_gpgconf_name? get_basename (default_gpgconf_name) : "gpgconf.exe"); if (!gpgconf) - gpgconf = find_program_at_standard_place ("GNU\\GnuPG\\gpgconf.exe"); + { + 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); + } return gpgconf; } diff --git a/tests/t-engine-info.c b/tests/t-engine-info.c index 43acd3d2..11fe4a4e 100644 --- a/tests/t-engine-info.c +++ b/tests/t-engine-info.c @@ -28,6 +28,12 @@ #include +#define PGM "t-engine-info" + +static int verbose; + + + #define fail_if_err(err) \ do \ @@ -42,13 +48,66 @@ while (0) - int main (int argc, char **argv ) { + int last_argc = -1; gpgme_engine_info_t info; gpgme_error_t err; + if (argc) + { argc--; argv++; } + + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + fputs ("usage: " PGM " [options]\n" + "Options:\n" + " --set-global-flag KEY VALUE\n", + stdout); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--set-global-flag")) + { + argc--; argv++; + if (argc < 2) + { + fprintf (stderr, PGM ": not enough arguments for option\n"); + exit (1); + } + if (gpgme_set_global_flag (argv[0], argv[1])) + { + fprintf (stderr, PGM ": gpgme_set_global_flag failed\n"); + exit (1); + } + argc--; argv++; + argc--; argv++; + } + else if (!strncmp (*argv, "--", 2)) + { + fprintf (stderr, PGM ": unknown option '%s'\n", *argv); + exit (1); + } + } + + if (argc) + { + fprintf (stderr, PGM ": unexpected arguments\n"); + exit (1); + } + gpgme_check_version (NULL); err = gpgme_get_engine_info (&info); fail_if_err (err);