Changed to GPLv3.
[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 keyboxs */
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 opertions.  */
390   if (hd->fp)
391     {
392       fclose (hd->fp);
393       hd->fp = NULL;
394     }
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, 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   return -1;
414 }
415
416
417 #endif /*KEYBOX_WITH_X509*/
418
419 /* Note: We assume that the keybox has been locked before the current
420    search was executed.  This is needed so that we can depend on the
421    offset information of the flags. */
422 int
423 keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
424 {
425   off_t off;
426   const char *fname;
427   FILE *fp;
428   gpg_err_code_t ec;
429   size_t flag_pos, flag_size;
430   const unsigned char *buffer;
431   size_t length;
432
433   if (!hd)
434     return gpg_error (GPG_ERR_INV_VALUE);
435   if (!hd->found.blob)
436     return gpg_error (GPG_ERR_NOTHING_FOUND);
437   if (!hd->kb)
438     return gpg_error (GPG_ERR_INV_HANDLE); 
439   if (!hd->found.blob)
440     return gpg_error (GPG_ERR_NOTHING_FOUND);
441   fname = hd->kb->fname;
442   if (!fname)
443     return gpg_error (GPG_ERR_INV_HANDLE); 
444
445   off = _keybox_get_blob_fileoffset (hd->found.blob);
446   if (off == (off_t)-1)
447     return gpg_error (GPG_ERR_GENERAL);
448
449   buffer = _keybox_get_blob_image (hd->found.blob, &length);
450   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
451   if (ec)
452     return gpg_error (ec);
453   
454   off += flag_pos;
455
456   if (hd->fp)
457     {
458       fclose (hd->fp);
459       hd->fp = NULL;
460     }
461   fp = fopen (hd->kb->fname, "r+b");
462   if (!fp)
463     return gpg_error (gpg_err_code_from_errno (errno));
464
465   ec = 0;
466   if (fseeko (fp, off, SEEK_SET))
467     ec = gpg_error (gpg_err_code_from_errno (errno));
468   else
469     {
470       unsigned char tmp[4];
471
472       tmp[0] = value >> 24;
473       tmp[1] = value >> 16;
474       tmp[2] = value >>  8;
475       tmp[3] = value;
476
477       switch (flag_size)
478         {
479         case 1: 
480         case 2:
481         case 4:
482           if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
483             ec = gpg_err_code_from_errno (errno);
484           break;
485         default:
486           ec = GPG_ERR_BUG;
487           break;
488         }
489     }
490
491   if (fclose (fp))
492     {
493       if (!ec)
494         ec = gpg_err_code_from_errno (errno);
495     }
496
497   return gpg_error (ec);
498 }
499
500
501
502 int
503 keybox_delete (KEYBOX_HANDLE hd)
504 {
505   off_t off;
506   const char *fname;
507   FILE *fp;
508   int rc;
509
510   if (!hd)
511     return gpg_error (GPG_ERR_INV_VALUE);
512   if (!hd->found.blob)
513     return gpg_error (GPG_ERR_NOTHING_FOUND);
514   if (!hd->kb)
515     return gpg_error (GPG_ERR_INV_HANDLE); 
516   fname = hd->kb->fname;
517   if (!fname)
518     return gpg_error (GPG_ERR_INV_HANDLE); 
519
520   off = _keybox_get_blob_fileoffset (hd->found.blob);
521   if (off == (off_t)-1)
522     return gpg_error (GPG_ERR_GENERAL);
523   off += 4;
524
525   if (hd->fp)
526     {
527       fclose (hd->fp);
528       hd->fp = NULL;
529     }
530   
531   fp = fopen (hd->kb->fname, "r+b");
532   if (!fp)
533     return gpg_error (gpg_err_code_from_errno (errno));
534
535   if (fseeko (fp, off, SEEK_SET))
536     rc = gpg_error (gpg_err_code_from_errno (errno));
537   else if (putc (0, fp) == EOF)
538     rc = gpg_error (gpg_err_code_from_errno (errno));
539   else
540     rc = 0;
541
542   if (fclose (fp))
543     {
544       if (!rc)
545         rc = gpg_error (gpg_err_code_from_errno (errno));
546     }
547
548   return rc;
549 }
550
551
552 /* Compress the keybox file.  This should be run with the file
553    locked. */
554 int
555 keybox_compress (KEYBOX_HANDLE hd)
556 {
557   int read_rc, rc;
558   const char *fname;
559   FILE *fp, *newfp;
560   char *bakfname = NULL;
561   char *tmpfname = NULL;
562   int first_blob;
563   KEYBOXBLOB blob = NULL;
564   u32 cut_time;
565   int any_changes = 0;
566   int skipped_deleted;
567
568   if (!hd)
569     return gpg_error (GPG_ERR_INV_HANDLE); 
570   if (!hd->kb)
571     return gpg_error (GPG_ERR_INV_HANDLE); 
572   if (hd->secret)
573     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
574   fname = hd->kb->fname;
575   if (!fname)
576     return gpg_error (GPG_ERR_INV_HANDLE); 
577
578   if (hd->fp)
579     {
580       fclose (hd->fp);
581       hd->fp = NULL;
582     }
583
584   /* Open the source file. Because we do a rename, we have to check the 
585      permissions of the file */
586   if (access (fname, W_OK))
587     return gpg_error (gpg_err_code_from_errno (errno));
588
589   fp = fopen (fname, "rb");
590   if (!fp && errno == ENOENT)
591     return 0; /* Ready. File has been deleted right after the access above. */
592   if (!fp)
593     {
594       rc = gpg_error (gpg_err_code_from_errno (errno));
595       return rc;
596     }
597
598   /* A quick test to see if we need to compress the file at all.  We
599      schedule a compress run after 3 hours. */
600   if ( !_keybox_read_blob (&blob, fp) )
601     {
602       const unsigned char *buffer;
603       size_t length;
604
605       buffer = _keybox_get_blob_image (blob, &length);
606       if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
607         {
608           u32 last_maint = ((buffer[20] << 24) | (buffer[20+1] << 16)
609                             | (buffer[20+2] << 8) | (buffer[20+3]));
610           
611           if ( (last_maint + 3*3600) > time (NULL) )
612             {
613               fclose (fp);
614               _keybox_release_blob (blob);
615               return 0; /* Compress run not yet needed. */
616             }
617         }
618       _keybox_release_blob (blob);
619       rewind (fp);
620     }
621
622   /* Create the new file. */
623   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
624   if (rc)
625     {
626       fclose(fp);
627       return rc;;
628     }
629
630   
631   /* Processing loop.  By reading using _keybox_read_blob we
632      automagically skip any blobs flagged as deleted.  Thus what we
633      only have to do is to check all ephemeral flagged blocks whether
634      their time has come and write out all other blobs. */
635   cut_time = time(NULL) - 86400;
636   first_blob = 1;
637   skipped_deleted = 0;
638   for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
639        _keybox_release_blob (blob), blob = NULL )
640     {
641       unsigned int blobflags;
642       const unsigned char *buffer;
643       size_t length, pos, size;
644       u32 created_at;
645
646       if (skipped_deleted)
647         any_changes = 1;
648       buffer = _keybox_get_blob_image (blob, &length);
649       if (first_blob)
650         {
651           first_blob = 0;
652           if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
653             {
654               /* Write out the blob with an updated maintenance time stamp. */
655               _keybox_update_header_blob (blob);
656               rc = _keybox_write_blob (blob, newfp);
657               if (rc)
658                 break;
659               continue;
660             }
661
662           /* The header blob is missing.  Insert it.  */
663           rc = _keybox_write_header_blob (newfp);
664           if (rc)
665             break;
666           any_changes = 1;
667         }
668       else if (length > 4 && buffer[4] == BLOBTYPE_HEADER)
669         {
670           /* Oops: There is another header record - remove it. */
671           any_changes = 1;
672           continue;
673         }
674
675       if (_keybox_get_flag_location (buffer, length, 
676                                      KEYBOX_FLAG_BLOB, &pos, &size)
677           || size != 2)
678         {
679           rc = gpg_error (GPG_ERR_BUG);
680           break;
681         }
682       blobflags = ((buffer[pos] << 8) | (buffer[pos+1]));
683       if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
684         {
685           /* This is an ephemeral blob. */
686           if (_keybox_get_flag_location (buffer, length, 
687                                          KEYBOX_FLAG_CREATED_AT, &pos, &size)
688               || size != 4)
689             created_at = 0; /* oops. */
690           else
691             created_at = ((buffer[pos] << 24) | (buffer[pos+1] << 16)
692                           | (buffer[pos+2] << 8) | (buffer[pos+3]));
693
694           if (created_at && created_at < cut_time)
695             {
696               any_changes = 1;
697               continue; /* Skip this blob. */
698             }
699         }
700
701       rc = _keybox_write_blob (blob, newfp);
702       if (rc)
703         break;
704     }
705   if (skipped_deleted)
706     any_changes = 1;
707   _keybox_release_blob (blob); blob = NULL;
708   if (!rc && read_rc == -1)
709     rc = 0;
710   else if (!rc)
711     rc = read_rc;
712
713   /* Close both files. */
714   if (fclose(fp) && !rc)
715     rc = gpg_error (gpg_err_code_from_errno (errno));
716   if (fclose(newfp) && !rc)
717     rc = gpg_error (gpg_err_code_from_errno (errno));
718
719   /* Rename or remove the temporary file. */
720   if (rc || !any_changes)
721     remove (tmpfname);
722   else
723     rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
724
725   xfree(bakfname);
726   xfree(tmpfname);
727   return rc;
728 }
729