Fixed a bunch of little bugs as reported by Fabian Keil.
[gnupg.git] / g10 / keyring.c
index 00a5bb9..6b3c489 100644 (file)
@@ -50,9 +50,11 @@ typedef struct off_item **OffsetHashTable;
 
 
 typedef struct keyring_name *KR_NAME;
-struct keyring_name {
+struct keyring_name 
+{
   struct keyring_name *next;
   int secret;
+  int readonly;
   DOTLOCK lockhd;
   int is_locked;
   int did_full_scan;
@@ -199,7 +201,8 @@ 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, void **ptr)
+keyring_register_filename (const char *fname, int secret, int readonly, 
+                           void **ptr)
 {
     KR_NAME kr;
 
@@ -210,8 +213,11 @@ keyring_register_filename (const char *fname, int secret, void **ptr)
       {
         if (same_file_p (kr->fname, fname))
          {
+            /* Already registered. */
+            if (readonly)
+              kr->readonly = 1;
             *ptr=kr;
-           return 0; /* Already registered.  */
+           return 0; 
          }
       }
 
@@ -221,6 +227,7 @@ keyring_register_filename (const char *fname, int secret, void **ptr)
     kr = xmalloc (sizeof *kr + strlen (fname));
     strcpy (kr->fname, fname);
     kr->secret = !!secret;
+    kr->readonly = readonly;
     kr->lockhd = NULL;
     kr->is_locked = 0;
     kr->did_full_scan = 0;
@@ -242,7 +249,7 @@ keyring_is_writable (void *token)
 {
   KR_NAME r = token;
 
-  return r? !access (r->fname, W_OK) : 0;
+  return r? (r->readonly || !access (r->fname, W_OK)) : 0;
 }
     
 
@@ -419,42 +426,52 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
         }
 
         in_cert = 1;
-        if (pkt->pkttype == PKT_RING_TRUST) {
+        if (pkt->pkttype == PKT_RING_TRUST) 
+          {
             /*(this code is duplicated after the loop)*/
             if ( lastnode 
                  && lastnode->pkt->pkttype == PKT_SIGNATURE
                  && (pkt->pkt.ring_trust->sigcache & 1) ) {
-                /* this is a ring trust packet with a checked signature 
+                /* This is a ring trust packet with a checked signature 
                  * status cache following directly a signature paket.
-                 * Set the cache status into that signature packet */
+                 * Set the cache status into that signature packet */
                 PKT_signature *sig = lastnode->pkt->pkt.signature;
                 
                 sig->flags.checked = 1;
                 sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
             }
-            /* reset lastnode, so that we set the cache status only from
-             * the ring trust packet immediately folling a signature */
+            /* Reset LASTNODE, so that we set the cache status only from
+             * the ring trust packet immediately following a signature. */
             lastnode = NULL;
-        }
-        else {
-            node = lastnode = new_kbnode (pkt);
-            if (!keyblock)
-                keyblock = node;
-            else
-                add_kbnode (keyblock, node);
-
-            if ( pkt->pkttype == PKT_PUBLIC_KEY
-                 || pkt->pkttype == PKT_PUBLIC_SUBKEY
-                 || pkt->pkttype == PKT_SECRET_KEY
-                 || pkt->pkttype == PKT_SECRET_SUBKEY) {
-                if (++pk_no == hd->found.pk_no)
-                    node->flag |= 1;
-            }
-            else if ( pkt->pkttype == PKT_USER_ID) {
-                if (++uid_no == hd->found.uid_no)
-                    node->flag |= 2;
-            }
-        }
+           free_packet(pkt);
+           init_packet(pkt);
+           continue;
+          }
+
+
+        node = lastnode = new_kbnode (pkt);
+        if (!keyblock)
+          keyblock = node;
+        else
+          add_kbnode (keyblock, node);
+        switch (pkt->pkttype)
+          {
+          case PKT_PUBLIC_KEY:
+          case PKT_PUBLIC_SUBKEY:
+          case PKT_SECRET_KEY:
+          case PKT_SECRET_SUBKEY:
+            if (++pk_no == hd->found.pk_no)
+              node->flag |= 1;
+            break;
+
+          case PKT_USER_ID:
+            if (++uid_no == hd->found.uid_no)
+              node->flag |= 2;
+            break;
+            
+          default:
+            break;
+          }
 
         pkt = xmalloc (sizeof *pkt);
         init_packet(pkt);
@@ -499,6 +516,9 @@ keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
+    if (hd->found.kr->readonly)
+      return gpg_error (GPG_ERR_EACCES);
+
     if (!hd->found.n_packets) {
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
@@ -540,16 +560,24 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
     if (!hd)
         fname = NULL;
     else if (hd->found.kr)
+      {
         fname = hd->found.kr->fname;
+        if (hd->found.kr->readonly)
+          return gpg_error (GPG_ERR_EACCES);
+      }
     else if (hd->current.kr)
+      {
         fname = hd->current.kr->fname;
+        if (hd->current.kr->readonly)
+          return gpg_error (GPG_ERR_EACCES);
+      }
     else 
         fname = hd->resource? hd->resource->fname:NULL;
 
     if (!fname)
         return G10ERR_GENERAL; 
 
-    /* close this one otherwise we will lose the position for
+    /* Close this one otherwise we will lose the position for
      * a next search.  Fixme: it would be better to adjust the position
      * after the write opertions.
      */
@@ -575,6 +603,9 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
     if (!hd->found.kr)
         return -1; /* no successful prior search */
 
+    if (hd->found.kr->readonly)
+      return gpg_error (GPG_ERR_EACCES);
+
     if (!hd->found.n_packets) {
         /* need to know the number of packets - do a dummy get_keyblock*/
         rc = keyring_get_keyblock (hd, NULL);
@@ -966,7 +997,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);