diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 034f7d5b4..3f07b2eac 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -99,6 +99,7 @@ enum cmd_and_opt_values { aFlush, aGPGConfList, aGPGConfTest, + aGPGConfVersions, oOptions, oDebug, @@ -161,6 +162,7 @@ static gpgrt_opt_t opts[] = { ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"), ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@"), + ARGPARSE_c (aGPGConfVersions, "gpgconf-versions", "@"), ARGPARSE_group (300, N_("@Commands:\n ")), @@ -411,6 +413,8 @@ static ldap_server_t parse_ldapserver_file (const char* filename, int ienoent); static fingerprint_list_t parse_ocsp_signer (const char *string); static void netactivity_action (void); static void handle_connections (assuan_fd_t listen_fd); +static void gpgconf_versions (void); + /* NPth wrapper function definitions. */ ASSUAN_SYSTEM_NPTH_IMPL; @@ -1007,6 +1011,7 @@ main (int argc, char **argv) case aFetchCRL: case aGPGConfList: case aGPGConfTest: + case aGPGConfVersions: cmd = pargs.r_opt; break; @@ -1116,7 +1121,7 @@ main (int argc, char **argv) * because it will attempt to connect to the tor client and that can * be time consuming. */ post_option_parsing (); - if (cmd != aGPGConfTest && cmd != aGPGConfList) + if (cmd != aGPGConfTest && cmd != aGPGConfList && cmd != aGPGConfVersions) set_tor_mode (); /* Get LDAP server list from file. */ @@ -1518,6 +1523,9 @@ main (int argc, char **argv) es_printf ("resolver-timeout:%lu:%u\n", flags | GC_OPT_FLAG_DEFAULT, 0); } + else if (cmd == aGPGConfVersions) + gpgconf_versions (); + cleanup (); return !!rc; } @@ -2327,3 +2335,61 @@ dirmngr_get_current_socket_name (void) else return dirmngr_socket_name (); } + + + +/* Parse the revision part from the extended version blurb. */ +static const char * +get_revision_from_blurb (const char *blurb, int *r_len) +{ + const char *s = blurb? blurb : ""; + int n; + + for (; *s; s++) + if (*s == '\n' && s[1] == '(') + break; + if (s) + { + s += 2; + for (n=0; s[n] && s[n] != ' '; n++) + ; + } + else + { + s = "?"; + n = 1; + } + *r_len = n; + return s; +} + + +/* Print versions of dirmngr and used libraries. This is used by + * "gpgconf --show-versions" so that there is no need to link gpgconf + * against all these libraries. This is an internal API and should + * not be relied upon. */ +static void +gpgconf_versions (void) +{ + const char *s; + int n; + + /* Unfortunately Npth has no way to get the version. */ + + s = get_revision_from_blurb (assuan_check_version ("\x01\x01"), &n); + es_fprintf (es_stdout, "* Libassuan %s (%.*s)\n\n", + assuan_check_version (NULL), n, s); + + es_fprintf (es_stdout, "* KSBA %s \n\n", + ksba_check_version (NULL)); + +#ifdef HTTP_USE_NTBTLS + s = get_revision_from_blurb (ntbtls_check_version ("\x01\x01"), &n); + es_fprintf (es_stdout, "* NTBTLS %s (%.*s)\n\n", + ntbtls_check_version (NULL), n, s); +#elif HTTP_USE_GNUTLS + es_fprintf (es_stdout, "* GNUTLS %s\n\n", + gnutls_check_version (NULL)); +#endif + +} diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 3583abe57..919bcb357 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -52,14 +52,6 @@ #include "../common/gc-opt-flags.h" #include "gpgconf.h" -/* There is a problem with gpg 1.4 under Windows: --gpgconf-list - returns a plain filename without escaping. As long as we have not - fixed that we need to use gpg2. */ -#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM) -#define GPGNAME "gpg2" -#else -#define GPGNAME GPG_NAME -#endif diff --git a/tools/gpgconf.c b/tools/gpgconf.c index f5f57f577..0b7348d1d 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -33,6 +33,7 @@ #include "../common/sysutils.h" #include "../common/init.h" #include "../common/status.h" +#include "../common/exechelp.h" /* Constants to identify the commands and options. */ @@ -69,6 +70,7 @@ enum cmd_and_opt_values aRemoveSocketDir, aApplyProfile, aReload, + aShowVersions, aShowCodepages }; @@ -100,6 +102,7 @@ static gpgrt_opt_t opts[] = { aKill, "kill", 256, N_("kill a given component")}, { aCreateSocketDir, "create-socketdir", 256, "@"}, { aRemoveSocketDir, "remove-socketdir", 256, "@"}, + ARGPARSE_c (aShowVersions, "show-versions", "@"), ARGPARSE_c (aShowCodepages, "show-codepages", "@"), { 301, NULL, 0, N_("@\nOptions:\n ") }, @@ -127,6 +130,9 @@ static gpgrt_opt_t opts[] = * this is NULL. */ static estream_t statusfp; +static void show_versions (estream_t fp); + + /* Print usage information and provide strings for help. */ static const char * @@ -604,6 +610,7 @@ main (int argc, char **argv) case aKill: case aCreateSocketDir: case aRemoveSocketDir: + case aShowVersions: case aShowCodepages: cmd = pargs.r_opt; break; @@ -923,6 +930,13 @@ main (int argc, char **argv) } break; + case aShowVersions: + { + get_outfp (&outfp); + show_versions (outfp); + } + break; + case aShowCodepages: #ifdef HAVE_W32_SYSTEM { @@ -961,3 +975,157 @@ gpgconf_failure (gpg_error_t err) gpg_err_code (err) == GPG_ERR_USER_2? GPG_ERR_EINVAL : err); exit (gpg_err_code (err) == GPG_ERR_USER_2? 2 : 1); } + + + +/* Parse the revision part from the extended version blurb. */ +static const char * +get_revision_from_blurb (const char *blurb, int *r_len) +{ + const char *s = blurb? blurb : ""; + int n; + + for (; *s; s++) + if (*s == '\n' && s[1] == '(') + break; + if (s) + { + s += 2; + for (n=0; s[n] && s[n] != ' '; n++) + ; + } + else + { + s = "?"; + n = 1; + } + *r_len = n; + return s; +} + + +static void +show_version_gnupg (estream_t fp) +{ + es_fprintf (fp, "* GnuPG %s (%s)\n%s\n", + gpgrt_strusage (13), BUILD_REVISION, gpgrt_strusage (17)); +#ifdef HAVE_W32_SYSTEM + { + OSVERSIONINFO osvi = { sizeof (osvi) }; + + GetVersionEx (&osvi); + es_fprintf (fp, "Windows %lu.%lu build %lu%s%s%s\n", + (unsigned long)osvi.dwMajorVersion, + (unsigned long)osvi.dwMinorVersion, + (unsigned long)osvi.dwBuildNumber, + *osvi.szCSDVersion? " (":"", + osvi.szCSDVersion, + *osvi.szCSDVersion? ")":"" + ); + } +#endif /*HAVE_W32_SYSTEM*/ +} + + +static void +show_version_libgcrypt (estream_t fp) +{ + const char *s; + int n; + + s = get_revision_from_blurb (gcry_check_version ("\x01\x01"), &n); + es_fprintf (fp, "* Libgcrypt %s (%.*s)\n", + gcry_check_version (NULL), n, s); +#if GCRYPT_VERSION_NUMBER >= 0x010800 + s = gcry_get_config (0, NULL); + if (s) + es_fputs (s, fp); +#endif +} + + +static void +show_version_gpgrt (estream_t fp) +{ + const char *s; + int n; + + s = get_revision_from_blurb (gpg_error_check_version ("\x01\x01"), &n); + es_fprintf (fp, "* GpgRT %s (%.*s)\n", + gpg_error_check_version (NULL), n, s); +} + + +/* Printing version information for other libraries is problematic + * because we don't want to link gpgconf to all these libraries. The + * best solution is delegating this to dirmngr which uses libassuan, + * libksba, libnpth and ntbtls anyway. */ +static void +show_versions_via_dirmngr (estream_t fp) +{ + gpg_error_t err; + const char *pgmname; + const char *argv[2]; + estream_t outfp; + pid_t pid; + char *line = NULL; + size_t line_len = 0; + ssize_t length; + int exitcode; + + pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); + argv[0] = "--gpgconf-versions"; + argv[1] = NULL; + err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0, + NULL, &outfp, NULL, &pid); + if (err) + { + log_error ("error spawning %s: %s", pgmname, gpg_strerror (err)); + es_fprintf (fp, "[error: can't get further info]\n"); + return; + } + + while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0) + { + /* Strip newline and carriage return, if present. */ + while (length > 0 + && (line[length - 1] == '\n' || line[length - 1] == '\r')) + line[--length] = '\0'; + es_fprintf (fp, "%s\n", line); + } + if (length < 0 || es_ferror (outfp)) + { + err = gpg_error_from_syserror (); + log_error ("error reading from %s: %s\n", pgmname, gpg_strerror (err)); + } + if (es_fclose (outfp)) + { + err = gpg_error_from_syserror (); + log_error ("error closing output stream of %s: %s\n", + pgmname, gpg_strerror (err)); + } + + err = gnupg_wait_process (pgmname, pid, 1, &exitcode); + if (err) + { + log_error ("running %s failed (exitcode=%d): %s\n", + pgmname, exitcode, gpg_strerror (err)); + es_fprintf (fp, "[error: can't get further info]\n"); + } + gnupg_release_process (pid); + xfree (line); +} + + +/* Show all kind of version information. */ +static void +show_versions (estream_t fp) +{ + show_version_gnupg (fp); + es_fputc ('\n', fp); + show_version_libgcrypt (fp); + es_fputc ('\n', fp); + show_version_gpgrt (fp); + es_fputc ('\n', fp); + show_versions_via_dirmngr (fp); +}