See ChangeLog: Wed Dec 23 13:34:22 CET 1998 Werner Koch
[gnupg.git] / g10 / ringedit.c
index ebeceb1..d46094c 100644 (file)
@@ -1,14 +1,14 @@
 /* ringedit.c -  Function for key ring editing
  *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -77,6 +77,7 @@ typedef struct resource_table_struct RESTBL;
 
 #define MAX_RESOURCES 10
 static RESTBL resource_table[MAX_RESOURCES];
+static const char *keyring_lock;
 
 static int search( PACKET *pkt, KBPOS *kbpos, int secret );
 
@@ -116,6 +117,15 @@ fatal_gdbm_error( const char *string )
 
 #endif /* HAVE_LIBGDBM */
 
+static void
+cleanup( void )
+{
+    if( keyring_lock ) {
+       release_dotlock( keyring_lock );
+       keyring_lock = NULL;
+    }
+}
+
 /****************************************************************
  ****************** public functions ****************************
  ****************************************************************/
@@ -152,6 +162,7 @@ enum_keyblock_resources( int *sequence, int secret )
 int
 add_keyblock_resource( const char *url, int force, int secret )
 {
+    static int initialized = 0;
     static int any_secret, any_public;
     const char *resname = url;
     IOBUF iobuf = NULL;
@@ -160,6 +171,11 @@ add_keyblock_resource( const char *url, int force, int secret )
     int rc = 0;
     enum resource_type rt = rt_UNKNOWN;
 
+    if( !initialized ) {
+       initialized = 1;
+       atexit( cleanup );
+    }
+
     /* Do we have an URL?
      * gnupg-gdbm:filename  := this is a GDBM resource
      * gnupg-ring:filename  := this is a plain keyring
@@ -233,7 +249,7 @@ add_keyblock_resource( const char *url, int force, int secret )
        goto leave;
 
       case rt_RING:
-       iobuf = iobuf_fopen( filename, "rb" );
+       iobuf = iobuf_open( filename );
        if( !iobuf && !force ) {
            rc = G10ERR_OPEN_FILE;
            goto leave;
@@ -282,7 +298,7 @@ add_keyblock_resource( const char *url, int force, int secret )
            else
                log_info(_("%s: keyring created\n"), filename );
        }
-      #ifdef __MINGW32__
+      #if __MINGW32__ || 1
        /* must close it again */
        iobuf_close( iobuf );
        iobuf = NULL;
@@ -671,9 +687,10 @@ enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
        kbpos->resno = i;
        rentry = check_pos( kbpos );
        kbpos->rt = resource_table[i].rt;
+       kbpos->valid = 0;
        switch( kbpos->rt ) {
          case rt_RING:
-           kbpos->fp = iobuf_fopen( rentry->fname, "rb" );
+           kbpos->fp = iobuf_open( rentry->fname );
            if( !kbpos->fp ) {
                log_error("can't open '%s'\n", rentry->fname );
                return G10ERR_OPEN_FILE;
@@ -832,6 +849,127 @@ update_keyblock( KBPOS *kbpos, KBNODE root )
 
 \f
 /****************************************************************
+ ********** Implemenation of a user ID database    **************
+ ****************************************************************/
+#if 0
+/****************
+ * Layout of the user ID db
+ *
+ * This user ID DB provides fast lookup of user ID, but the user ids are
+ * not in any specific order.
+ *
+ * A string "GnuPG user db", a \n.
+ * user ids of one key, delimited by \t,
+ * a # or ^ followed by a 20 byte fingerprint, followed by an \n
+ * The literal characters %, \n, \t, #, ^ must be replaced by a percent sign
+ * and their hex value.
+ *
+ * (We use Boyer/Moore pattern matching)
+ */
+
+/****************
+ * This compiles pattern to the distance table, the table will be allocate
+ * here and must be freed by using free().
+ * Returns: Ptr to new allocated Table
+ *         Caller must free the table.
+ */
+
+static size_t *
+compile_bm_table( const byte *pattern, size_t len )
+{
+    ushort *dist;
+    int i;
+
+    dist = m_alloc_clear( 256 * sizeof *dist );
+    for(i=0; i < 256; i++ )
+       dist[i] = len;
+    for(i=0; i < len-1; i++ )
+       dTbl[p[i]] = len-i-1;
+    return dist;
+}
+
+
+
+
+/****************
+ * Search BUF of BUFLEN for pattern P of length PATLEN.
+ * dist is the Boyer/Moore distance table of 256 Elements,
+ * case insensitive search is done if IGNCASE is true (In this case
+ * the distance table has to compiled from uppercase chacaters and
+ * PAT must also be uppercase.
+ * Returns: Prt to maching string in BUF, or NULL if not found.
+ */
+
+static const *
+do_bm_search( const byte *buf, size_t buflen,
+             const byte *pat, size_t patlen, size_t *dist, int igncase )
+{
+    int i, j, k;
+
+    if( igncase ) {
+       int c, c1;
+
+       for( i = --patlen; i < buflen; i += dist[c1] )
+           for( j=patlen, k=i, c1=c=toupper(buf[k]); c == pat[j];
+                                         j--, k--, c=toupper(buf[k]) ) {
+               if( !j )
+                   return buf+k;
+           }
+    }
+    else {
+       for( i = --patlen; i < buflen; i += dist[buf[i]] )
+           for( j=patlen, k=i; buf[k] == pat[j]; j--, k-- ) {
+               if( !j )
+                   return buf+k;
+           }
+    }
+    return NULL;
+}
+
+
+typedef struct {
+    size_t dist[256];
+} *SCAN_USER_HANDLE;
+
+static SCAN_USER_HANDLE
+scan_user_file_open( const byte *name )
+{
+    SCAN_USER_HANDLE hd;
+    size_t *dist;
+    int i;
+
+    hd = m_alloc_clear( sizeof *hd );
+    dist = hd->dist;
+    /* compile the distance table */
+    for(i=0; i < 256; i++ )
+       dist[i] = len;
+    for(i=0; i < len-1; i++ )
+       dTbl[p[i]] = len-i-1;
+    /* setup other things */
+
+    return hd;
+}
+
+static int
+scan_user_file_close( SCAN_USER_HANDLE hd )
+{
+    m_free( hd );
+}
+
+static int
+scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr )
+{
+    char record[1000];
+
+    /* read a record */
+
+
+}
+#endif
+
+
+\f
+/****************************************************************
  ********** Functions which operates on regular keyrings ********
  ****************************************************************/
 
@@ -882,8 +1020,9 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
     init_packet(&pkt);
     save_mode = set_packet_list_mode(0);
     kbpos->rt = rt_RING;
+    kbpos->valid = 0;
 
-  #if __MINGW32__
+  #if __MINGW32__  || 1
     assert(!iobuf);
     iobuf = iobuf_open( fname );
     if( !iobuf ) {
@@ -920,13 +1059,15 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
            BUG();
        free_packet(&pkt);
     }
-    if( !rc )
+    if( !rc ) {
        kbpos->offset = offset;
+       kbpos->valid = 1;
+    }
 
   leave:
     free_packet(&pkt);
     set_packet_list_mode(save_mode);
-  #if __MINGW32__
+  #if __MINGW32__ || 1
     iobuf_close(iobuf);
   #endif
     return rc;
@@ -946,12 +1087,14 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
     if( !(rentry=check_pos(kbpos)) )
        return G10ERR_GENERAL;
 
-    a = iobuf_fopen( rentry->fname, "rb" );
+    a = iobuf_open( rentry->fname );
     if( !a ) {
        log_error("can't open '%s'\n", rentry->fname );
        return G10ERR_OPEN_FILE;
     }
 
+    if( !kbpos->valid )
+       log_debug("kbpos not valid in keyring_read, want %d\n", (int)kbpos->offset );
     if( iobuf_seek( a, kbpos->offset ) ) {
        log_error("can't seek to %lu\n", kbpos->offset);
        iobuf_close(a);
@@ -975,6 +1118,12 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
        }
        /* make a linked list of all packets */
        switch( pkt->pkttype ) {
+         case PKT_COMPRESSED:
+           log_error("skipped compressed packet in keyring\n" );
+           free_packet(pkt);
+           init_packet(pkt);
+           break;
+
          case PKT_PUBLIC_KEY:
          case PKT_SECRET_KEY:
            if( in_cert )
@@ -992,6 +1141,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
        }
     }
   ready:
+    kbpos->valid = 0;
     if( rc == -1 && root )
        rc = 0;
 
@@ -1037,6 +1187,12 @@ keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs )
        }
        /* make a linked list of all packets */
        switch( pkt->pkttype ) {
+         case PKT_COMPRESSED:
+           log_error("skipped compressed packet in keyring\n" );
+           free_packet(pkt);
+           init_packet(pkt);
+           break;
+
          case PKT_PUBLIC_KEY:
          case PKT_SECRET_KEY:
            if( root ) { /* store this packet */
@@ -1103,8 +1259,13 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
     if( kbpos->fp )
        BUG(); /* not allowed with such a handle */
 
+    if( !keyring_lock );
+       keyring_lock = make_dotlock( rentry->fname, -1 );
+    if( !keyring_lock )
+       log_fatal("can't lock '%s'\n", rentry->fname );
+
     /* open the source file */
-    fp = iobuf_fopen( rentry->fname, "rb" );
+    fp = iobuf_open( rentry->fname );
     if( mode == 1 && !fp && errno == ENOENT ) { /* no file yet */
        KBNODE kbctx, node;
 
@@ -1112,6 +1273,10 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
        newfp = iobuf_create( rentry->fname );
        if( !newfp ) {
            log_error(_("%s: can't create: %s\n"), rentry->fname, strerror(errno));
+           if( !opt.lock_once ) {
+               release_dotlock( keyring_lock );
+               keyring_lock = NULL;
+           }
            return G10ERR_OPEN_FILE;
        }
        else
@@ -1123,16 +1288,28 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
                log_error("build_packet(%d) failed: %s\n",
                            node->pkt->pkttype, g10_errstr(rc) );
                iobuf_cancel(newfp);
+               if( !opt.lock_once ) {
+                   release_dotlock( keyring_lock );
+                   keyring_lock = NULL;
+               }
                return G10ERR_WRITE_FILE;
            }
        }
        if( iobuf_close(newfp) ) {
            log_error("%s: close failed: %s\n", rentry->fname, strerror(errno));
+           if( !opt.lock_once ) {
+               release_dotlock( keyring_lock );
+               keyring_lock = NULL;
+           }
            return G10ERR_CLOSE_FILE;
        }
        if( chmod( rentry->fname, S_IRUSR | S_IWUSR ) ) {
            log_error("%s: chmod failed: %s\n",
                                    rentry->fname, strerror(errno) );
+           if( !opt.lock_once ) {
+               release_dotlock( keyring_lock );
+               keyring_lock = NULL;
+           }
            return G10ERR_WRITE_FILE;
        }
        return 0;
@@ -1229,6 +1406,7 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
                goto leave;
            }
        }
+       kbpos->valid = 0;
     }
 
     if( mode == 2 || mode == 3 ) { /* delete or update */
@@ -1297,6 +1475,10 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
     }
 
   leave:
+    if( !opt.lock_once ) {
+       release_dotlock( keyring_lock );
+       keyring_lock = NULL;
+    }
     m_free(bakfname);
     m_free(tmpfname);
     return rc;
@@ -1364,6 +1546,9 @@ do_gdbm_store( KBPOS *kbpos, KBNODE root, int update )
     content.dsize = iobuf_get_temp_length( fp );
     rc = gdbm_store( rentry->dbf, key, content,
                                  update? GDBM_REPLACE : GDBM_INSERT );
+    if( rc == 1 && !update )
+       rc = gdbm_store( rentry->dbf, key, content, GDBM_REPLACE );
+
     if( rc ) {
        log_error("%s: gdbm_store failed: %s\n", rentry->fname,
                            rc == 1 ? "already stored"