LCOV - code coverage report
Current view: top level - kbx - keybox-update.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 185 353 52.4 %
Date: 2015-11-05 17:10:59 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /* keybox-update.c - keybox update operations
       2             :  * Copyright (C) 2001, 2003, 2004, 2012 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             : #include <assert.h>
      28             : 
      29             : #include "keybox-defs.h"
      30             : #include "../common/sysutils.h"
      31             : #include "../common/host2net.h"
      32             : 
      33             : #define EXTSEP_S "."
      34             : 
      35             : #define FILECOPY_INSERT 1
      36             : #define FILECOPY_DELETE 2
      37             : #define FILECOPY_UPDATE 3
      38             : 
      39             : 
      40             : #if !defined(HAVE_FSEEKO) && !defined(fseeko)
      41             : 
      42             : #ifdef HAVE_LIMITS_H
      43             : # include <limits.h>
      44             : #endif
      45             : #ifndef LONG_MAX
      46             : # define LONG_MAX ((long) ((unsigned long) -1 >> 1))
      47             : #endif
      48             : #ifndef LONG_MIN
      49             : # define LONG_MIN (-1 - LONG_MAX)
      50             : #endif
      51             : 
      52             : /****************
      53             :  * A substitute for fseeko, for hosts that don't have it.
      54             :  */
      55             : static int
      56             : fseeko (FILE * stream, off_t newpos, int whence)
      57             : {
      58             :   while (newpos != (long) newpos)
      59             :     {
      60             :       long pos = newpos < 0 ? LONG_MIN : LONG_MAX;
      61             :       if (fseek (stream, pos, whence) != 0)
      62             :         return -1;
      63             :       newpos -= pos;
      64             :       whence = SEEK_CUR;
      65             :     }
      66             :   return fseek (stream, (long) newpos, whence);
      67             : }
      68             : #endif /* !defined(HAVE_FSEEKO) && !defined(fseeko) */
      69             : 
      70             : 
      71             : 
      72             : static int
      73          66 : create_tmp_file (const char *template,
      74             :                  char **r_bakfname, char **r_tmpfname, FILE **r_fp)
      75             : {
      76             :   char *bakfname, *tmpfname;
      77             : 
      78          66 :   *r_bakfname = NULL;
      79          66 :   *r_tmpfname = NULL;
      80             : 
      81             : # ifdef USE_ONLY_8DOT3
      82             :   /* Here is another Windoze bug?:
      83             :    * you cant rename("pubring.kbx.tmp", "pubring.kbx");
      84             :    * but        rename("pubring.kbx.tmp", "pubring.aaa");
      85             :    * works.  So we replace ".kbx" by ".kb_" or ".k__".  Note that we
      86             :    * can't use ".bak" and ".tmp", because these suffixes are used by
      87             :    * gpg and would lead to a sharing violation or data corruption.
      88             :    */
      89             :   if (strlen (template) > 4
      90             :       && !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
      91             :     {
      92             :       bakfname = xtrymalloc (strlen (template) + 1);
      93             :       if (!bakfname)
      94             :         return gpg_error_from_syserror ();
      95             :       strcpy (bakfname, template);
      96             :       strcpy (bakfname+strlen(template)-4, EXTSEP_S "kb_");
      97             : 
      98             :       tmpfname = xtrymalloc (strlen (template) + 1);
      99             :       if (!tmpfname)
     100             :         {
     101             :           gpg_error_t tmperr = gpg_error_from_syserror ();
     102             :           xfree (bakfname);
     103             :           return tmperr;
     104             :         }
     105             :       strcpy (tmpfname,template);
     106             :       strcpy (tmpfname + strlen (template)-4, EXTSEP_S "k__");
     107             :     }
     108             :   else
     109             :     { /* File does not end with kbx, thus we hope we are working on a
     110             :          modern file system and appending a suffix works. */
     111             :       bakfname = xtrymalloc ( strlen (template) + 5);
     112             :       if (!bakfname)
     113             :         return gpg_error_from_syserror ();
     114             :       strcpy (stpcpy (bakfname, template), EXTSEP_S "kb_");
     115             : 
     116             :       tmpfname = xtrymalloc ( strlen (template) + 5);
     117             :       if (!tmpfname)
     118             :         {
     119             :           gpg_error_t tmperr = gpg_error_from_syserror ();
     120             :           xfree (bakfname);
     121             :           return tmperr;
     122             :         }
     123             :       strcpy (stpcpy (tmpfname, template), EXTSEP_S "k__");
     124             :     }
     125             : # else /* Posix file names */
     126          66 :   bakfname = xtrymalloc (strlen (template) + 2);
     127          66 :   if (!bakfname)
     128           0 :     return gpg_error_from_syserror ();
     129          66 :   strcpy (stpcpy (bakfname,template),"~");
     130             : 
     131          66 :   tmpfname = xtrymalloc ( strlen (template) + 5);
     132          66 :   if (!tmpfname)
     133             :     {
     134           0 :       gpg_error_t tmperr = gpg_error_from_syserror ();
     135           0 :       xfree (bakfname);
     136           0 :       return tmperr;
     137             :     }
     138          66 :   strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
     139             : # endif /* Posix filename */
     140             : 
     141          66 :   *r_fp = fopen (tmpfname, "wb");
     142          66 :   if (!*r_fp)
     143             :     {
     144           0 :       gpg_error_t tmperr = gpg_error_from_syserror ();
     145           0 :       xfree (tmpfname);
     146           0 :       xfree (bakfname);
     147           0 :       return tmperr;
     148             :     }
     149             : 
     150          66 :   *r_bakfname = bakfname;
     151          66 :   *r_tmpfname = tmpfname;
     152          66 :   return 0;
     153             : }
     154             : 
     155             : 
     156             : static int
     157          65 : rename_tmp_file (const char *bakfname, const char *tmpfname,
     158             :                  const char *fname, int secret )
     159             : {
     160          65 :   int rc=0;
     161             : 
     162             :   /* restrict the permissions for secret keyboxs */
     163             : #ifndef HAVE_DOSISH_SYSTEM
     164             : /*    if (secret && !opt.preserve_permissions) */
     165             : /*      { */
     166             : /*        if (chmod (tmpfname, S_IRUSR | S_IWUSR) )  */
     167             : /*          { */
     168             : /*            log_debug ("chmod of '%s' failed: %s\n", */
     169             : /*                       tmpfname, strerror(errno) ); */
     170             : /*            return KEYBOX_Write_File; */
     171             : /*      } */
     172             : /*      } */
     173             : #endif
     174             : 
     175             :   /* fixme: invalidate close caches (not used with stdio)*/
     176             : /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ); */
     177             : /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname ); */
     178             : /*    iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname ); */
     179             : 
     180             :   /* First make a backup file except for secret keyboxes. */
     181          65 :   if (!secret)
     182             :     {
     183             : #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
     184             :       gnupg_remove (bakfname);
     185             : #endif
     186          65 :       if (rename (fname, bakfname) )
     187             :         {
     188           0 :           return gpg_error_from_syserror ();
     189             :         }
     190             :     }
     191             : 
     192             :   /* Then rename the file. */
     193             : #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
     194             :   gnupg_remove (fname);
     195             : #endif
     196          65 :   if (rename (tmpfname, fname) )
     197             :     {
     198           0 :       rc = gpg_error_from_syserror ();
     199             :       if (secret)
     200             :         {
     201             : /*            log_info ("WARNING: 2 files with confidential" */
     202             : /*                       " information exists.\n"); */
     203             : /*            log_info ("%s is the unchanged one\n", fname ); */
     204             : /*            log_info ("%s is the new one\n", tmpfname ); */
     205             : /*            log_info ("Please fix this possible security flaw\n"); */
     206             :         }
     207           0 :       return rc;
     208             :     }
     209             : 
     210          65 :   return 0;
     211             : }
     212             : 
     213             : 
     214             : 
     215             : /* Perform insert/delete/update operation.  MODE is one of
     216             :    FILECOPY_INSERT, FILECOPY_DELETE, FILECOPY_UPDATE.  FOR_OPENPGP
     217             :    indicates that this is called due to an OpenPGP keyblock change.  */
     218             : static int
     219          64 : blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
     220             :                int secret, int for_openpgp, off_t start_offset)
     221             : {
     222             :   FILE *fp, *newfp;
     223          64 :   int rc=0;
     224          64 :   char *bakfname = NULL;
     225          64 :   char *tmpfname = NULL;
     226             :   char buffer[4096];  /* (Must be at least 32 bytes) */
     227             :   int nread, nbytes;
     228             : 
     229             :   /* Open the source file. Because we do a rename, we have to check the
     230             :      permissions of the file */
     231          64 :   if (access (fname, W_OK))
     232           0 :     return gpg_error_from_syserror ();
     233             : 
     234          64 :   fp = fopen (fname, "rb");
     235          64 :   if (mode == FILECOPY_INSERT && !fp && errno == ENOENT)
     236             :     {
     237             :       /* Insert mode but file does not exist:
     238             :          Create a new keybox file. */
     239           0 :       newfp = fopen (fname, "wb");
     240           0 :       if (!newfp )
     241           0 :         return gpg_error_from_syserror ();
     242             : 
     243           0 :       rc = _keybox_write_header_blob (newfp, for_openpgp);
     244           0 :       if (rc)
     245             :         {
     246           0 :           fclose (newfp);
     247           0 :           return rc;
     248             :         }
     249             : 
     250           0 :       rc = _keybox_write_blob (blob, newfp);
     251           0 :       if (rc)
     252             :         {
     253           0 :           fclose (newfp);
     254           0 :           return rc;
     255             :         }
     256             : 
     257           0 :       if ( fclose (newfp) )
     258           0 :         return gpg_error_from_syserror ();
     259             : 
     260             : /*        if (chmod( fname, S_IRUSR | S_IWUSR )) */
     261             : /*          { */
     262             : /*            log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
     263             : /*            return KEYBOX_File_Error; */
     264             : /*          } */
     265           0 :       return 0; /* Ready. */
     266             :     }
     267             : 
     268          64 :   if (!fp)
     269             :     {
     270           0 :       rc = gpg_error_from_syserror ();
     271           0 :       goto leave;
     272             :     }
     273             : 
     274             :   /* Create the new file. */
     275          64 :   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
     276          64 :   if (rc)
     277             :     {
     278           0 :       fclose (fp);
     279           0 :       fclose (newfp);
     280           0 :       goto leave;
     281             :     }
     282             : 
     283             :   /* prepare for insert */
     284          64 :   if (mode == FILECOPY_INSERT)
     285             :     {
     286          62 :       int first_record = 1;
     287             : 
     288             :       /* Copy everything to the new file.  If this is for OpenPGP, we
     289             :          make sure that the openpgp flag is set in the header.  (We
     290             :          failsafe the blob type.) */
     291         659 :       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
     292             :         {
     293         535 :           if (first_record && for_openpgp
     294          59 :               && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
     295             :             {
     296          59 :               first_record = 0;
     297          59 :               buffer[7] |= 0x02; /* OpenPGP data may be available.  */
     298             :             }
     299             : 
     300         535 :           if (fwrite (buffer, nread, 1, newfp) != 1)
     301             :             {
     302           0 :               rc = gpg_error_from_syserror ();
     303           0 :               fclose (fp);
     304           0 :               fclose (newfp);
     305           0 :               goto leave;
     306             :             }
     307             :         }
     308          62 :       if (ferror (fp))
     309             :         {
     310           0 :           rc = gpg_error_from_syserror ();
     311           0 :           fclose (fp);
     312           0 :           fclose (newfp);
     313           0 :           goto leave;
     314             :         }
     315             :     }
     316             : 
     317             :   /* Prepare for delete or update. */
     318          64 :   if ( mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE )
     319             :     {
     320           2 :       off_t current = 0;
     321             : 
     322             :       /* Copy first part to the new file. */
     323          23 :       while ( current < start_offset )
     324             :         {
     325          19 :           nbytes = DIM(buffer);
     326          19 :           if (current + nbytes > start_offset)
     327           2 :               nbytes = start_offset - current;
     328          19 :           nread = fread (buffer, 1, nbytes, fp);
     329          19 :           if (!nread)
     330           0 :             break;
     331          19 :           current += nread;
     332             : 
     333          19 :           if (fwrite (buffer, nread, 1, newfp) != 1)
     334             :             {
     335           0 :               rc = gpg_error_from_syserror ();
     336           0 :               fclose (fp);
     337           0 :               fclose (newfp);
     338           0 :               goto leave;
     339             :             }
     340             :         }
     341           2 :       if (ferror (fp))
     342             :         {
     343           0 :           rc = gpg_error_from_syserror ();
     344           0 :           fclose (fp);
     345           0 :           fclose (newfp);
     346           0 :           goto leave;
     347             :         }
     348             : 
     349             :       /* Skip this blob. */
     350           2 :       rc = _keybox_read_blob (NULL, fp);
     351           2 :       if (rc)
     352             :         {
     353           0 :           fclose (fp);
     354           0 :           fclose (newfp);
     355           0 :           return rc;
     356             :         }
     357             :     }
     358             : 
     359             :   /* Do an insert or update. */
     360          64 :   if ( mode == FILECOPY_INSERT || mode == FILECOPY_UPDATE )
     361             :     {
     362          64 :       rc = _keybox_write_blob (blob, newfp);
     363          64 :       if (rc)
     364             :         {
     365           0 :           fclose (fp);
     366           0 :           fclose (newfp);
     367           0 :           return rc;
     368             :         }
     369             :     }
     370             : 
     371             :   /* Copy the rest of the packet for an delete or update. */
     372          64 :   if (mode == FILECOPY_DELETE || mode == FILECOPY_UPDATE)
     373             :     {
     374          17 :       while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
     375             :         {
     376          13 :           if (fwrite (buffer, nread, 1, newfp) != 1)
     377             :             {
     378           0 :               rc = gpg_error_from_syserror ();
     379           0 :               fclose (fp);
     380           0 :               fclose (newfp);
     381           0 :               goto leave;
     382             :             }
     383             :         }
     384           2 :       if (ferror (fp))
     385             :         {
     386           0 :           rc = gpg_error_from_syserror ();
     387           0 :           fclose (fp);
     388           0 :           fclose (newfp);
     389           0 :           goto leave;
     390             :         }
     391             :     }
     392             : 
     393             :   /* Close both files. */
     394          64 :   if (fclose(fp))
     395             :     {
     396           0 :       rc = gpg_error_from_syserror ();
     397           0 :       fclose (newfp);
     398           0 :       goto leave;
     399             :     }
     400          64 :   if (fclose(newfp))
     401             :     {
     402           0 :       rc = gpg_error_from_syserror ();
     403           0 :       goto leave;
     404             :     }
     405             : 
     406          64 :   rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
     407             : 
     408             :  leave:
     409          64 :   xfree(bakfname);
     410          64 :   xfree(tmpfname);
     411          64 :   return rc;
     412             : }
     413             : 
     414             : 
     415             : /* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD.  SIGSTATUS is
     416             :    a vector describing the status of the signatures; its first element
     417             :    gives the number of following elements.  */
     418             : gpg_error_t
     419          59 : keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
     420             :                         u32 *sigstatus)
     421             : {
     422             :   gpg_error_t err;
     423             :   const char *fname;
     424             :   KEYBOXBLOB blob;
     425             :   size_t nparsed;
     426             :   struct _keybox_openpgp_info info;
     427             : 
     428          59 :   if (!hd)
     429           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     430          59 :   if (!hd->kb)
     431           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     432          59 :   fname = hd->kb->fname;
     433          59 :   if (!fname)
     434           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     435             : 
     436             : 
     437             :   /* Close this one otherwise we will mess up the position for a next
     438             :      search.  Fixme: it would be better to adjust the position after
     439             :      the write operation.  */
     440          59 :   _keybox_close_file (hd);
     441             : 
     442          59 :   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
     443          59 :   if (err)
     444           0 :     return err;
     445          59 :   assert (nparsed <= imagelen);
     446          59 :   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
     447             :                                      sigstatus, hd->ephemeral);
     448          59 :   _keybox_destroy_openpgp_info (&info);
     449          59 :   if (!err)
     450             :     {
     451          59 :       err = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 1, 0);
     452          59 :       _keybox_release_blob (blob);
     453             :       /*    if (!rc && !hd->secret && kb_offtbl) */
     454             :       /*      { */
     455             :       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
     456             :       /*      } */
     457             :     }
     458          59 :   return err;
     459             : }
     460             : 
     461             : 
     462             : /* Update the current key at HD with the given OpenPGP keyblock in
     463             :    {IMAGE,IMAGELEN}.  */
     464             : gpg_error_t
     465           2 : keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
     466             : {
     467             :   gpg_error_t err;
     468             :   const char *fname;
     469             :   off_t off;
     470             :   KEYBOXBLOB blob;
     471             :   size_t nparsed;
     472             :   struct _keybox_openpgp_info info;
     473             : 
     474           2 :   if (!hd || !image || !imagelen)
     475           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     476           2 :   if (!hd->found.blob)
     477           0 :     return gpg_error (GPG_ERR_NOTHING_FOUND);
     478           2 :   if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
     479           0 :     return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
     480           2 :   fname = hd->kb->fname;
     481           2 :   if (!fname)
     482           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     483             : 
     484           2 :   off = _keybox_get_blob_fileoffset (hd->found.blob);
     485           2 :   if (off == (off_t)-1)
     486           0 :     return gpg_error (GPG_ERR_GENERAL);
     487             : 
     488             :   /* Close this the file so that we do no mess up the position for a
     489             :      next search.  */
     490           2 :   _keybox_close_file (hd);
     491             : 
     492             :   /* Build a new blob.  */
     493           2 :   err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
     494           2 :   if (err)
     495           0 :     return err;
     496           2 :   assert (nparsed <= imagelen);
     497           2 :   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
     498             :                                      NULL, hd->ephemeral);
     499           2 :   _keybox_destroy_openpgp_info (&info);
     500             : 
     501             :   /* Update the keyblock.  */
     502           2 :   if (!err)
     503             :     {
     504           2 :       err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, 1, off);
     505           2 :       _keybox_release_blob (blob);
     506             :     }
     507           2 :   return err;
     508             : }
     509             : 
     510             : 
     511             : 
     512             : #ifdef KEYBOX_WITH_X509
     513             : int
     514           3 : keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
     515             :                     unsigned char *sha1_digest)
     516             : {
     517             :   int rc;
     518             :   const char *fname;
     519             :   KEYBOXBLOB blob;
     520             : 
     521           3 :   if (!hd)
     522           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     523           3 :   if (!hd->kb)
     524           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     525           3 :   fname = hd->kb->fname;
     526           3 :   if (!fname)
     527           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     528             : 
     529             :   /* Close this one otherwise we will mess up the position for a next
     530             :      search.  Fixme: it would be better to adjust the position after
     531             :      the write operation.  */
     532           3 :   _keybox_close_file (hd);
     533             : 
     534           3 :   rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
     535           3 :   if (!rc)
     536             :     {
     537           3 :       rc = blob_filecopy (FILECOPY_INSERT, fname, blob, hd->secret, 0, 0);
     538           3 :       _keybox_release_blob (blob);
     539             :       /*    if (!rc && !hd->secret && kb_offtbl) */
     540             :       /*      { */
     541             :       /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
     542             :       /*      } */
     543             :     }
     544           3 :   return rc;
     545             : }
     546             : 
     547             : int
     548           0 : keybox_update_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
     549             :                     unsigned char *sha1_digest)
     550             : {
     551             :   (void)hd;
     552             :   (void)cert;
     553             :   (void)sha1_digest;
     554           0 :   return -1;
     555             : }
     556             : 
     557             : 
     558             : #endif /*KEYBOX_WITH_X509*/
     559             : 
     560             : /* Note: We assume that the keybox has been locked before the current
     561             :    search was executed.  This is needed so that we can depend on the
     562             :    offset information of the flags. */
     563             : int
     564           0 : keybox_set_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int value)
     565             : {
     566             :   off_t off;
     567             :   const char *fname;
     568             :   FILE *fp;
     569             :   gpg_err_code_t ec;
     570             :   size_t flag_pos, flag_size;
     571             :   const unsigned char *buffer;
     572             :   size_t length;
     573             : 
     574             :   (void)idx;  /* Not yet used.  */
     575             : 
     576           0 :   if (!hd)
     577           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     578           0 :   if (!hd->found.blob)
     579           0 :     return gpg_error (GPG_ERR_NOTHING_FOUND);
     580           0 :   if (!hd->kb)
     581           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     582           0 :   if (!hd->found.blob)
     583           0 :     return gpg_error (GPG_ERR_NOTHING_FOUND);
     584           0 :   fname = hd->kb->fname;
     585           0 :   if (!fname)
     586           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     587             : 
     588           0 :   off = _keybox_get_blob_fileoffset (hd->found.blob);
     589           0 :   if (off == (off_t)-1)
     590           0 :     return gpg_error (GPG_ERR_GENERAL);
     591             : 
     592           0 :   buffer = _keybox_get_blob_image (hd->found.blob, &length);
     593           0 :   ec = _keybox_get_flag_location (buffer, length, what, &flag_pos, &flag_size);
     594           0 :   if (ec)
     595           0 :     return gpg_error (ec);
     596             : 
     597           0 :   off += flag_pos;
     598             : 
     599           0 :   _keybox_close_file (hd);
     600           0 :   fp = fopen (hd->kb->fname, "r+b");
     601           0 :   if (!fp)
     602           0 :     return gpg_error_from_syserror ();
     603             : 
     604           0 :   ec = 0;
     605           0 :   if (fseeko (fp, off, SEEK_SET))
     606           0 :     ec = gpg_err_code_from_syserror ();
     607             :   else
     608             :     {
     609             :       unsigned char tmp[4];
     610             : 
     611           0 :       tmp[0] = value >> 24;
     612           0 :       tmp[1] = value >> 16;
     613           0 :       tmp[2] = value >>  8;
     614           0 :       tmp[3] = value;
     615             : 
     616           0 :       switch (flag_size)
     617             :         {
     618             :         case 1:
     619             :         case 2:
     620             :         case 4:
     621           0 :           if (fwrite (tmp+4-flag_size, flag_size, 1, fp) != 1)
     622           0 :             ec = gpg_err_code_from_syserror ();
     623           0 :           break;
     624             :         default:
     625           0 :           ec = GPG_ERR_BUG;
     626           0 :           break;
     627             :         }
     628             :     }
     629             : 
     630           0 :   if (fclose (fp))
     631             :     {
     632           0 :       if (!ec)
     633           0 :         ec = gpg_err_code_from_syserror ();
     634             :     }
     635             : 
     636           0 :   return gpg_error (ec);
     637             : }
     638             : 
     639             : 
     640             : 
     641             : int
     642           3 : keybox_delete (KEYBOX_HANDLE hd)
     643             : {
     644             :   off_t off;
     645             :   const char *fname;
     646             :   FILE *fp;
     647             :   int rc;
     648             : 
     649           3 :   if (!hd)
     650           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     651           3 :   if (!hd->found.blob)
     652           0 :     return gpg_error (GPG_ERR_NOTHING_FOUND);
     653           3 :   if (!hd->kb)
     654           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     655           3 :   fname = hd->kb->fname;
     656           3 :   if (!fname)
     657           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     658             : 
     659           3 :   off = _keybox_get_blob_fileoffset (hd->found.blob);
     660           3 :   if (off == (off_t)-1)
     661           0 :     return gpg_error (GPG_ERR_GENERAL);
     662           3 :   off += 4;
     663             : 
     664           3 :   _keybox_close_file (hd);
     665           3 :   fp = fopen (hd->kb->fname, "r+b");
     666           3 :   if (!fp)
     667           0 :     return gpg_error_from_syserror ();
     668             : 
     669           3 :   if (fseeko (fp, off, SEEK_SET))
     670           0 :     rc = gpg_error_from_syserror ();
     671           3 :   else if (putc (0, fp) == EOF)
     672           0 :     rc = gpg_error_from_syserror ();
     673             :   else
     674           3 :     rc = 0;
     675             : 
     676           3 :   if (fclose (fp))
     677             :     {
     678           0 :       if (!rc)
     679           0 :         rc = gpg_error_from_syserror ();
     680             :     }
     681             : 
     682           3 :   return rc;
     683             : }
     684             : 
     685             : 
     686             : /* Compress the keybox file.  This should be run with the file
     687             :    locked. */
     688             : int
     689           3 : keybox_compress (KEYBOX_HANDLE hd)
     690             : {
     691             :   int read_rc, rc;
     692             :   const char *fname;
     693             :   FILE *fp, *newfp;
     694           3 :   char *bakfname = NULL;
     695           3 :   char *tmpfname = NULL;
     696             :   int first_blob;
     697           3 :   KEYBOXBLOB blob = NULL;
     698             :   u32 cut_time;
     699           3 :   int any_changes = 0;
     700             :   int skipped_deleted;
     701             : 
     702           3 :   if (!hd)
     703           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     704           3 :   if (!hd->kb)
     705           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     706           3 :   if (hd->secret)
     707           0 :     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     708           3 :   fname = hd->kb->fname;
     709           3 :   if (!fname)
     710           0 :     return gpg_error (GPG_ERR_INV_HANDLE);
     711             : 
     712           3 :   _keybox_close_file (hd);
     713             : 
     714             :   /* Open the source file. Because we do a rename, we have to check the
     715             :      permissions of the file */
     716           3 :   if (access (fname, W_OK))
     717           0 :     return gpg_error_from_syserror ();
     718             : 
     719           3 :   fp = fopen (fname, "rb");
     720           3 :   if (!fp && errno == ENOENT)
     721           0 :     return 0; /* Ready. File has been deleted right after the access above. */
     722           3 :   if (!fp)
     723             :     {
     724           0 :       rc = gpg_error_from_syserror ();
     725           0 :       return rc;
     726             :     }
     727             : 
     728             :   /* A quick test to see if we need to compress the file at all.  We
     729             :      schedule a compress run after 3 hours. */
     730           3 :   if ( !_keybox_read_blob (&blob, fp) )
     731             :     {
     732             :       const unsigned char *buffer;
     733             :       size_t length;
     734             : 
     735           2 :       buffer = _keybox_get_blob_image (blob, &length);
     736           2 :       if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
     737             :         {
     738           1 :           u32 last_maint = buf32_to_u32 (buffer+20);
     739             : 
     740           1 :           if ( (last_maint + 3*3600) > time (NULL) )
     741             :             {
     742           1 :               fclose (fp);
     743           1 :               _keybox_release_blob (blob);
     744           1 :               return 0; /* Compress run not yet needed. */
     745             :             }
     746             :         }
     747           1 :       _keybox_release_blob (blob);
     748           1 :       fseek (fp, 0, SEEK_SET);
     749           1 :       clearerr (fp);
     750             :     }
     751             : 
     752             :   /* Create the new file. */
     753           2 :   rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
     754           2 :   if (rc)
     755             :     {
     756           0 :       fclose (fp);
     757           0 :       return rc;;
     758             :     }
     759             : 
     760             : 
     761             :   /* Processing loop.  By reading using _keybox_read_blob we
     762             :      automagically skip any blobs flagged as deleted.  Thus what we
     763             :      only have to do is to check all ephemeral flagged blocks whether
     764             :      their time has come and write out all other blobs. */
     765           2 :   cut_time = time(NULL) - 86400;
     766           2 :   first_blob = 1;
     767           2 :   skipped_deleted = 0;
     768           5 :   for (rc=0; !(read_rc = _keybox_read_blob2 (&blob, fp, &skipped_deleted));
     769           1 :        _keybox_release_blob (blob), blob = NULL )
     770             :     {
     771             :       unsigned int blobflags;
     772             :       const unsigned char *buffer;
     773             :       size_t length, pos, size;
     774             :       u32 created_at;
     775             : 
     776           1 :       if (skipped_deleted)
     777           0 :         any_changes = 1;
     778           1 :       buffer = _keybox_get_blob_image (blob, &length);
     779           1 :       if (first_blob)
     780             :         {
     781           1 :           first_blob = 0;
     782           1 :           if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
     783             :             {
     784             :               /* Write out the blob with an updated maintenance time
     785             :                  stamp and if needed (ie. used by gpg) set the openpgp
     786             :                  flag.  */
     787           0 :               _keybox_update_header_blob (blob, hd->for_openpgp);
     788           0 :               rc = _keybox_write_blob (blob, newfp);
     789           0 :               if (rc)
     790           0 :                 break;
     791           0 :               continue;
     792             :             }
     793             : 
     794             :           /* The header blob is missing.  Insert it.  */
     795           1 :           rc = _keybox_write_header_blob (newfp, hd->for_openpgp);
     796           1 :           if (rc)
     797           0 :             break;
     798           1 :           any_changes = 1;
     799             :         }
     800           0 :       else if (length > 4 && buffer[4] == KEYBOX_BLOBTYPE_HEADER)
     801             :         {
     802             :           /* Oops: There is another header record - remove it. */
     803           0 :           any_changes = 1;
     804           0 :           continue;
     805             :         }
     806             : 
     807           1 :       if (_keybox_get_flag_location (buffer, length,
     808             :                                      KEYBOX_FLAG_BLOB, &pos, &size)
     809           1 :           || size != 2)
     810             :         {
     811           0 :           rc = gpg_error (GPG_ERR_BUG);
     812           0 :           break;
     813             :         }
     814           1 :       blobflags = buf16_to_uint (buffer+pos);
     815           1 :       if ((blobflags & KEYBOX_FLAG_BLOB_EPHEMERAL))
     816             :         {
     817             :           /* This is an ephemeral blob. */
     818           0 :           if (_keybox_get_flag_location (buffer, length,
     819             :                                          KEYBOX_FLAG_CREATED_AT, &pos, &size)
     820           0 :               || size != 4)
     821           0 :             created_at = 0; /* oops. */
     822             :           else
     823           0 :             created_at = buf32_to_u32 (buffer+pos);
     824             : 
     825           0 :           if (created_at && created_at < cut_time)
     826             :             {
     827           0 :               any_changes = 1;
     828           0 :               continue; /* Skip this blob. */
     829             :             }
     830             :         }
     831             : 
     832           1 :       rc = _keybox_write_blob (blob, newfp);
     833           1 :       if (rc)
     834           0 :         break;
     835             :     }
     836           2 :   if (skipped_deleted)
     837           0 :     any_changes = 1;
     838           2 :   _keybox_release_blob (blob); blob = NULL;
     839           2 :   if (!rc && read_rc == -1)
     840           2 :     rc = 0;
     841           0 :   else if (!rc)
     842           0 :     rc = read_rc;
     843             : 
     844             :   /* Close both files. */
     845           2 :   if (fclose(fp) && !rc)
     846           0 :     rc = gpg_error_from_syserror ();
     847           2 :   if (fclose(newfp) && !rc)
     848           0 :     rc = gpg_error_from_syserror ();
     849             : 
     850             :   /* Rename or remove the temporary file. */
     851           2 :   if (rc || !any_changes)
     852           1 :     gnupg_remove (tmpfname);
     853             :   else
     854           1 :     rc = rename_tmp_file (bakfname, tmpfname, fname, hd->secret);
     855             : 
     856           2 :   xfree(bakfname);
     857           2 :   xfree(tmpfname);
     858           2 :   return rc;
     859             : }

Generated by: LCOV version 1.11