1 /* loadswdb.c - Load the swdb file from versions.gnupg.org
2 * Copyright (C) 2016 g10 Code GmbH
3 * Copyright (C) 2016 Bundesamt für Sicherheit in der Informationstechnik
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <https://www.gnu.org/licenses/>.
28 #include "../common/ccparray.h"
29 #include "../common/exectool.h"
31 #include "ks-engine.h"
34 /* Get the time from the current swdb file and store it at R_FILEDATE
35 * and R_VERIFIED. If the file does not exist 0 is stored at there.
36 * The function returns 0 on success or an error code. */
38 time_of_saved_swdb (const char *fname, time_t *r_filedate, time_t *r_verified)
43 size_t length_of_line = 0;
48 time_t filedate = (time_t)(-1);
49 time_t verified = (time_t)(-1);
54 fp = es_fopen (fname, "r");
55 err = fp? 0 : gpg_error_from_syserror ();
58 if (gpg_err_code (err) == GPG_ERR_ENOENT)
59 err = 0; /* No file - assume time is the year of Unix. */
63 /* Note that the parser uses the first occurrence of a matching
64 * values and ignores possible duplicated values. */
65 maxlen = 2048; /* Set limit. */
66 while ((len = es_read_line (fp, &line, &length_of_line, &maxlen)) > 0)
70 err = gpg_error (GPG_ERR_LINE_TOO_LONG);
73 /* Strip newline and carriage return, if present. */
74 while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
77 if (split_fields (line, fields, DIM (fields)) < DIM(fields))
78 continue; /* Skip empty lines and names w/o a value. */
79 if (*fields[0] == '#')
80 continue; /* Skip comments. */
82 /* Record the meta data. */
83 if (filedate == (time_t)(-1) && !strcmp (fields[0], ".filedate"))
85 if (string2isotime (isot, fields[1]))
86 filedate = isotime2epoch (isot);
88 else if (verified == (time_t)(-1) && !strcmp (fields[0], ".verified"))
90 if (string2isotime (isot, fields[1]))
91 verified = isotime2epoch (isot);
94 if (len < 0 || es_ferror (fp))
96 err = gpg_error_from_syserror ();
99 if (filedate == (time_t)(-1) || verified == (time_t)(-1))
101 err = gpg_error (GPG_ERR_INV_TIME);
105 *r_filedate = filedate;
106 *r_verified = verified;
110 log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
118 /* Read a file from URL and return it as an estream memory buffer at
121 fetch_file (ctrl_t ctrl, const char *url, estream_t *r_fp)
125 estream_t httpfp = NULL;
126 size_t nread, nwritten;
129 if ((err = ks_http_fetch (ctrl, url, &httpfp)))
132 /* We now read the data from the web server into a memory buffer.
133 * To avoid excessive memory use in case of a ill behaving server we
134 * put a 64 k size limit on the buffer. As of today the actual size
135 * of the swdb.lst file is 3k. */
136 fp = es_fopenmem (64*1024, "rw");
139 err = gpg_error_from_syserror ();
140 log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
146 if (es_read (httpfp, buffer, sizeof buffer, &nread))
148 err = gpg_error_from_syserror ();
149 log_error ("error reading '%s': %s\n",
150 es_fname_get (httpfp), gpg_strerror (err));
156 if (es_write (fp, buffer, nread, &nwritten))
158 err = gpg_error_from_syserror ();
159 log_error ("error writing '%s': %s\n",
160 es_fname_get (fp), gpg_strerror (err));
163 else if (nread != nwritten)
165 err = gpg_error (GPG_ERR_EIO);
166 log_error ("error writing '%s': %s\n",
167 es_fname_get (fp), "short write");
183 /* Communication object for verify_status_cb. */
184 struct verify_status_parm_s
191 verify_status_cb (void *opaque, const char *keyword, char *args)
193 struct verify_status_parm_s *parm = opaque;
196 log_debug ("gpgv status: %s %s\n", keyword, args);
198 /* We care only about the first valid signature. */
199 if (!strcmp (keyword, "VALIDSIG") && !parm->anyvalid)
204 if (split_fields (args, fields, DIM (fields)) >= 3)
205 parm->sigtime = parse_timestamp (fields[2], NULL);
211 /* Load the swdb file into the current home directory. Do this onlky
212 * when needed unless FORCE is set which will always get a new
215 dirmngr_load_swdb (ctrl_t ctrl, int force)
218 char *fname = NULL; /* The swdb.lst file. */
219 char *tmp_fname = NULL; /* The temporary swdb.lst file. */
220 char *keyfile_fname = NULL;
221 estream_t swdb = NULL;
222 estream_t swdb_sig = NULL;
224 const char **argv = NULL;
225 struct verify_status_parm_s verify_status_parm = { (time_t)(-1), 0 };
226 estream_t outfp = NULL;
227 time_t now = gnupg_get_time ();
228 time_t filedate = 0; /* ".filedate" from our swdb. */
229 time_t verified = 0; /* ".verified" from our swdb. */
230 gnupg_isotime_t isotime;
233 fname = make_filename_try (gnupg_homedir (), "swdb.lst", NULL);
236 err = gpg_error_from_syserror ();
240 /* Check whether there is a need to get an update. */
243 static int not_older_than;
244 static time_t lastcheck;
248 /* To balance access to the server we use a random time from
249 * 5 to 7 days for update checks. */
250 not_older_than = 5 * 86400;
251 not_older_than += (get_uint_nonce () % (2*86400));
254 if (now - lastcheck < 3600)
256 /* We checked our swdb file in the last hour - don't check
257 * again to avoid unnecessary disk access. */
263 err = time_of_saved_swdb (fname, &filedate, &verified);
264 if (gpg_err_code (err) == GPG_ERR_INV_TIME)
265 err = 0; /* Force reading. */
269 goto leave; /* Current or newer. */
270 if (now - filedate < not_older_than)
271 goto leave; /* Our copy is pretty new (not older than 7 days). */
272 if (verified > now && now - verified < 3*3600)
273 goto leave; /* We downloaded and verified in the last 3 hours. */
276 /* Create the filename of the file with the keys. */
277 keyfile_fname = make_filename_try (gnupg_datadir (), "distsigkey.gpg", NULL);
280 err = gpg_error_from_syserror ();
284 /* Fetch the swdb from the web. */
285 err = fetch_file (ctrl, "https://versions.gnupg.org/swdb.lst", &swdb);
288 err = fetch_file (ctrl, "https://versions.gnupg.org/swdb.lst.sig", &swdb_sig);
293 ccparray_init (&ccp, 0);
294 ccparray_put (&ccp, "--enable-special-filenames");
295 ccparray_put (&ccp, "--status-fd=2");
296 ccparray_put (&ccp, "--keyring");
297 ccparray_put (&ccp, keyfile_fname);
298 ccparray_put (&ccp, "--");
299 ccparray_put (&ccp, "-&@INEXTRA@");
300 ccparray_put (&ccp, "-");
301 ccparray_put (&ccp, NULL);
302 argv = ccparray_get (&ccp, NULL);
305 err = gpg_error_from_syserror ();
310 log_debug ("starting gpgv\n");
311 err = gnupg_exec_tool_stream (gnupg_module_name (GNUPG_MODULE_NAME_GPGV),
312 argv, swdb, swdb_sig, NULL,
313 verify_status_cb, &verify_status_parm);
314 if (!err && verify_status_parm.sigtime == (time_t)(-1))
315 err = gpg_error (verify_status_parm.anyvalid? GPG_ERR_BAD_SIGNATURE
316 /**/ : GPG_ERR_INV_TIME );
318 log_debug ("gpgv finished: err=%d\n", err);
322 /* If our swdb is not older than the downloaded one. We don't
323 * bother to update. */
324 if (!force && filedate >= verify_status_parm.sigtime)
327 /* Create a file name for a temporary file in the home directory.
328 * We will later rename that file to the real name. */
332 #ifdef HAVE_W32_SYSTEM
333 tmpstr = es_bsprintf ("tmp-%u-swdb", (unsigned int)getpid ());
335 tmpstr = es_bsprintf (".#%u.swdb", (unsigned int)getpid ());
339 err = gpg_error_from_syserror ();
342 tmp_fname = make_filename_try (gnupg_homedir (), tmpstr, NULL);
346 err = gpg_error_from_syserror ();
351 outfp = es_fopen (tmp_fname, "w");
354 err = gpg_error_from_syserror ();
355 log_error (_("error creating '%s': %s\n"), tmp_fname, gpg_strerror (err));
359 epoch2isotime (isotime, verify_status_parm.sigtime);
360 es_fprintf (outfp, ".filedate %s\n", isotime);
361 epoch2isotime (isotime, now);
362 es_fprintf (outfp, ".verified %s\n", isotime);
364 if (es_fseek (swdb, 0, SEEK_SET))
366 err = gpg_error_from_syserror ();
370 err = copy_stream (swdb, outfp);
373 /* Well, it might also be a reading error, but that is pretty
374 * unlikely for a memory stream. */
375 log_error (_("error writing '%s': %s\n"), tmp_fname, gpg_strerror (err));
379 if (es_fclose (outfp))
381 err = gpg_error_from_syserror ();
382 log_error (_("error writing '%s': %s\n"), tmp_fname, gpg_strerror (err));
387 err = gnupg_rename_file (tmp_fname, fname, NULL);
397 gnupg_remove (tmp_fname); /* This is a temporary file. */
399 es_fclose (swdb_sig);
401 xfree (keyfile_fname);