Fix regression in gpg's mail address parsing.
[gnupg.git] / kbx / keybox-update.c
1 /* keybox-update.c - keybox update operations
2  *      Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <unistd.h>
27
28 #include "keybox-defs.h"
29 #include "../common/sysutils.h"
30
31 #define EXTSEP_S "."
32
33
34 #if !defined(HAVE_FSEEKO) && !defined(fseeko)
35
36 #ifdef HAVE_LIMITS_H
37 # include <limits.h>
38 #endif
39 #ifndef LONG_MAX
40 # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
41 #endif
42 #ifndef LONG_MIN
43 # define LONG_MIN (-1 - LONG_MAX)
44 #endif
45
46 /****************
47  * A substitute for fseeko, for hosts that don't have it.
48  */
49 static int
50 fseeko (FILE * stream, off_t newpos, int whence)
51 {
52   while (newpos != (long) newpos)
53     {
54       long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
55       if (fseek (stream, pos, whence) != 0)
56         return -1;
57       newpos -= pos;
58       whence = SEEK_CUR;
59     }
60   return fseek (stream, (long) newpos, whence);
61 }
62 #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
63
64
65
66 static int
67 create_tmp_file (const char *template,
68                  char **r_bakfname, char **r_tmpfname, FILE **r_fp)
69 {
70   char *bakfname, *tmpfname;
71
72   *r_bakfname = NULL;
73   *r_tmpfname = NULL;
74
75 # ifdef USE_ONLY_8DOT3
76   /* Here is another Windoze bug?:
77    * you cant rename("pubring.kbx.tmp", "pubring.kbx");
78    * but        rename("pubring.kbx.tmp", "pubring.aaa");
79    * works.  So we replace ".kbx" by ".kb_" or ".k__".  Note that we
80    * can't use ".bak" and ".tmp", because these suffixes are used by
81    * gpg and would lead to a sharing violation or data corruption.
82    */
83   if (strlen (template) > 4
84       && !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
85     {
86       bakfname = xtrymalloc (strlen (template) + 1);
87       if (!bakfname)
88         return gpg_error_from_syserror ();
89       strcpy (bakfname, template);
90       strcpy (bakfname+strlen(template)-4, EXTSEP_S "kb_");
91
92       tmpfname = xtrymalloc (strlen (template) + 1);
93       if (!tmpfname)
94         {
95           gpg_error_t tmperr = gpg_error_from_syserror ();
96           xfree (bakfname);
97           return tmperr;
98         }
99       strcpy (tmpfname,template);
100       strcpy (tmpfname + strlen (template)-4, EXTSEP_S "k__");
101     }
102   else
103     { /* File does not end with kbx, thus we hope we are working on a
104          modern file system and appending a suffix works. */
105       bakfname = xtrymalloc ( strlen (template) + 5);
106       if (!bakfname)
107         return gpg_error_from_syserror ();
108       strcpy (stpcpy (bakfname, template), EXTSEP_S "kb_");
109
110       tmpfname = xtrymalloc ( strlen (template) + 5);
111       if (!tmpfname)
112         {
113           gpg_error_t tmperr = gpg_error_from_syserror ();
114           xfree (bakfname);
115           return tmperr;
116         }
117       strcpy (stpcpy (tmpfname, template), EXTSEP_S "k__");
118     }
119 # else /* Posix file names */
120   bakfname = xtrymalloc (strlen (template) + 2);
121   if (!bakfname)
122     return gpg_error_from_syserror ();
123   strcpy (stpcpy (bakfname,template),"~");
124
125   tmpfname = xtrymalloc ( strlen (template) + 5);
126   if (!tmpfname)
127     {
128       gpg_error_t tmperr = gpg_error_from_syserror ();
129       xfree (bakfname);
130       return tmperr;
131     }
132   strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
133 # endif /* Posix filename */
134
135   *r_fp = fopen (tmpfname, "wb");
136   if (!*r_fp)
137     {
138       gpg_error_t tmperr = gpg_error_from_syserror ();
139       xfree (tmpfname);
140       xfree (bakfname);
141       return tmperr;
142     }
143
144   *r_bakfname = bakfname;
145   *r_tmpfname = tmpfname;
146   return 0;
147 }
148
149
150 static int
151 rename_tmp_file (const char *bakfname, const char *tmpfname,
152                  const char *fname, int secret )
153 {
154   int rc=0;
155
156   /* restrict the permissions for secret keyboxs */
157 #ifndef HAVE_DOSISH_SYSTEM
158 /*    if (secret && !opt.preserve_permissions) */
159 /*      { */
160 /*        if (chmod (tmpfname, S_IRUSR | S_IWUSR) )  */
161 /*          { */
162 /*            log_debug ("chmod of `%s' failed: %s\n", */
163 /*                       tmpfname, strerror(errno) ); */
164 /*            return KEYBOX_Write_File; */
165 /*      } */
166 /*      } */
167 #endif
168
169   /* fixme: invalidate close caches (not used with stdio)*/
170 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ); */
171 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname ); */
172 /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname ); */
173
174   /* First make a backup file except for secret keyboxes. */
175   if (!secret)
176     {
177 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
178       gnupg_remove (bakfname);
179 #endif
180       if (rename (fname, bakfname) )
181         {
182           return gpg_error_from_syserror ();
183         }
184     }
185
186   /* Then rename the file. */
187 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
188   gnupg_remove (fname);
189 #endif
190   if (rename (tmpfname, fname) )
191     {
192       rc = gpg_error_from_syserror ();
193       if (secret)
194         {
195 /*            log_info ("WARNING: 2 files with confidential" */
196 /*                       " information exists.\n"); */
197 /*            log_info ("%s is the unchanged one\n", fname ); */
198 /*            log_info ("%s is the new one\n", tmpfname ); */
199 /*            log_info ("Please fix this possible security flaw\n"); */
200         }
201       return rc;
202     }
203
204   return 0;
205 }
206
207
208
209 /* Perform insert/delete/update operation.
210     mode 1 = insert
211          2 = delete
212          3 = update
213 */
214 static int
215 blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
216                int secret, off_t start_offset)
217 {
218   FILE *fp, *newfp;
219   int rc=0;
220   char *bakfname = NULL;
221   char *tmpfname = NULL;
222   char buffer[4096];
223   int nread, nbytes;
224
225   /* Open the source file. Because we do a rename, we have to check the
226      permissions of the file */
227   if (access (fname, W_OK))
228     return gpg_error_from_syserror ();
229
230   fp = fopen (fname, "rb");
231   if (mode == 1 && !fp && errno == ENOENT)
232     {
233       /* Insert mode but file does not exist:
234          Create a new keybox file. */
235       newfp = fopen (fname, "wb");
236       if (!newfp )
237         return gpg_error_from_syserror ();
238
239       rc = _keybox_write_header_blob (newfp);
240       if (rc)
241         return rc;
242
243       rc = _keybox_write_blob (blob, newfp);
244       if (rc)
245         return rc;
246
247       if ( fclose (newfp) )
248         return gpg_error_from_syserror ();
249
250 /*        if (chmod( fname, S_IRUSR | S_IWUSR )) */
251 /*          { */
252 /*            log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
253 /*            return KEYBOX_File_Error; */
254 /*          } */
255       return 0; /* Ready. */
256     }
257
258   if (!fp)
259     {
260       rc = gpg_error_from_syserror ();
261       goto leave;
262     }
263
264   /* Create the new file. */
265   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
266   if (rc)
267     {
268       fclose(fp);
269       goto leave;
270     }
271
272   /* prepare for insert */
273   if (mode == 1)
274     {
275       /* Copy everything to the new file. */
276       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
277         {
278           if (fwrite (buffer, nread, 1, newfp) != 1)
279             {
280               rc = gpg_error_from_syserror ();
281               goto leave;
282             }
283         }
284       if (ferror (fp))
285         {
286           rc = gpg_error_from_syserror ();
287           goto leave;
288         }
289     }
290
291   /* Prepare for delete or update. */
292   if ( mode == 2 || mode == 3 )
293     {
294       off_t current = 0;
295
296       /* Copy first part to the new file. */
297       while ( current < start_offset )
298         {
299           nbytes = DIM(buffer);
300           if (current + nbytes > start_offset)
301               nbytes = start_offset - current;
302           nread = fread (buffer, 1, nbytes, fp);
303           if (!nread)
304             break;
305           current += nread;
306
307           if (fwrite (buffer, nread, 1, newfp) != 1)
308             {
309               rc = gpg_error_from_syserror ();
310               goto leave;
311             }
312         }
313       if (ferror (fp))
314         {
315           rc = gpg_error_from_syserror ();
316           goto leave;
317         }
318
319       /* Skip this blob. */
320       rc = _keybox_read_blob (NULL, fp);
321       if (rc)
322         return rc;
323     }
324
325   /* Do an insert or update. */
326   if ( mode == 1 || mode == 3 )
327     {
328       rc = _keybox_write_blob (blob, newfp);
329       if (rc)
330           return rc;
331     }
332
333   /* Copy the rest of the packet for an delete or update. */
334   if (mode == 2 || mode == 3)
335     {
336       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
337         {
338           if (fwrite (buffer, nread, 1, newfp) != 1)
339             {
340               rc = gpg_error_from_syserror ();
341               goto leave;
342             }
343         }
344       if (ferror (fp))
345         {
346           rc = gpg_error_from_syserror ();
347           goto leave;
348         }
349     }
350
351   /* Close both files. */
352   if (fclose(fp))
353     {
354       rc = gpg_error_from_syserror ();
355       fclose (newfp);
356       goto leave;
357     }
358   if (fclose(newfp))
359     {
360       rc = gpg_error_from_syserror ();
361       goto leave;
362     }
363
364   rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
365
366  leave:
367   xfree(bakfname);
368   xfree(tmpfname);
369   return rc;
370 }
371
372
373
374 #ifdef KEYBOX_WITH_X509
375 int
376 keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
377                     unsigned char *sha1_digest)
378 {
379   int rc;
380   const char *fname;
381   KEYBOXBLOB blob;
382
383   if (!hd)
384     return gpg_error (GPG_ERR_INV_HANDLE);
385   if (!hd->kb)
386     return gpg_error (GPG_ERR_INV_HANDLE);
387   fname = hd->kb->fname;
388   if (!fname)
389     return gpg_error (GPG_ERR_INV_HANDLE);
390
391   /* Close this one otherwise we will mess up the position for a next
392      search.  Fixme: it would be better to adjust the position after
393      the write operation.  */
394   _keybox_close_file (hd);
395
396   rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
397   if (!rc)
398     {
399       rc = blob_filecopy (1, fname, blob, hd->secret, 0);
400       _keybox_release_blob (blob);
401       /*    if (!rc && !hd->secret && kb_offtbl) */
402       /*      { */
403       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
404       /*      } */
405     }
406   return rc;
407 }
408
409 int
410 keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
411                     unsigned char *sha1_digest)
412 {
413   (void)hd;
414   (void)cert;
415   (void)sha1_digest;
416   return -1;
417 }
418
419
420 #endif /*KEYBOX_WITH_X509*/
421
422 /* Note: We assume that the keybox has been locked before the current
423    search was executed.  This is needed so that we can depend on the
424    offset information of the flags. */
425 int
426 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
427 {
428   off_t off;
429   const char *fname;
430   FILE *fp;
431   gpg_err_code_t ec;
432   size_t flag_pos, flag_size;
433   const unsigned char *buffer;
434   size_t length;
435
436   (void)idx;  /* Not yet used.  */
437
438   if (!hd)
439     return gpg_error (GPG_ERR_INV_VALUE);
440   if (!hd->found.blob)
441     return gpg_error (GPG_ERR_NOTHING_FOUND);
442   if (!hd->kb)
443     return gpg_error (GPG_ERR_INV_HANDLE);
444   if (!hd->found.blob)
445     return gpg_error (GPG_ERR_NOTHING_FOUND);
446   fname = hd->kb->fname;
447   if (!fname)
448     return gpg_error (GPG_ERR_INV_HANDLE);
449
450   off = _keybox_get_blob_fileoffset (hd->found.blob);
451   if (off == (off_t)-1)
452     return gpg_error (GPG_ERR_GENERAL);
453
454   buffer = _keybox_get_blob_image (hd->found.blob, &length);
455   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
456   if (ec)
457     return gpg_error (ec);
458
459   off += flag_pos;
460
461   _keybox_close_file (hd);
462   fp = fopen (hd->kb->fname, "r+b");
463   if (!fp)
464     return gpg_error_from_syserror ();
465
466   ec = 0;
467   if (fseeko (fp, off, SEEK_SET))
468     ec = gpg_error_from_syserror ();
469   else
470     {
471       unsigned char tmp[4];
472
473       tmp[0] = value >> 24;
474       tmp[1] = value >> 16;
475       tmp[2] = value >>  8;
476       tmp[3] = value;
477
478       switch (flag_size)
479         {
480         case 1:
481         case 2:
482         case 4:
483           if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
484             ec = gpg_err_code_from_syserror ();
485           break;
486         default:
487           ec = GPG_ERR_BUG;
488           break;
489         }
490     }
491
492   if (fclose (fp))
493     {
494       if (!ec)
495         ec = gpg_err_code_from_syserror ();
496     }
497
498   return gpg_error (ec);
499 }
500
501
502
503 int
504 keybox_delete (KEYBOX_HANDLE hd)
505 {
506   off_t off;
507   const char *fname;
508   FILE *fp;
509   int rc;
510
511   if (!hd)
512     return gpg_error (GPG_ERR_INV_VALUE);
513   if (!hd->found.blob)
514     return gpg_error (GPG_ERR_NOTHING_FOUND);
515   if (!hd->kb)
516     return gpg_error (GPG_ERR_INV_HANDLE);
517   fname = hd->kb->fname;
518   if (!fname)
519     return gpg_error (GPG_ERR_INV_HANDLE);
520
521   off = _keybox_get_blob_fileoffset (hd->found.blob);
522   if (off == (off_t)-1)
523     return gpg_error (GPG_ERR_GENERAL);
524   off += 4;
525
526   _keybox_close_file (hd);
527   fp = fopen (hd->kb->fname, "r+b");
528   if (!fp)
529     return gpg_error_from_syserror ();
530
531   if (fseeko (fp, off, SEEK_SET))
532     rc = gpg_error_from_syserror ();
533   else if (putc (0, fp) == EOF)
534     rc = gpg_error_from_syserror ();
535   else
536     rc = 0;
537
538   if (fclose (fp))
539     {
540       if (!rc)
541         rc = gpg_error_from_syserror ();
542     }
543
544   return rc;
545 }
546
547
548 /* Compress the keybox file.  This should be run with the file
549    locked. */
550 int
551 keybox_compress (KEYBOX_HANDLE hd)
552 {
553   int read_rc, rc;
554   const char *fname;
555   FILE *fp, *newfp;
556   char *bakfname = NULL;
557   char *tmpfname = NULL;
558   int first_blob;
559   KEYBOXBLOB blob = NULL;
560   u32 cut_time;
561   int any_changes = 0;
562   int skipped_deleted;
563
564   if (!hd)
565     return gpg_error (GPG_ERR_INV_HANDLE);
566   if (!hd->kb)
567     return gpg_error (GPG_ERR_INV_HANDLE);
568   if (hd->secret)
569     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
570   fname = hd->kb->fname;
571   if (!fname)
572     return gpg_error (GPG_ERR_INV_HANDLE);
573
574   _keybox_close_file (hd);
575
576   /* Open the source file. Because we do a rename, we have to check the
577      permissions of the file */
578   if (access (fname, W_OK))
579     return gpg_error_from_syserror ();
580
581   fp = fopen (fname, "rb");
582   if (!fp && errno == ENOENT)
583     return 0; /* Ready. File has been deleted right after the access above. */
584   if (!fp)
585     {
586       rc = gpg_error_from_syserror ();
587       return rc;
588     }
589
590   /* A quick test to see if we need to compress the file at all.  We
591      schedule a compress run after 3 hours. */
592   if ( !_keybox_read_blob (&blob, fp) )
593     {
594       const unsigned char *buffer;
595       size_t length;
596
597       buffer = _keybox_get_blob_image (blob, &length);
598       if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
599         {
600           u32 last_maint = ((buffer[20] << 24) | (buffer[20+1] << 16)
601                             | (buffer[20+2] << 8) | (buffer[20+3]));
602
603           if ( (last_maint + 3*3600) > time (NULL) )
604             {
605               fclose (fp);
606               _keybox_release_blob (blob);
607               return 0; /* Compress run not yet needed. */
608             }
609         }
610       _keybox_release_blob (blob);
611       fseek (fp, 0, SEEK_SET);
612       clearerr (fp);
613     }
614
615   /* Create the new file. */
616   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
617   if (rc)
618     {
619       fclose(fp);
620       return rc;;
621     }
622
623
624   /* Processing loop.  By reading using _keybox_read_blob we
625      automagically skip any blobs flagged as deleted.  Thus what we
626      only have to do is to check all ephemeral flagged blocks whether
627      their time has come and write out all other blobs. */
628   cut_time = time(NULL) - 86400;
629   first_blob = 1;
630   skipped_deleted = 0;
631   for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
632        _keybox_release_blob (blob), blob = NULL )
633     {
634       unsigned int blobflags;
635       const unsigned char *buffer;
636       size_t length, pos, size;
637       u32 created_at;
638
639       if (skipped_deleted)
640         any_changes = 1;
641       buffer = _keybox_get_blob_image (blob, &length);
642       if (first_blob)
643         {
644           first_blob = 0;
645           if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
646             {
647               /* Write out the blob with an updated maintenance time stamp. */
648               _keybox_update_header_blob (blob);
649               rc = _keybox_write_blob (blob, newfp);
650               if (rc)
651                 break;
652               continue;
653             }
654
655           /* The header blob is missing.  Insert it.  */
656           rc = _keybox_write_header_blob (newfp);
657           if (rc)
658             break;
659           any_changes = 1;
660         }
661       else if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
662         {
663           /* Oops: There is another header record - remove it. */
664           any_changes = 1;
665           continue;
666         }
667
668       if (_keybox_get_flag_location (buffer, length,
669                                      KEYBOX_FLAG_BLOB, &pos, &size)
670           || size != 2)
671         {
672           rc = gpg_error (GPG_ERR_BUG);
673           break;
674         }
675       blobflags = ((buffer[pos] << 8) | (buffer[pos+1]));
676       if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
677         {
678           /* This is an ephemeral blob. */
679           if (_keybox_get_flag_location (buffer, length,
680                                          KEYBOX_FLAG_CREATED_AT, &pos, &size)
681               || size != 4)
682             created_at = 0; /* oops. */
683           else
684             created_at = ((buffer[pos] << 24) | (buffer[pos+1] << 16)
685                           | (buffer[pos+2] << 8) | (buffer[pos+3]));
686
687           if (created_at && created_at < cut_time)
688             {
689               any_changes = 1;
690               continue; /* Skip this blob. */
691             }
692         }
693
694       rc = _keybox_write_blob (blob, newfp);
695       if (rc)
696         break;
697     }
698   if (skipped_deleted)
699     any_changes = 1;
700   _keybox_release_blob (blob); blob = NULL;
701   if (!rc && read_rc == -1)
702     rc = 0;
703   else if (!rc)
704     rc = read_rc;
705
706   /* Close both files. */
707   if (fclose(fp) && !rc)
708     rc = gpg_error_from_syserror ();
709   if (fclose(newfp) && !rc)
710     rc = gpg_error_from_syserror ();
711
712   /* Rename or remove the temporary file. */
713   if (rc || !any_changes)
714     gnupg_remove (tmpfname);
715   else
716     rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
717
718   xfree(bakfname);
719   xfree(tmpfname);
720   return rc;
721 }