Extend algo selection menu.
[gnupg.git] / g10 / keyring.c
index 2c89431..d069b13 100644 (file)
@@ -1,5 +1,5 @@
 /* keyring.c - keyring file handling
- * Copyright (C) 2001, 2004, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2004, 2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -53,9 +53,8 @@ typedef struct keyring_name *KR_NAME;
 struct keyring_name 
 {
   struct keyring_name *next;
-  int secret;
-  int readonly;
-  DOTLOCK lockhd;
+  int read_only;
+  dotlock_t lockhd;
   int is_locked;
   int did_full_scan;
   char fname[1];
@@ -69,9 +68,9 @@ static OffsetHashTable kr_offtbl;
 static int kr_offtbl_ready;
 
 
-struct keyring_handle {
+struct keyring_handle
+{
   CONST_KR_NAME resource;
-  int secret;             /* this is for a secret keyring */
   struct {
     CONST_KR_NAME kr;
     IOBUF iobuf;
@@ -93,7 +92,7 @@ struct keyring_handle {
 
 
 
-static int do_copy (int mode, const char *fname, KBNODE root, int secret,
+static int do_copy (int mode, const char *fname, KBNODE root,
                     off_t start_offset, unsigned int n_packets );
 
 
@@ -201,8 +200,7 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
  * if a new keyring was registered.
 */
 int
-keyring_register_filename (const char *fname, int secret, int readonly, 
-                           void **ptr)
+keyring_register_filename (const char *fname, int read_only, void **ptr)
 {
     KR_NAME kr;
 
@@ -214,20 +212,16 @@ keyring_register_filename (const char *fname, int secret, int readonly,
         if (same_file_p (kr->fname, fname))
          {
             /* Already registered. */
-            if (readonly)
-              kr->readonly = 1;
+            if (read_only)
+              kr->read_only = 1;
             *ptr=kr;
            return 0; 
          }
       }
 
-    if (secret)
-      register_secured_file (fname);
-
     kr = xmalloc (sizeof *kr + strlen (fname));
     strcpy (kr->fname, fname);
-    kr->secret = !!secret;
-    kr->readonly = readonly;
+    kr->read_only = read_only;
     kr->lockhd = NULL;
     kr->is_locked = 0;
     kr->did_full_scan = 0;
@@ -249,26 +243,24 @@ keyring_is_writable (void *token)
 {
   KR_NAME r = token;
 
-  return r? (r->readonly || !access (r->fname, W_OK)) : 0;
+  return r? (r->read_only || !access (r->fname, W_OK)) : 0;
 }
     
 
 \f
-/* Create a new handle for the resource associated with TOKEN.  SECRET
-   is just just as a cross-check.
+/* Create a new handle for the resource associated with TOKEN.
    
    The returned handle must be released using keyring_release (). */
 KEYRING_HANDLE
-keyring_new (void *token, int secret)
+keyring_new (void *token)
 {
   KEYRING_HANDLE hd;
   KR_NAME resource = token;
 
-  assert (resource && !resource->secret == !secret);
+  assert (resource);
   
   hd = xmalloc_clear (sizeof *hd);
   hd->resource = resource;
-  hd->secret = !!secret;
   active_handles++;
   return hd;
 }
@@ -516,7 +508,7 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
-    if (hd->found.kr->readonly)
+    if (hd->found.kr->read_only)
       return gpg_error (GPG_ERR_EACCES);
 
     if (!hd->found.n_packets) {
@@ -537,10 +529,10 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     hd->current.iobuf = NULL;
 
     /* do the update */
-    rc = do_copy (3, hd->found.kr->fname, kb, hd->secret,
+    rc = do_copy (3, hd->found.kr->fname, kb,
                   hd->found.offset, hd->found.n_packets );
     if (!rc) {
-      if (!hd->secret && kr_offtbl)
+      if (kr_offtbl)
         {
           update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
         }
@@ -562,13 +554,13 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     else if (hd->found.kr)
       {
         fname = hd->found.kr->fname;
-        if (hd->found.kr->readonly)
+        if (hd->found.kr->read_only)
           return gpg_error (GPG_ERR_EACCES);
       }
     else if (hd->current.kr)
       {
         fname = hd->current.kr->fname;
-        if (hd->current.kr->readonly)
+        if (hd->current.kr->read_only)
           return gpg_error (GPG_ERR_EACCES);
       }
     else 
@@ -585,8 +577,8 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     hd->current.iobuf = NULL;
 
     /* do the insert */
-    rc = do_copy (1, fname, kb, hd->secret, 0, 0 );
-    if (!rc && !hd->secret && kr_offtbl)
+    rc = do_copy (1, fname, kb, 0, 0 );
+    if (!rc && kr_offtbl)
       {
         update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
       }
@@ -603,7 +595,7 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
-    if (hd->found.kr->readonly)
+    if (hd->found.kr->read_only)
       return gpg_error (GPG_ERR_EACCES);
 
     if (!hd->found.n_packets) {
@@ -625,7 +617,7 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
     hd->current.iobuf = NULL;
 
     /* do the delete */
-    rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret,
+    rc = do_copy (2, hd->found.kr->fname, NULL,
                   hd->found.offset, hd->found.n_packets );
     if (!rc) {
         /* better reset the found info */
@@ -907,7 +899,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   int use_offtbl;
   PKT_user_id *uid = NULL;
   PKT_public_key *pk = NULL;
-  PKT_secret_key *sk = NULL;
   u32 aki[2];
 
   /* figure out what information we need */
@@ -953,7 +944,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
   if (rc)
     return rc;
 
-  use_offtbl = !hd->secret && kr_offtbl;
+  use_offtbl = !!kr_offtbl;
   if (!use_offtbl)
     ;
   else if (!kr_offtbl_ready)
@@ -997,7 +988,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           hd->word_match.name = xstrdup (name);
           hd->word_match.pattern = prepare_word_match (name);
         }
-      name = hd->word_match.pattern;
+      /*  name = hd->word_match.pattern; */
     }
 
   init_packet(&pkt);
@@ -1025,10 +1016,11 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
        
       pk = NULL;
-      sk = NULL;
       uid = NULL;
       if (   pkt.pkttype == PKT_PUBLIC_KEY
-             || pkt.pkttype == PKT_PUBLIC_SUBKEY)
+             || pkt.pkttype == PKT_PUBLIC_SUBKEY
+             || pkt.pkttype == PKT_SECRET_KEY
+             || pkt.pkttype == PKT_SECRET_SUBKEY) 
         {
           pk = pkt.pkt.public_key;
           ++pk_no;
@@ -1049,21 +1041,6 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           uid = pkt.pkt.user_id;
           ++uid_no;
         }
-      else if (    pkt.pkttype == PKT_SECRET_KEY
-                   || pkt.pkttype == PKT_SECRET_SUBKEY) 
-        {
-          sk = pkt.pkt.secret_key;
-          ++pk_no;
-
-          if (need_fpr) {
-            fingerprint_from_sk (sk, afp, &an);
-            while (an < 20) /* fill up to 20 bytes */
-              afp[an++] = 0;
-          }
-          if (need_keyid)
-            keyid_from_sk (sk, aki);
-            
-        }
 
       for (n=0; n < ndesc; n++) 
         {
@@ -1084,29 +1061,29 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
             break;
                 
           case KEYDB_SEARCH_MODE_SHORT_KID: 
-            if ((pk||sk) && desc[n].u.kid[1] == aki[1])
+            if (pk && desc[n].u.kid[1] == aki[1])
               goto found;
             break;
           case KEYDB_SEARCH_MODE_LONG_KID:
-            if ((pk||sk) && desc[n].u.kid[0] == aki[0]
+            if (pk && desc[n].u.kid[0] == aki[0]
                 && desc[n].u.kid[1] == aki[1])
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FPR16:
-            if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 16))
+            if (pk && !memcmp (desc[n].u.fpr, afp, 16))
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FPR20:
           case KEYDB_SEARCH_MODE_FPR: 
-            if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
+            if (pk && !memcmp (desc[n].u.fpr, afp, 20))
               goto found;
             break;
           case KEYDB_SEARCH_MODE_FIRST: 
-            if (pk||sk)
+            if (pk)
               goto found;
             break;
           case KEYDB_SEARCH_MODE_NEXT: 
-            if (pk||sk)
+            if (pk)
               goto found;
             break;
           default: 
@@ -1136,7 +1113,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
     {
       hd->found.offset = main_offset;
       hd->found.kr = hd->current.kr;
-      hd->found.pk_no = (pk||sk)? pk_no : 0;
+      hd->found.pk_no = pk? pk_no : 0;
       hd->found.uid_no = uid? uid_no : 0;
     }
   else if (rc == -1)
@@ -1148,11 +1125,10 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         {
           KR_NAME kr;
           
-          /* First set the did_full_scan flag for this keyring (ignore
-             secret keyrings) */
+          /* First set the did_full_scan flag for this keyring.  */
           for (kr=kr_names; kr; kr = kr->next)
             {
-              if (!kr->secret && hd->resource == kr) 
+              if (hd->resource == kr) 
                 {
                   kr->did_full_scan = 1;
                   break;
@@ -1162,7 +1138,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
              offtbl ready */
           for (kr=kr_names; kr; kr = kr->next)
             {
-              if (!kr->secret && !kr->did_full_scan) 
+              if (!kr->did_full_scan) 
                 break;
             }
           if (!kr)
@@ -1226,7 +1202,7 @@ create_tmp_file (const char *template,
     if (is_secured_filename (tmpfname))
       {
         *r_fp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     else
       *r_fp = iobuf_create (tmpfname);
@@ -1247,50 +1223,35 @@ create_tmp_file (const char *template,
 
 
 static int
-rename_tmp_file (const char *bakfname, const char *tmpfname,
-                 const char *fname, int secret )
+rename_tmp_file (const char *bakfname, const char *tmpfname, const char *fname)
 {
   int rc = 0;
 
-  /* It's a secret keyring, so let's force a fsync just to be safe on
-     filesystems that may not sync data and metadata together
-     (e.g. ext4). */
-  if (secret && iobuf_ioctl (NULL, 4, 0, (char*)tmpfname))
-    {
-      rc = gpg_error_from_syserror ();
-      goto fail;
-    }
-
   /* Invalidate close caches.  */
-  if (iobuf_ioctl (NULL, 2, 0, (char*)tmpfname ))
+  if (iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)tmpfname ))
     {
       rc = gpg_error_from_syserror ();
       goto fail;
     }
-  iobuf_ioctl (NULL, 2, 0, (char*)bakfname );
-  iobuf_ioctl (NULL, 2, 0, (char*)fname );
+  iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)bakfname );
+  iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname );
 
-  /* first make a backup file except for secret keyrings */
-  if (!secret)
-    { 
+  /* First make a backup file. */
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-      remove (bakfname);
+  gnupg_remove (bakfname);
 #endif
-      if (rename (fname, bakfname) )
-        {
-          rc = gpg_error_from_syserror ();
-          log_error ("renaming `%s' to `%s' failed: %s\n",
-                     fname, bakfname, strerror(errno) );
-          return rc;
-       }
+  if (rename (fname, bakfname) )
+    {
+      rc = gpg_error_from_syserror ();
+      log_error ("renaming `%s' to `%s' failed: %s\n",
+                 fname, bakfname, strerror(errno) );
+      return rc;
     }
   
   /* then rename the file */
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
-  remove( fname );
+  gnupg_remove( fname );
 #endif
-  if (secret)
-    unregister_secured_file (fname);
   if (rename (tmpfname, fname) )
     {
       rc = gpg_error_from_syserror ();
@@ -1308,9 +1269,7 @@ rename_tmp_file (const char *bakfname, const char *tmpfname,
 
     statbuf.st_mode=S_IRUSR | S_IWUSR;
 
-    if (((secret && !opt.preserve_permissions)
-         || !stat (bakfname,&statbuf)) 
-        && !chmod (fname,statbuf.st_mode))
+    if (!stat (bakfname, &statbuf) && !chmod (fname, statbuf.st_mode))
       ;
     else
       log_error ("WARNING: unable to restore permissions to `%s': %s",
@@ -1321,13 +1280,6 @@ rename_tmp_file (const char *bakfname, const char *tmpfname,
   return 0;
 
  fail:
-  if (secret)
-    {
-      log_info(_("WARNING: 2 files with confidential information exists.\n"));
-      log_info(_("%s is the unchanged one\n"), fname );
-      log_info(_("%s is the new one\n"), tmpfname );
-      log_info(_("Please fix this possible security flaw\n"));
-    }
   return rc;
 }
 
@@ -1392,7 +1344,7 @@ keyring_rebuild_cache (void *token,int noisy)
   int rc;
   ulong count = 0, sigcount = 0;
 
-  hd = keyring_new (token, 0);
+  hd = keyring_new (token);
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
 
@@ -1420,7 +1372,7 @@ keyring_rebuild_cache (void *token,int noisy)
               tmpfp = NULL;
             }
           rc = lastresname? rename_tmp_file (bakfilename, tmpfilename, 
-                                             lastresname, 0) : 0;
+                                             lastresname) : 0;
           xfree (tmpfilename);  tmpfilename = NULL;
           xfree (bakfilename);  bakfilename = NULL;
           if (rc)
@@ -1440,7 +1392,20 @@ keyring_rebuild_cache (void *token,int noisy)
           log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
           goto leave;
         }
-      assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+      if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+        {
+          /* We had a few reports about corrupted keyrings; if we have
+             been called directly from the command line we delete such
+             a keyblock instead of bailing out.  */
+          log_error ("unexpected keyblock found (pkttype=%d)%s\n",
+                     keyblock->pkt->pkttype, noisy? " - deleted":"");
+          if (noisy)
+            continue;
+          log_info ("Hint: backup your keys and try running `%s'\n",
+                    "gpg --rebuild-keydb-caches");
+          rc = gpg_error (GPG_ERR_INV_KEYRING);
+          goto leave;
+        }
 
       /* check all signature to set the signature's cache flags */
       for (node=keyblock; node; node=node->next)
@@ -1500,7 +1465,7 @@ keyring_rebuild_cache (void *token,int noisy)
       tmpfp = NULL;
     }
   rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
-                                     lastresname, 0) : 0;
+                                     lastresname) : 0;
   xfree (tmpfilename);  tmpfilename = NULL;
   xfree (bakfilename);  bakfilename = NULL;
 
@@ -1523,7 +1488,7 @@ keyring_rebuild_cache (void *token,int noisy)
  *     3 = update
  */
 static int
-do_copy (int mode, const char *fname, KBNODE root, int secret,
+do_copy (int mode, const char *fname, KBNODE root,
          off_t start_offset, unsigned int n_packets )
 {
     IOBUF fp, newfp;
@@ -1543,9 +1508,9 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
        mode_t oldmask;
 
        oldmask=umask(077);
-        if (!secret && is_secured_filename (fname)) {
+        if (is_secured_filename (fname)) {
             newfp = NULL;
-            errno = EPERM;
+            gpg_err_set_errno (EPERM);
         }
         else
             newfp = iobuf_create (fname);
@@ -1589,8 +1554,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
        iobuf_close(fp);
        goto leave;
     }
-    if (secret)
-      register_secured_file (tmpfname);
 
     if( mode == 1 ) { /* insert */
        /* copy everything to the new file */
@@ -1599,8 +1562,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
            log_error("%s: copy to `%s' failed: %s\n",
                      fname, tmpfname, g10_errstr(rc) );
            iobuf_close(fp);
-            if (secret)
-              unregister_secured_file (tmpfname);
            iobuf_cancel(newfp);
            goto leave;
        }
@@ -1614,8 +1575,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
            log_error ("%s: copy to `%s' failed: %s\n",
                        fname, tmpfname, g10_errstr(rc) );
            iobuf_close(fp);
-            if (secret)
-              unregister_secured_file (tmpfname);
            iobuf_cancel(newfp);
            goto leave;
        }
@@ -1626,8 +1585,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
            log_error("%s: skipping %u packets failed: %s\n",
                            fname, n_packets, g10_errstr(rc));
            iobuf_close(fp);
-            if (secret)
-              unregister_secured_file (tmpfname);
            iobuf_cancel(newfp);
            goto leave;
        }
@@ -1637,8 +1594,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
         rc = write_keyblock (newfp, root);
         if (rc) {
           iobuf_close(fp);
-          if (secret)
-            unregister_secured_file (tmpfname);
           iobuf_cancel(newfp);
           goto leave;
         }
@@ -1651,8 +1606,6 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
            log_error("%s: copy to `%s' failed: %s\n",
                      fname, tmpfname, g10_errstr(rc) );
            iobuf_close(fp);
-            if (secret)
-              unregister_secured_file (tmpfname);
            iobuf_cancel(newfp);
            goto leave;
        }
@@ -1671,7 +1624,7 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
        goto leave;
     }
 
-    rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
+    rc = rename_tmp_file (bakfname, tmpfname, fname);
 
   leave:
     xfree(bakfname);