dirmngr: Improve downloading of swdb.lst.

* dirmngr/loadswdb.c (time_of_saved_swdb): Aslo return the "verified"
timestamp.
(dirmngr_load_swdb): Avoid unnecessary disk or network access witout
FORCE.  Do not update swdb.lst if it did not change.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2016-11-17 10:07:11 +01:00
parent d8da5bc50b
commit c45ca316a5
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 63 additions and 19 deletions

View File

@ -30,11 +30,11 @@
#include "ks-engine.h" #include "ks-engine.h"
/* Get the time from the current swdb file and store it at R_TIME. If /* Get the time from the current swdb file and store it at R_FILEDATE
* the file does not exist 0 is stored at R_TIME. The function * and R_VERIFIED. If the file does not exist 0 is stored at there.
* returns 0 on sucess or an error code. */ * The function returns 0 on sucess or an error code. */
static gpg_error_t static gpg_error_t
time_of_saved_swdb (const char *fname, time_t *r_time) time_of_saved_swdb (const char *fname, time_t *r_filedate, time_t *r_verified)
{ {
gpg_error_t err; gpg_error_t err;
estream_t fp = NULL; estream_t fp = NULL;
@ -43,9 +43,12 @@ time_of_saved_swdb (const char *fname, time_t *r_time)
size_t maxlen; size_t maxlen;
ssize_t len; ssize_t len;
char *fields[2]; char *fields[2];
time_t t = (time_t)(-1); gnupg_isotime_t isot;
time_t filedate = (time_t)(-1);
time_t verified = (time_t)(-1);
*r_time = 0; *r_filedate = 0;
*r_verified = 0;
fp = es_fopen (fname, "r"); fp = es_fopen (fname, "r");
err = fp? 0 : gpg_error_from_syserror (); err = fp? 0 : gpg_error_from_syserror ();
@ -76,12 +79,15 @@ time_of_saved_swdb (const char *fname, time_t *r_time)
continue; /* Skip comments. */ continue; /* Skip comments. */
/* Record the meta data. */ /* Record the meta data. */
if (!strcmp (fields[0], ".filedate")) if (filedate == (time_t)(-1) && !strcmp (fields[0], ".filedate"))
{ {
gnupg_isotime_t isot; if (string2isotime (isot, fields[1]))
if (string2isotime (isot, fields[1]) filedate = isotime2epoch (isot);
&& (t = isotime2epoch (isot)) != (time_t)(-1)) }
break; /* Got the time - stop reading. */ else if (verified == (time_t)(-1) && !strcmp (fields[0], ".verified"))
{
if (string2isotime (isot, fields[1]))
verified = isotime2epoch (isot);
} }
} }
if (len < 0 || es_ferror (fp)) if (len < 0 || es_ferror (fp))
@ -89,13 +95,14 @@ time_of_saved_swdb (const char *fname, time_t *r_time)
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
goto leave; goto leave;
} }
if (t == (time_t)(-1)) if (filedate == (time_t)(-1) || verified == (time_t)(-1))
{ {
err = gpg_error (GPG_ERR_INV_TIME); err = gpg_error (GPG_ERR_INV_TIME);
goto leave; goto leave;
} }
*r_time = t; *r_filedate = filedate;
*r_verified = verified;
leave: leave:
if (err) if (err)
@ -214,6 +221,8 @@ dirmngr_load_swdb (ctrl_t ctrl, int force)
struct verify_status_parm_s verify_status_parm = { (time_t)(-1), 0 }; struct verify_status_parm_s verify_status_parm = { (time_t)(-1), 0 };
estream_t outfp = NULL; estream_t outfp = NULL;
time_t now = gnupg_get_time (); time_t now = gnupg_get_time ();
time_t filedate = 0; /* ".filedate" from our swdb. */
time_t verified = 0; /* ".verified" from our swdb. */
gnupg_isotime_t isotime; gnupg_isotime_t isotime;
@ -227,15 +236,37 @@ dirmngr_load_swdb (ctrl_t ctrl, int force)
/* Check whether there is a need to get an update. */ /* Check whether there is a need to get an update. */
if (!force) if (!force)
{ {
time_t filetime; static int not_older_than;
static time_t lastcheck;
err = time_of_saved_swdb (fname, &filetime); if (!not_older_than)
{
/* To balance access to the server we use a random time from
* 5 to 7 days for update checks. */
not_older_than = 5 * 86400;
not_older_than += (get_uint_nonce () % (2*86400));
}
if (now - lastcheck < 3600)
{
/* We checked our swdb file in the last hour - don't check
* again to avoid unnecessary disk access. */
err = 0;
goto leave;
}
lastcheck = now;
err = time_of_saved_swdb (fname, &filedate, &verified);
if (gpg_err_code (err) == GPG_ERR_INV_TIME)
err = 0; /* Force reading. */
if (err) if (err)
goto leave; goto leave;
if (filetime >= now) if (filedate >= now)
goto leave; /* Current or newer. */ goto leave; /* Current or newer. */
if (now - filetime < 3*86400) if (now - filedate < not_older_than)
goto leave; /* Not older than 3 days. */ goto leave; /* Our copy is pretty new (not older than 7 days). */
if (verified > now && now - verified < 3*3600)
goto leave; /* We downloaded and verified in the last 3 hours. */
} }
/* Create the filename of the file with the keys. */ /* Create the filename of the file with the keys. */
@ -277,6 +308,11 @@ dirmngr_load_swdb (ctrl_t ctrl, int force)
if (err) if (err)
goto leave; goto leave;
/* If our swdb is not older than the downloaded one. We don't
* bother to update. */
if (!force && filedate >= verify_status_parm.sigtime)
goto leave;
/* Create a file name for a temporary file in the home directory. /* Create a file name for a temporary file in the home directory.
* We will later rename that file to the real name. */ * We will later rename that file to the real name. */
{ {

View File

@ -307,7 +307,15 @@ is given, check that file instead.
@item --query-swdb @var{package_name} [@var{version_string}] @item --query-swdb @var{package_name} [@var{version_string}]
Returns the current version for @var{package_name} and if Returns the current version for @var{package_name} and if
@var{version_string} is given also an indicator on whether an update @var{version_string} is given also an indicator on whether an update
is available. is available. The actual file with the software version is
automatically downloaded and checked by @command{dirmngr}.
@command{dirmngr} uses a thresholds to avoid download the file too
often and it does this by default only if it can be done via Tor. To
force an update of that file this command can be used:
@example
gpg-connect-agent --dirmngr 'loadswdb --force' /bye
@end example
@item --reload [@var{component}] @item --reload [@var{component}]