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