diff options
author | Werner Koch <[email protected]> | 2016-11-02 16:54:32 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2016-11-02 16:58:11 +0000 |
commit | 0ed6a6df5aa421a9c5cdb1e63867f0deee79af9e (patch) | |
tree | f2e461fa3f22c31ec8352f86224221ab7f531d43 /tools | |
parent | common: Improve compare_string_versions. (diff) | |
download | gnupg-0ed6a6df5aa421a9c5cdb1e63867f0deee79af9e.tar.gz gnupg-0ed6a6df5aa421a9c5cdb1e63867f0deee79af9e.zip |
gpgconf: Add command --query-swdb.
* tools/gpgconf.c (aQuerySWDB): New.
(opts): Add --query-swdb.
(valid_swdb_name_p): New.
(query_swdb): New.
(main): Implement command --query-swdb.
--
Right now this command is not very useful because dimngr has not yet
been changed to create the swdb.lst. For manual tests the swdb.lst
file from the Net can be used with these additional lines:
.filedate 20161102T130337
.verified 20161102T150000
Diffstat (limited to 'tools')
-rw-r--r-- | tools/gpgconf.c | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/tools/gpgconf.c b/tools/gpgconf.c index a1ca79fd0..1f00418ee 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -1,5 +1,6 @@ /* gpgconf.c - Configuration utility for GnuPG * Copyright (C) 2003, 2007, 2009, 2011 Free Software Foundation, Inc. + * Copyright (C) 2016 g10 Code GmbH. * * This file is part of GnuPG. * @@ -52,6 +53,7 @@ enum cmd_and_opt_values aApplyDefaults, aListConfig, aCheckConfig, + aQuerySWDB, aListDirs, aLaunch, aKill, @@ -79,6 +81,8 @@ static ARGPARSE_OPTS opts[] = N_("list global configuration file") }, { aCheckConfig, "check-config", 256, N_("check global configuration file") }, + { aQuerySWDB, "query-swdb", 256, + N_("query the software version database") }, { aReload, "reload", 256, N_("reload all or a given component")}, { aLaunch, "launch", 256, N_("launch a given component")}, { aKill, "kill", 256, N_("kill a given component")}, @@ -203,6 +207,235 @@ list_dirs (estream_t fp, char **names) } + +/* Check whether NAME is valid argument for query_swdb(). Valid names + * start with a letter and contain only alphanumeric characters or an + * underscore. */ +static int +valid_swdb_name_p (const char *name) +{ + if (!name || !*name || !alphap (name)) + return 0; + + for (name++; *name; name++) + if (!alnump (name) && *name != '_') + return 0; + + return 1; +} + + +/* Query the SWDB file. If necessary and possible this functions asks + * the dirmngr to load an updated version of that file. The caller + * needs to provide the NAME to query (e.g. "gnupg", "libgcrypt") and + * optional the currently installed version in CURRENT_VERSION. The + * output written to OUT is a colon delimited line with these fields: + * + * name :: The name of the package + * status :: This value tells the status of the software package + * '-' :: No information available + * (error or CURRENT_VERSION not given) + * '?' :: Unknown NAME + * 'u' :: Update available + * 'c' :: The version is Current + * 'n' :: The current version is already Newer than the + * available one. + * urgency :: If the value is greater than zero an urgent update is required. + * error :: 0 on success or an gpg_err_code_t + * Common codes seen: + * GPG_ERR_TOO_OLD :: The SWDB file is to old to be used. + * GPG_ERR_ENOENT :: The SWDB file is not available. + * GPG_ERR_BAD_SIGNATURE :: Currupted SWDB file. + * filedate:: Date of the swdb file (yyyymmddThhmmss) + * verified:: Date we checked the validity of the file (yyyyymmddThhmmss) + * version :: The version string from the swdb. + * reldate :: Release date of that version (yyyymmddThhmmss) + * size :: Size of the package in bytes. + * hash :: SHA-2 hash of the package. + * + */ +static void +query_swdb (estream_t out, const char *name, const char *current_version) +{ + gpg_error_t err; + const char *search_name; + char *fname = NULL; + estream_t fp = NULL; + char *line = NULL; + char *self_version = NULL; + size_t length_of_line = 0; + size_t maxlen; + ssize_t len; + char *fields[2]; + char *p; + gnupg_isotime_t filedate = {0}; + gnupg_isotime_t verified = {0}; + char *value_ver = NULL; + gnupg_isotime_t value_date = {0}; + char *value_size = NULL; + char *value_sha2 = NULL; + unsigned long value_size_ul; + int status, i; + + + if (!valid_swdb_name_p (name)) + { + log_error ("error in package name '%s': %s\n", + name, gpg_strerror (GPG_ERR_INV_NAME)); + goto leave; + } + if (!strcmp (name, "gnupg")) + search_name = "gnupg21"; + else if (!strcmp (name, "gnupg1")) + search_name = "gnupg1"; + else + search_name = name; + + if (!current_version && !strcmp (name, "gnupg")) + { + /* Use our own version but string a possible beta string. */ + self_version = xstrdup (PACKAGE_VERSION); + p = strchr (self_version, '-'); + if (p) + *p = 0; + current_version = self_version; + } + + if (current_version && compare_version_strings (current_version, NULL)) + { + log_error ("error in version string '%s': %s\n", + current_version, gpg_strerror (GPG_ERR_INV_ARG)); + goto leave; + } + + fname = make_filename (gnupg_homedir (), "swdb.lst", NULL); + fp = es_fopen (fname, "r"); + if (!fp) + { + err = gpg_error_from_syserror (); + es_fprintf (out, "%s:-::%u:::::::\n", name, gpg_err_code (err)); + if (gpg_err_code (err) != GPG_ERR_ENOENT) + log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err)); + goto leave; + } + + /* Note that the parser uses the first occurance of a matching + * values and ignores possible duplicated values. */ + + maxlen = 2048; /* Set limit. */ + while ((len = es_read_line (fp, &line, &length_of_line, &maxlen)) > 0) + { + if (!maxlen) + { + err = gpg_error (GPG_ERR_LINE_TOO_LONG); + log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err)); + goto leave; + } + /* Strip newline and carriage return, if present. */ + while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r')) + line[--len] = '\0'; + + if (split_fields (line, fields, DIM (fields)) < DIM(fields)) + continue; /* Skip empty lines and names w/o a value. */ + if (*fields[0] == '#') + continue; /* Skip comments. */ + + /* Record the meta data. */ + if (!*filedate && !strcmp (fields[0], ".filedate")) + { + string2isotime (filedate, fields[1]); + continue; + } + if (!*verified && !strcmp (fields[0], ".verified")) + { + string2isotime (verified, fields[1]); + continue; + } + + /* Tokenize the name. */ + p = strrchr (fields[0], '_'); + if (!p) + continue; /* Name w/o an underscore. */ + *p++ = 0; + + /* Wait for the requested name. */ + if (!strcmp (fields[0], search_name)) + { + if (!strcmp (p, "ver") && !value_ver) + value_ver = xstrdup (fields[1]); + else if (!strcmp (p, "date") && !*value_date) + string2isotime (value_date, fields[1]); + else if (!strcmp (p, "size") && !value_size) + value_size = xstrdup (fields[1]); + else if (!strcmp (p, "sha2") && !value_sha2) + value_sha2 = xstrdup (fields[1]); + } + } + if (len < 0 || es_ferror (fp)) + { + err = gpg_error_from_syserror (); + log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err)); + goto leave; + } + + if (!*filedate || !*verified) + { + err = gpg_error (GPG_ERR_INV_TIME); + es_fprintf (out, "%s:-::%u:::::::\n", name, gpg_err_code (err)); + goto leave; + } + + if (!value_ver) + { + es_fprintf (out, "%s:?:::::::::\n", name); + goto leave; + } + + if (value_size) + { + gpg_err_set_errno (0); + value_size_ul = strtoul (value_size, &p, 10); + if (errno) + value_size_ul = 0; + else if (*p == 'k') + value_size_ul *= 1024; + } + + err = 0; + status = '-'; + if (compare_version_strings (value_ver, NULL)) + err = gpg_error (GPG_ERR_INV_VALUE); + else if (!current_version) + ; + else if (!(i = compare_version_strings (value_ver, current_version))) + status = 'c'; + else if (i > 0) + status = 'u'; + else + status = 'n'; + + es_fprintf (out, "%s:%c::%d:%s:%s:%s:%s:%lu:%s:\n", + name, + status, + err, + filedate, + verified, + value_ver, + value_date, + value_size_ul, + value_sha2? value_sha2 : ""); + + leave: + xfree (value_ver); + xfree (value_size); + xfree (value_sha2); + xfree (line); + es_fclose (fp); + xfree (fname); + xfree (self_version); +} + + /* gpgconf main. */ int main (int argc, char **argv) @@ -250,6 +483,7 @@ main (int argc, char **argv) case aApplyDefaults: case aListConfig: case aCheckConfig: + case aQuerySWDB: case aReload: case aLaunch: case aKill: @@ -417,6 +651,18 @@ main (int argc, char **argv) list_dirs (outfp, argc? argv : NULL); break; + case aQuerySWDB: + /* Query the software version database. */ + if (!fname || argc > 2) + { + es_fprintf (es_stderr, "usage: %s --query-swdb NAME [VERSION]\n", + GPGCONF_NAME); + exit (2); + } + get_outfp (&outfp); + query_swdb (outfp, fname, argc > 1? argv[1] : NULL); + break; + case aCreateSocketDir: { char *socketdir; |