See ChangeLog: Thu Jan 7 18:00:58 CET 1999 Werner Koch
authorWerner Koch <wk@gnupg.org>
Thu, 7 Jan 1999 17:05:48 +0000 (17:05 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 7 Jan 1999 17:05:48 +0000 (17:05 +0000)
31 files changed:
NEWS
TODO
cipher/ChangeLog
cipher/md.c
configure.in
doc/gpg.1pod
g10/ChangeLog
g10/armor.c
g10/compress.c
g10/encr-data.c
g10/filter.h
g10/getkey.c
g10/keydb.h
g10/packet.h
g10/parse-packet.c
g10/passphrase.c
g10/pkclist.c
g10/plaintext.c
g10/seckey-cert.c
g10/sig-check.c
g10/tdbio.c
include/ChangeLog
include/cipher.h
include/mpi.h
mpi/ChangeLog
mpi/mpi-bit.c
mpi/mpi-cmp.c
po/de.po
util/ChangeLog
util/argparse.c
util/iobuf.c

diff --git a/NEWS b/NEWS
index 18c538f..3d52560 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,13 @@
 
     * Polish language support.
 
+    * When querying the passphrase, the key ID of the primary key is
+      displayed along with the one of the used secondary key.
+
+    * Fixed a bug occurring when decrypting pgp 5 encrypted messages,
+      fixed an infinite loop bug in the 3DES code and in the code
+      which looks for trusted signatures.
+
 
 Noteworthy changes in version 0.9.0
 -----------------------------------
diff --git a/TODO b/TODO
index 4bae8a9..f125491 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,8 +22,8 @@ Important
 
     * print a warning when a revoked/expired secret key is used.
 
-    * display trhe primary keyID in passphrase.c in addition to the
-      one for the requested key.
+    * Allow the use of a the faked RNG onyl for keys which are
+      flagged as INSECURE.
 
 
 Needed
@@ -35,6 +35,12 @@ Needed
       encrypt this all) - We need an identifier for Twofish to put this
       one into the cipher preferences.
 
+    * The -export-dynamic flag to ld works only for FreeBSD 3.0.  It does
+      not exist on FreeBSD's 2.2.x version of ld.
+      Also, on my FreeBSD 2.2-stable box, i simply removed the
+      -Wl,-export-dynamic flag from my Makefile and it linked and seems to
+      be working OK so far.
+
 Minor Bugs
 ----------
 
@@ -51,3 +57,4 @@ Nice to have
     * change the fake_data stuff to mpi_set_opaque
     * rewrite the ugly armor code.
 
+
index 328f264..347d346 100644 (file)
@@ -1,3 +1,8 @@
+Thu Jan  7 18:00:58 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * md.c (md_stop_debug): Do a flush first.
+       (md_open): size of buffer now depends on the secure parameter
+
 Sun Jan  3 15:28:44 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * rndunix.c (start_gatherer): Fixed stupid ==/= bug
index b1274c6..f7be5e4 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #include "util.h"
 #include "cipher.h"
 #include "errors.h"
@@ -208,8 +209,18 @@ MD_HANDLE
 md_open( int algo, int secure )
 {
     MD_HANDLE hd;
-    hd = secure ? m_alloc_secure_clear( sizeof *hd )
-               : m_alloc_clear( sizeof *hd );
+    int bufsize;
+
+    if( secure ) {
+       bufsize = 512 - sizeof( *hd );
+       hd = m_alloc_secure_clear( sizeof *hd + bufsize );
+    }
+    else {
+       bufsize = 1024 - sizeof( *hd );
+       hd = m_alloc_clear( sizeof *hd + bufsize );
+    }
+
+    hd->bufsize = bufsize+1; /* hd has already one byte allocated */
     hd->secure = secure;
     if( algo )
        md_enable( hd, algo );
@@ -252,9 +263,11 @@ md_copy( MD_HANDLE a )
     MD_HANDLE b;
     struct md_digest_list_s *ar, *br;
 
-    b = a->secure ? m_alloc_secure( sizeof *b )
-                 : m_alloc( sizeof *b );
-    memcpy( b, a, sizeof *a );
+    if( a->bufcount )
+       md_write( a, NULL, 0 );
+    b = a->secure ? m_alloc_secure( sizeof *b + a->bufsize - 1 )
+                 : m_alloc( sizeof *b + a->bufsize - 1 );
+    memcpy( b, a, sizeof *a + a->bufsize - 1 );
     b->list = NULL;
     b->debug = NULL;
     /* and now copy the complete list of algorithms */
@@ -266,6 +279,9 @@ md_copy( MD_HANDLE a )
        br->next = b->list;
        b->list = br;
     }
+
+    if( a->debug )
+       md_start_debug( b, "unknown" );
     return b;
 }
 
@@ -490,6 +506,8 @@ void
 md_stop_debug( MD_HANDLE md )
 {
     if( md->debug ) {
+       if( md->bufcount )
+           md_write( md, NULL, 0 );
        fclose(md->debug);
        md->debug = NULL;
     }
index 0450817..f710486 100644 (file)
@@ -106,6 +106,8 @@ case "${target}" in
             CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE"
         fi
         ;;
+    m68k-atari-mint)
+        ;;
     *)
        ;;
 esac
index 3122665..d4e4ab0 100644 (file)
@@ -399,10 +399,10 @@ B<--s2k-mode> I<number>
 B<--compress-algo> I<number>
     Use compress algorithm I<number>. Default is I<2> which is
     RFC1950 compression; you may use I<1> to use the old zlib
-    version which is used by PGP. This is only used for
-    new messages. The default algorithm may give better
+    version which is used by PGP.
+    The default algorithm may give better
     results because the window size is not limited to 8K.
-    If this is not used the OpenPGP behaviour is used; i.e.
+    If this is not used the OpenPGP behavior is used; i.e.
     the compression algorith is selected from the preferences.
 
 B<--digest-algo> I<name>
@@ -418,7 +418,7 @@ B<--throw-keyid>
     process because all available secret keys are tried.
 
 B<--not-dash-escaped>
-    This option changes the behaviour of cleartext signature
+    This option changes the behavior of cleartext signature
     so that they can be used for patch files. You should not
     send such an armored file via email because all spaces
     and line endings are hashed too.  You can not use this
index 69c1092..532fa47 100644 (file)
@@ -1,3 +1,23 @@
+Thu Jan  7 18:00:58 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * pkclist.c (add_ownertrust): Fixed return value.
+
+       * encr-data.c (decrypt_data): Disabled iobuf_set_limit and
+       iobuf_pop_filter stuff.
+       * compress.c (handle_compressed): Disabled iobuf_pop_filter.
+
+       * packet.h (PKT_secret_key): Add is_primary flag.
+       * parse-packet.c (parse_key): Set this flag.
+       * passphrase.c (passphrase_to_dek): Kludge to print the primary
+       keyid - changed the API: keyid must now hold 2 keyids.
+       * getkey.c (get_primary_seckey): New.
+       * seckey-cert.c (do_check): pass primary keyid to passphrase query
+
+       * tbdio.c (open_db): removed the atexit
+       (tdbio_set_dbname): and moved it to here.
+
+       * armor.c: Rewrote large parts.
+
 Tue Dec 29 19:55:38 CET 1998  Werner Koch  <wk@isil.d.shuttle.de>
 
        * revoke.c (gen_revoke): Removed compression.
index cddddf0..be0e69b 100644 (file)
@@ -1,5 +1,5 @@
 /* armor.c - Armor flter
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -37,6 +37,8 @@
 #include "i18n.h"
 
 
+#define MAX_LINELEN 20000
+
 #define CRCINIT 0xB704CE
 #define CRCPOLY 0X864CFB
 #define CRCUPDATE(a,c) do {                                                \
@@ -86,6 +88,7 @@ typedef enum {
 
 /* if we encounter this armor string with this index, go
  * into a mode which fakes packets and wait for the next armor */
+#define BEGIN_SIGNATURE 2
 #define BEGIN_SIGNED_MSG_IDX 3
 static char *head_strings[] = {
     "BEGIN PGP MESSAGE",
@@ -109,12 +112,6 @@ static char *tail_strings[] = {
 };
 
 
-static fhdr_state_t find_header( fhdr_state_t state,
-                                byte *buf, size_t *r_buflen,
-                                IOBUF a, size_t n,
-                                unsigned *r_empty, int *r_hashes,
-                                int only_keyblocks, int *not_dashed );
-
 
 static void
 initialize(void)
@@ -153,7 +150,7 @@ initialize(void)
  * Returns: True if it seems to be armored
  */
 static int
-is_armored( byte *buf )
+is_armored( const byte *buf )
 {
     int ctb, pkttype;
 
@@ -256,6 +253,8 @@ parse_hash_header( const char *line )
 }
 
 
+
+#if 0 /* old code */
 /****************
  * parse an ascii armor.
  * Returns: the state,
@@ -656,10 +655,125 @@ find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
        }
     }
 
+  fprintf(stderr,"ARMOR READ (state=%d): %.*s", state, n, buf );
+
     *r_buflen = n;
     *r_empty = empty;
     return state;
 }
+#endif
+
+
+static unsigned
+trim_trailing_spaces( byte *line, unsigned len )
+{
+    byte *p, *mark;
+    unsigned n;
+
+    for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
+       if( strchr(" \t\r\n", *p ) ) {
+           if( !mark )
+               mark = p;
+       }
+       else
+           mark = NULL;
+    }
+
+    if( mark ) {
+       *mark = 0;
+       return mark - line;
+    }
+    return len;
+}
+
+
+
+/****************
+ * Check whether this is a armor line.
+ * returns: -1 if it is not a armor header or the index number of the
+ * armor header.
+ */
+static int
+is_armor_header( byte *line, unsigned len )
+{
+    const char *s;
+    byte *save_p, *p;
+    int save_c;
+    int i;
+
+    if( len < 15 )
+       return -1; /* too short */
+    if( memcmp( line, "-----", 5 ) )
+       return -1; /* no */
+    p = strstr( line+5, "-----");
+    if( !p )
+       return -1;
+    save_p = p;
+    p += 5;
+    if( *p == '\r' )
+       p++;
+    if( *p == '\n' )
+       p++;
+    if( *p )
+       return -1; /* garbage after dashes */
+    save_c = *save_p; *save_p = 0;
+    p = line+5;
+    for(i=0; (s=head_strings[i]); i++ )
+       if( !strcmp(s, p) )
+           break;
+    *save_p = save_c;
+    if( !s )
+       return -1; /* unknown armor line */
+
+    if( opt.verbose > 1 )
+       log_info(_("armor: %s\n"), head_strings[i]);
+    return i;
+}
+
+
+
+/****************
+ * Parse a header lines
+ * Return 0: Empty line (end of header lines)
+ *      -1: invalid header line
+ *      >0: Good header line
+ */
+static int
+parse_header_line( armor_filter_context_t *afx, byte *line, unsigned len )
+{
+    byte *p;
+    int hashes=0;
+
+    if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
+       return 0; /* empty line */
+    len = trim_trailing_spaces( line, len );
+    p = strchr( line, ':');
+    if( !p || !p[1] ) {
+       log_error(_("invalid armor header: "));
+       print_string( stderr, line, len, 0 );
+       putc('\n', stderr);
+       return -1;
+    }
+
+    if( opt.verbose ) {
+       log_info(_("armor header: "));
+       print_string( stderr, line, len, 0 );
+       putc('\n', stderr);
+    }
+
+    if( afx->in_cleartext ) {
+       if( (hashes=parse_hash_header( line )) )
+           afx->hashes |= hashes;
+       else if( strlen(line) > 15 && !memcmp( line, "NotDashEscaped:", 15 ) )
+           afx->not_dash_escaped = 1;
+       else {
+           log_error(_("invalid clearsig header\n"));
+           return -1;
+       }
+    }
+    return 1;
+}
+
 
 
 /* figure out whether the data is armored or not */
@@ -667,73 +781,119 @@ static int
 check_input( armor_filter_context_t *afx, IOBUF a )
 {
     int rc = 0;
+    int i;
     size_t n;
-    fhdr_state_t state = afx->parse_state;
     unsigned emplines;
+    byte *line;
+    unsigned len;
+    unsigned maxlen;
+    int hdr_line = -1;
+
+    /* read the first line to see whether this is armored data */
+    maxlen = MAX_LINELEN;
+    len = afx->buffer_len = iobuf_read_line( a, &afx->buffer,
+                                            &afx->buffer_size, &maxlen );
+    line = afx->buffer;
+    if( !maxlen ) {
+       /* line has been truncated: assume not armored */
+       afx->inp_checked = 1;
+       afx->inp_bypass = 1;
+       return 0;
+    }
 
-    if( state != fhdrENDClearsig )
-       state = fhdrHASArmor;
+    if( !len ) {
+       return -1; /* eof */
+    }
 
-    n = DIM(afx->helpbuf);
-    state = find_header( state, afx->helpbuf, &n, a,
-                               afx->helplen, &emplines, &afx->hashes,
-                               afx->only_keyblocks, &afx->not_dash_escaped );
-    switch( state ) {
-      case fhdrNOArmor:
+    /* (the line is always a C string but maybe longer) */
+    if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
+       ;
+    else if( !is_armored( line ) ) {
        afx->inp_checked = 1;
        afx->inp_bypass = 1;
-       afx->helplen = n;
-       break;
+       return 0;
+    }
 
-      case fhdrERROR:
-       invalid_armor();
-       break;
+    /* find the armor header */
+    while(len) {
+       i = is_armor_header( line, len );
+       if( i >= 0 && !(afx->only_keyblocks && i != 1 && i != 5 && i != 6 )) {
+           hdr_line = i;
+           if( hdr_line == BEGIN_SIGNED_MSG_IDX ) {
+               if( afx->in_cleartext ) {
+                   log_error(_("nested clear text signatures\n"));
+                   rc = G10ERR_INVALID_ARMOR;
+               }
+               afx->in_cleartext = 1;
+           }
+           break;
+       }
+       /* read the next line (skip all truncated lines) */
+       do {
+           maxlen = MAX_LINELEN;
+           afx->buffer_len = iobuf_read_line( a, &afx->buffer,
+                                              &afx->buffer_size, &maxlen );
+           line = afx->buffer;
+           len = afx->buffer_len;
+       } while( !maxlen );
+    }
+
+    /* parse the header lines */
+    while(len) {
+       /* read the next line (skip all truncated lines) */
+       do {
+           maxlen = MAX_LINELEN;
+           afx->buffer_len = iobuf_read_line( a, &afx->buffer,
+                                              &afx->buffer_size, &maxlen );
+           line = afx->buffer;
+           len = afx->buffer_len;
+       } while( !maxlen );
+
+       i = parse_header_line( afx, line, len );
+       if( i <= 0 ) {
+           if( i )
+               rc = G10ERR_INVALID_ARMOR;
+           break;
+       }
+    }
 
-      case fhdrEOF:
-       rc = -1;
-       break;
-
-      case fhdrNullClearsig:
-      case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
-      case fhdrREADClearsigNext:
-      case fhdrCLEARSIGSimple:
-      case fhdrCLEARSIGSimpleNext:
-       afx->helplen = n;
-       afx->helpidx = 0;
-       afx->faked = 1;
-       break;
 
-      case fhdrTEXT:
-       afx->helplen = n;
-       afx->helpidx = 0;
+    if( rc )
+       invalid_armor();
+    else if( afx->in_cleartext ) {
+       afx->faked = 1;
+    }
+    else {
        afx->inp_checked = 1;
        afx->crc = CRCINIT;
        afx->idx = 0;
        afx->radbuf[0] = 0;
-       break;
-
-      default: BUG();
     }
 
-    afx->parse_state = state;
     return rc;
 }
 
 
 
-/* fake a literal data packet and wait for an armor line */
+/****************
+ * Fake a literal data packet and wait for the next armor line
+ * fixme: empty line handling and null length clear text signature are
+ *       not implemented/checked.
+ */
 static int
 fake_packet( armor_filter_context_t *afx, IOBUF a,
             size_t *retn, byte *buf, size_t size  )
 {
     int rc = 0;
     size_t len = 0;
-    size_t n, nn;
-    fhdr_state_t state = afx->parse_state;
     unsigned emplines = afx->empty;
+    int lastline = 0;
+    unsigned maxlen, n;
+    byte *p;
 
     len = 2;   /* reserve 2 bytes for the length header */
     size -= 3; /* and 1 for empline handling and 2 for the term header */
+               /* or the appended CR,LF */
     while( !rc && len < size ) {
        if( emplines ) {
            while( emplines && len < size ) {
@@ -743,70 +903,98 @@ fake_packet( armor_filter_context_t *afx, IOBUF a,
            }
            continue;
        }
-       if( state == fhdrENDClearsigHelp ) {
-           state = fhdrENDClearsig;
-           afx->faked = 0;
-           rc = -1;
-           continue;
-       }
-       if( state != fhdrNullClearsig
-           && afx->helpidx < afx->helplen ) { /* flush the last buffer */
-           n = afx->helplen;
-           for(nn=afx->helpidx; len < size && nn < n ; nn++ )
-               buf[len++] = afx->helpbuf[nn];
-           afx->helpidx = nn;
-           continue;
+
+       if( afx->faked == 1 )
+           afx->faked++;  /* skip the first (empty) line */
+       else {
+           while( len < size && afx->buffer_pos < afx->buffer_len )
+               buf[len++] = afx->buffer[afx->buffer_pos++];
+           buf[len++] = '\r';
+           buf[len++] = '\n';
+           if( len >= size )
+               continue;
        }
-       if( state == fhdrEOF ) {
-           rc = -1;
+
+       /* read the next line */
+       maxlen = MAX_LINELEN;
+       afx->buffer_pos = 0;
+       afx->buffer_len = iobuf_read_line( a, &afx->buffer,
+                                          &afx->buffer_size, &maxlen );
+       if( !afx->buffer_len ) {
+           rc = -1; /* eof */
            continue;
        }
-       /* read a new one */
-       n = DIM(afx->helpbuf);
-       afx->helpidx = 0;
-       state = find_header( state, afx->helpbuf, &n, a,
-                             state == fhdrNullClearsig? afx->helplen:0,
-                                               &emplines, &afx->hashes,
-                                               afx->only_keyblocks,
-                                               &afx->not_dash_escaped );
-       switch( state) {
-         case fhdrERROR:
-           invalid_armor();
-           break;
-
-         case fhdrEOF:
-           rc = -1;
-           break;
-
-         case fhdrCLEARSIG:
-           BUG();
-
-         case fhdrREADClearsig:
-         case fhdrREADClearsigNext:
-         case fhdrCLEARSIGSimple:
-         case fhdrCLEARSIGSimpleNext:
-           afx->helplen = n;
-           break;
-
-         case fhdrENDClearsig:
-           state = fhdrENDClearsigHelp;
-           afx->helplen = n;
-           break;
-
-         default: BUG();
+       if( !maxlen )
+           afx->truncated++;
+       afx->buffer_len = trim_trailing_spaces( afx->buffer, afx->buffer_len );
+       p = afx->buffer;
+       n = afx->buffer_len;
+
+       if( n > 2 && *p == '-' ) {
+           /* check for dash escaped or armor header */
+           if( p[1] == ' ' && !afx->not_dash_escaped ) {
+               /* issue a warning if it is not regular encoded */
+               if( p[2] != '-' && !( n > 6 && !memcmp(p+2, "From ", 5))) {
+                   log_info(_("invalid dash escaped line: "));
+                   print_string( stderr, p, n, 0 );
+                   putc('\n', stderr);
+               }
+               afx->buffer_pos = 2; /* skip */
+           }
+           else if( n >= 15 &&  p[1] == '-' && p[2] == '-' && p[3] == '-' ) {
+               if( is_armor_header( p, n ) != BEGIN_SIGNATURE ) {
+                   log_info(_("unexpected armor:"));
+                   print_string( stderr, p, n, 0 );
+                   putc('\n', stderr);
+               }
+               lastline = 1;
+               assert( len >= 4 );
+               len -= 2; /* remove the last CR,LF */
+               rc = -1;
+           }
        }
     }
+
     buf[0] = (len-2) >> 8;
     buf[1] = (len-2);
-    if( state == fhdrENDClearsig ) { /* write last (ending) length header */
-       if( buf[0] || buf[1] ) { /* write only if length of text is > 0 */
+    if( lastline ) { /* write last (ending) length header */
+       if( buf[0] && buf[1] ) { /* only if we have some text */
            buf[len++] = 0;
            buf[len++] = 0;
        }
        rc = 0;
+       afx->faked = 0;
+       afx->in_cleartext = 0;
+       /* and now read the header lines */
+       afx->buffer_pos = 0;
+       for(;;) {
+           int i;
+
+           /* read the next line (skip all truncated lines) */
+           do {
+               maxlen = MAX_LINELEN;
+               afx->buffer_len = iobuf_read_line( a, &afx->buffer,
+                                                &afx->buffer_size, &maxlen );
+           } while( !maxlen );
+           p = afx->buffer;
+           n = afx->buffer_len;
+           if( !n ) {
+               rc = -1;
+               break; /* eof */
+           }
+           i = parse_header_line( afx, p , n );
+           if( i <= 0 ) {
+               if( i )
+                   invalid_armor();
+               break;
+           }
+       }
+       afx->inp_checked = 1;
+       afx->crc = CRCINIT;
+       afx->idx = 0;
+       afx->radbuf[0] = 0;
     }
 
-    afx->parse_state = state;
     afx->empty = emplines;
     *retn = len;
     return rc;
@@ -830,9 +1018,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
     idx = afx->idx;
     val = afx->radbuf[0];
     for( n=0; n < size; ) {
-       if( afx->helpidx < afx->helplen )
-           c = afx->helpbuf[afx->helpidx++];
-       else if( (c=iobuf_get(a)) == -1 )
+       if( (c=iobuf_get(a)) == -1 )
            break;
        if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
            continue;
@@ -864,11 +1050,8 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
        afx->any_data = 1;
        afx->inp_checked=0;
        afx->faked = 0;
-       afx->parse_state = 0;
        for(;;) { /* skip lf and pad characters */
-           if( afx->helpidx < afx->helplen )
-               c = afx->helpbuf[afx->helpidx++];
-           else if( (c=iobuf_get(a)) == -1 )
+           if( (c=iobuf_get(a)) == -1 )
                break;
            if( c == '\n' || c == ' ' || c == '\r'
                || c == '\t' || c == '=' )
@@ -889,9 +1072,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                  case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
                  case 3: val |= c&0x3f; mycrc |= val; break;
                }
-               if( afx->helpidx < afx->helplen )
-                   c = afx->helpbuf[afx->helpidx++];
-               else if( (c=iobuf_get(a)) == -1 )
+               if( (c=iobuf_get(a)) == -1 )
                    break;
            } while( ++idx < 4 );
            if( c == -1 ) {
@@ -913,9 +1094,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                for(rc=0;!rc;) {
                    rc = 0 /*check_trailer( &fhdr, c )*/;
                    if( !rc ) {
-                       if( afx->helpidx < afx->helplen )
-                           c = afx->helpbuf[afx->helpidx++];
-                       else if( (c=iobuf_get(a)) == -1 )
+                       if( (c=iobuf_get(a)) == -1 )
                            rc = 2;
                    }
                }
@@ -955,7 +1134,7 @@ armor_filter( void *opaque, int control,
     int  idx, idx2;
     size_t n=0;
     u32 crc;
-  #if 0
+  #if 1
     static FILE *fp ;
 
     if( !fp ) {
@@ -967,7 +1146,14 @@ armor_filter( void *opaque, int control,
     if( DBG_FILTER )
        log_debug("armor-filter: control: %d\n", control );
     if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
-       for( n=0; n < size; n++ ) {
+       n = 0;
+       if( afx->buffer_len ) {
+           for(; n < size && afx->buffer_pos < afx->buffer_len; n++ )
+               buf[n++] = afx->buffer[afx->buffer_pos++];
+           if( afx->buffer_pos >= afx->buffer_len )
+               afx->buffer_len = 0;
+       }
+       for(; n < size; n++ ) {
            if( (c=iobuf_get(a)) == -1 )
                break;
            buf[n] = c & 0xff;
@@ -985,12 +1171,12 @@ armor_filter( void *opaque, int control,
        else if( !afx->inp_checked ) {
            rc = check_input( afx, a );
            if( afx->inp_bypass ) {
-               for( n=0; n < size && n < afx->helplen; n++ )
-                   buf[n] = afx->helpbuf[n];
+               for(n=0; n < size && afx->buffer_pos < afx->buffer_len; n++ )
+                   buf[n++] = afx->buffer[afx->buffer_pos++];
+               if( afx->buffer_pos >= afx->buffer_len )
+                   afx->buffer_len = 0;
                if( !n )
                    rc = -1;
-               assert( n == afx->helplen );
-               afx->helplen = 0;
            }
            else if( afx->faked ) {
                unsigned hashes = afx->hashes;
@@ -1046,7 +1232,7 @@ armor_filter( void *opaque, int control,
        }
        else
            rc = radix64_read( afx, a, &n, buf, size );
-      #if 0
+      #if 1
        if( n )
            if( fwrite(buf, n, 1, fp ) != 1 )
                BUG();
@@ -1181,6 +1367,8 @@ armor_filter( void *opaque, int control,
        }
        else if( !afx->any_data && !afx->inp_bypass )
            log_error(_("no valid OpenPGP data found.\n"));
+       m_free( afx->buffer );
+       afx->buffer = NULL;
     }
     else if( control == IOBUFCTRL_DESC )
        *(char**)buf = "armor_filter";
index 31cc4c5..5aad678 100644 (file)
@@ -266,8 +266,8 @@ handle_compressed( PKT_compressed *cd,
        rc = callback(cd->buf, passthru );
     else
        rc = proc_packets(cd->buf);
-    iobuf_pop_filter( cd->buf, compress_filter, &cfx );
   #if 0
+    iobuf_pop_filter( cd->buf, compress_filter, &cfx );
     if( cd->len )
        iobuf_set_limit( cd->buf, 0 ); /* disable the readlimit */
     else
index 06c686b..d44d6c2 100644 (file)
@@ -79,7 +79,7 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
     cipher_setiv( dfx.cipher_hd, NULL );
 
     if( ed->len ) {
-       iobuf_set_limit( ed->buf, ed->len );
+       /*iobuf_set_limit( ed->buf, ed->len );*/
 
        for(i=0; i < (blocksize+2) && ed->len; i++, ed->len-- )
            temp[i] = iobuf_get(ed->buf);
@@ -100,11 +100,13 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
     }
     iobuf_push_filter( ed->buf, decode_filter, &dfx );
     proc_packets(ed->buf);
+  #if 0
     iobuf_pop_filter( ed->buf, decode_filter, &dfx );
     if( ed->len )
        iobuf_set_limit( ed->buf, 0 ); /* disable the readlimit */
     else
        iobuf_clear_eof( ed->buf );
+  #endif
     ed->buf = NULL;
     cipher_close(dfx.cipher_hd);
     return 0;
index 75d629e..46e3f8a 100644 (file)
@@ -29,23 +29,32 @@ typedef struct {
 } md_filter_context_t;
 
 typedef struct {
-    int status;
-    int what;
-    int only_keyblocks;  /* skip all headers but ".... key block" */
+    /* these fields may be initialized */
+    int what;              /* what kind of armor headers to write */
+    int only_keyblocks;     /* skip all headers but ".... key block" */
+    const char *hdrlines;   /* write these headerlines */
+
+    /* the following fields must be initialized to zero */
+    int inp_checked;       /* set if the input has been checked */
+    int inp_bypass;        /* set if the input is not armored */
+    int in_cleartext;      /* clear text message */
+    int not_dash_escaped;   /* clear text is not dash escaped */
+    int hashes;            /* detected hash algorithms */
+    int faked;             /* we are faking a literal data packet */
+    int truncated;         /* number of truncated lines */
+
+    byte *buffer;          /* malloced buffer */
+    unsigned buffer_size;   /* and size of this buffer */
+    unsigned buffer_len;    /* used length of the buffer */
+    unsigned buffer_pos;    /* read position */
+
     byte radbuf[4];
-    int  idx, idx2;
+    int idx, idx2;
     u32 crc;
-    byte helpbuf[100];
-    int  helpidx, helplen;
-    unsigned empty;    /* empty line counter */
-    int hashes;        /* detected hash algorithms */
-    int faked;
-    int parse_state;
-    int inp_checked;   /* set if inp has been checked */
-    int inp_bypass;    /* set if the input is not armored */
-    int any_data;
-    const char *hdrlines;
-    int not_dash_escaped;
+
+    int status;            /* an internal state flag */
+    int any_data;          /* any valid armored data seen */
+    unsigned empty;        /* empty line counter USED??? */
 } armor_filter_context_t;
 
 
index 6715e0d..aa2a8ce 100644 (file)
@@ -627,6 +627,16 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
 }
 
 /****************
+ * Get the primary secret key and store it into sk
+ * Note: This function does not unprotect the key!
+ */
+int
+get_primary_seckey( PKT_secret_key *sk, u32 *keyid )
+{
+    return lookup_sk( sk, 11, keyid, NULL, 1 );
+}
+
+/****************
  * Check whether the secret key is available
  * Returns: 0 := key is available
  *         G10ERR_NO_SECKEY := not availabe
index 1d1c6c2..4a18b7e 100644 (file)
@@ -138,6 +138,7 @@ int get_pubkey_byname( GETKEY_CTX *rx, PKT_public_key *pk,
 int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
 void get_pubkey_end( GETKEY_CTX ctx );
 int get_seckey( PKT_secret_key *sk, u32 *keyid );
+int get_primary_seckey( PKT_secret_key *sk, u32 *keyid );
 int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
                                                 size_t fprint_len );
 int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
index 1f5f574..06fb92e 100644 (file)
@@ -131,6 +131,7 @@ typedef struct {
     byte    version;
     byte    pubkey_algo;    /* algorithm used for public key scheme */
     byte    pubkey_usage;
+    byte is_primary;
     byte is_protected; /* The secret info is protected and must */
                        /* be decrypted before use, the protected */
                        /* MPIs are simply (void*) pointers to memory */
index 5bee45b..3acce40 100644 (file)
@@ -1201,6 +1201,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
        sk->expiredate = expiredate;
        sk->hdrbytes = hdrlen;
        sk->version = version;
+       sk->is_primary = pkttype == PKT_SECRET_KEY;
        sk->pubkey_algo = algorithm;
        sk->pubkey_usage = 0; /* not yet used */
     }
index 7f975b8..785d21d 100644 (file)
@@ -147,16 +147,25 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode )
 
        if( !get_pubkey( pk, keyid ) ) {
            const char *s = pubkey_algo_to_string( pk->pubkey_algo );
-           tty_printf( _("(%u-bit %s key, ID %08lX, created %s)\n"),
+           tty_printf( _("%u-bit %s key, ID %08lX, created %s"),
                       nbits_from_pk( pk ), s?s:"?", (ulong)keyid[1],
                       strtimestamp(pk->timestamp) );
+           if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
+                                    && keyid[1] != keyid[3] )
+               tty_printf( _(" (main key ID %08lX)"), (ulong)keyid[3] );
+           tty_printf("\n");
        }
+
        tty_printf("\n");
        free_public_key( pk );
     }
     else if( keyid && !next_pw ) {
-       char buf[20];
+       char buf[50];
        sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
+       if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
+                                && keyid[1] != keyid[3] )
+           sprintf( buf+strlen(buf), " %08lX%08lX",
+                                     (ulong)keyid[2], (ulong)keyid[3] );
        write_status_text( STATUS_NEED_PASSPHRASE, buf );
     }
 
index 6c08a6a..f579fc3 100644 (file)
@@ -264,7 +264,7 @@ _("Could not find a valid trust path to the key.  Let's see whether we\n"
     else if( !changed )
        tty_printf(_("No trust values changed.\n\n") );
 
-    return any? 0:-1;
+    return changed? 0:-1;
 }
 
 /****************
index ab750e4..c5c6685 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <assert.h>
 #include "util.h"
 #include "memory.h"
 #include "options.h"
@@ -137,7 +138,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                goto leave;
            }
            if( mfx->md ) {
-               if( convert && clearsig )
+               if( 0 && convert && clearsig )
                    special_md_putc(mfx->md, c, &special_state );
                else
                    md_putc(mfx->md, c );
@@ -157,7 +158,7 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
     else {
        while( (c = iobuf_get(pt->buf)) != -1 ) {
            if( mfx->md ) {
-               if( convert && clearsig )
+               if( 0 && convert && clearsig )
                    special_md_putc(mfx->md, c, &special_state  );
                else
                    md_putc(mfx->md, c );
@@ -173,9 +174,9 @@ handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
                }
            }
        }
-       iobuf_clear_eof(pt->buf);
+       pt->buf = NULL;
     }
-    if( mfx->md && convert && clearsig )
+    if( 0 && mfx->md && convert && clearsig )
        special_md_putc(mfx->md, -1, &special_state  ); /* flush */
 
     if( fp && fp != stdout && fclose(fp) ) {
index 6adfafd..5edebf7 100644 (file)
@@ -44,7 +44,7 @@ do_check( PKT_secret_key *sk )
 
     if( sk->is_protected ) { /* remove the protection */
        DEK *dek = NULL;
-       u32 keyid[2];
+       u32 keyid[4]; /* 4! because we need two of them */
        CIPHER_HANDLE cipher_hd=NULL;
        PKT_secret_key *save_sk;
        char save_iv[8];
@@ -58,6 +58,13 @@ do_check( PKT_secret_key *sk )
            return G10ERR_CIPHER_ALGO;
        }
        keyid_from_sk( sk, keyid );
+       keyid[2] = keyid[3] = 0;
+       if( !sk->is_primary ) {
+           PKT_secret_key *sk2 = m_alloc_clear( sizeof *sk2 );
+           if( !get_primary_seckey( sk2, keyid ) )
+               keyid_from_sk( sk2, keyid+2 );
+           free_secret_key( sk2 );
+       }
        dek = passphrase_to_dek( keyid, sk->protect.algo,
                                 &sk->protect.s2k, 0 );
        cipher_hd = cipher_open( sk->protect.algo,
index 355f6cd..2e9fd47 100644 (file)
@@ -217,6 +217,7 @@ do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest )
 
     result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
                                      mpi_get_nbits(pk->pkey[0]));
+
     ctx.sig = sig;
     ctx.md = digest;
     rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
index 094f23c..b69d6c3 100644 (file)
@@ -389,11 +389,25 @@ tdbio_cancel_transaction()
  **************** cached I/O functions ******************
  ********************************************************/
 
+static void
+cleanup(void)
+{
+    if( lockname ) {
+       release_dotlock(lockname);
+       lockname = NULL;
+    }
+}
+
 int
 tdbio_set_dbname( const char *new_dbname, int create )
 {
     char *fname;
+    static int initialized = 0;
 
+    if( !initialized ) {
+       atexit( cleanup );
+       initialized = 1;
+    }
     fname = new_dbname? m_strdup( new_dbname )
                      : make_filename(opt.homedir, "trustdb.gpg", NULL );
 
@@ -480,14 +494,6 @@ tdbio_get_dbname()
 }
 
 
-static void
-cleanup(void)
-{
-    if( lockname ) {
-       release_dotlock(lockname);
-       lockname = NULL;
-    }
-}
 
 static void
 open_db()
@@ -504,7 +510,6 @@ open_db()
        log_fatal( _("%s: can't open: %s\n"), db_name, strerror(errno) );
     if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
        log_fatal( _("%s: invalid trustdb\n"), db_name );
-    atexit( cleanup );
 }
 
 
index e5452d7..bfe4dfe 100644 (file)
@@ -1,3 +1,7 @@
+Thu Jan  7 18:00:58 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * cipher.h (MD_BUFFER_SIZE): Removed.
+
 Mon Dec 14 21:18:49 CET 1998  Werner Koch  <wk@isil.d.shuttle.de>
 
        * types.h: fix for SUNPRO_C
index 38050ef..9cd5b5f 100644 (file)
@@ -75,15 +75,13 @@ struct cipher_handle_s { char does_not_matter[1]; };
 #define CIPHER_MODE_AUTO_CFB  4
 #define CIPHER_MODE_DUMMY     5  /* used with algo DUMMY for no encryption */
 
-
-#define MD_BUFFER_SIZE 512
-
 typedef struct {
-    byte buffer[MD_BUFFER_SIZE];
-    int  bufcount;
     int  secure;
     FILE  *debug;
     struct md_digest_list_s *list;
+    int  bufcount;
+    int  bufsize;
+    byte buffer[1];
 } *MD_HANDLE;
 
 
@@ -118,9 +116,9 @@ const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen );
 void md_start_debug( MD_HANDLE a, const char *suffix );
 void md_stop_debug( MD_HANDLE a );
 #define md_is_secure(a) ((a)->secure)
-#define md_putc(h,c)                                       \
+#define md_putc(h,c)  \
            do {                                            \
-               if( (h)->bufcount == MD_BUFFER_SIZE )       \
+               if( (h)->bufcount == (h)->bufsize )         \
                    md_write( (h), NULL, 0 );               \
                (h)->buffer[(h)->bufcount++] = (c) & 0xff;  \
            } while(0)
index 6fbed37..266b915 100644 (file)
@@ -158,6 +158,7 @@ void mpi_putbyte( MPI a, unsigned index, int value );
 unsigned mpi_trailing_zeros( MPI a );
 
 /*-- mpi-bit.c --*/
+void mpi_normalize( MPI a );
 unsigned mpi_get_nbits( MPI a );
 int  mpi_test_bit( MPI a, unsigned n );
 void mpi_set_bit( MPI a, unsigned n );
index 2b0d99e..9d79660 100644 (file)
@@ -1,3 +1,10 @@
+Thu Jan  7 18:00:58 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * mpi-bit.c (mpi_normalize): New.
+       (mpi_get_nbits): Normalize the MPI.
+       * mpi-bit.c (mpi_cmp): Normalize the MPI before the compare.
+
+
 Tue Dec  8 13:15:16 CET 1998  Werner Koch  <wk@isil.d.shuttle.de>
 
        * config.links: Moved the case for powerpc*linux
index 8ca5c57..227a929 100644 (file)
@@ -48,7 +48,19 @@ __clz_tab[] =
 #define A_LIMB_1 ((mpi_limb_t)1)
 
 
+/****************
+ * Sometimes we have MSL (most significant limbs) which are 0;
+ * this is for some reasons not good, so this function removes them.
+ */
+void
+mpi_normalize( MPI a )
+{
+    if( mpi_is_protected(a) )
+       return;
 
+    for( ; a->nlimbs && !a->d[a->nlimbs-1]; a->nlimbs-- )
+       ;
+}
 
 
 
@@ -67,6 +79,7 @@ mpi_get_nbits( MPI a )
        return n;
     }
 
+    mpi_normalize( a );
     if( a->nlimbs ) {
        mpi_limb_t alimb = a->d[a->nlimbs-1];
        if( alimb )
index f4dd70e..3c3c76b 100644 (file)
@@ -46,27 +46,28 @@ mpi_cmp_ui( MPI u, unsigned long v )
 int
 mpi_cmp( MPI u, MPI v )
 {
-    mpi_size_t usize = u->nlimbs;
-    mpi_size_t vsize = v->nlimbs;
+    mpi_size_t usize, vsize;
     int cmp;
 
-    /* FIXME: are the numbers always normalized? */
+    mpi_normalize( u );
+    mpi_normalize( v );
+    usize = u->nlimbs;
+    vsize = v->nlimbs;
     if( !u->sign && v->sign )
        return 1;
-    else if( u->sign && !v->sign )
+    if( u->sign && !v->sign )
        return -1;
-    else if( usize != vsize && !u->sign && !v->sign )
+    if( usize != vsize && !u->sign && !v->sign )
        return usize - vsize;
-    else if( usize != vsize && u->sign && v->sign )
+    if( usize != vsize && u->sign && v->sign )
        return vsize + usize;
-    else if( !usize )
+    if( !usize )
        return 0;
-    else if( !(cmp=mpihelp_cmp( u->d, v->d, usize )) )
+    if( !(cmp=mpihelp_cmp( u->d, v->d, usize )) )
        return 0;
-    else if( (cmp < 0?1:0) == (u->sign?1:0))
+    if( (cmp < 0?1:0) == (u->sign?1:0))
        return 1;
-    else
-       return -1;
+    return -1;
 }
 
 
index 4f1fd7b..494ce37 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -513,7 +513,7 @@ msgstr "|N|Die Komprimierverfahren N benutzen"
 
 #: g10/g10.c:254
 msgid "throw keyid field of encrypted packets"
-msgstr "entferne die AbsenderI-ID verschl├╝sselter Pakete"
+msgstr "entferne die Absender-ID verschl├╝sselter Pakete"
 
 #: g10/g10.c:262
 msgid ""
index 217d92e..641d623 100644 (file)
@@ -1,3 +1,11 @@
+Thu Jan  7 18:00:58 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
+
+       * iobuf.c (iobuf_clear_eof): Removed.
+       (underflow): Changed the eof handling.
+       (iobuf_pop_filter): Made static and renamed to pop_filter.
+
+       * iobuf.c (iobuf_read_line): New.
+
 Sun Jan  3 15:28:44 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
 
        * dotlock.c (make_dotlock): print another informal message.
index 67c3c8e..6514c2c 100644 (file)
@@ -1,5 +1,5 @@
 /* [argparse.c wk 17.06.97] Argument Parser for option handling
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
  *  This file is part of GnuPG.
  *
  *  GnuPG is free software; you can redistribute it and/or modify
@@ -873,7 +873,7 @@ default_strusage( int level )
     switch( level ) {
       case 11: p = "foo"; break;
       case 13: p = "0.0"; break;
-      case 14: p = "Copyright (C) 1998 Free Software Foundation, Inc."; break;
+      case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break;
       case 15: p =
 "This program comes with ABSOLUTELY NO WARRANTY.\n"
 "This is free software, and you are welcome to redistribute it\n"
index 25bd154..755da1d 100644 (file)
@@ -1,5 +1,5 @@
 /* iobuf.c  -  file handling
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -434,7 +434,7 @@ iobuf_close( IOBUF a )
     if( a && a->directfp ) {
        fclose( a->directfp );
        if( DBG_IOBUF )
-           log_debug("iobuf-close -> %p\n", a->directfp );
+           log_debug("iobuf_close -> %p\n", a->directfp );
        return 0;
     }
 
@@ -722,9 +722,10 @@ iobuf_push_filter( IOBUF a,
 
 /****************
  * Remove an i/o filter.
+ * Only needed for iobuf_seek?
  */
-int
-iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
+static int
+pop_filter( IOBUF a, int (*f)(void *opaque, int control,
                      IOBUF chain, byte *buf, size_t *len), void *ov )
 {
     IOBUF b;
@@ -798,16 +799,26 @@ underflow(IOBUF a)
     size_t len;
     int rc;
 
-  /*log_debug("iobuf-%d.%d: underflow: start=%lu len=%lu\n",
-               a->no, a->subno, (ulong)a->d.start, (ulong)a->d.len );*/
     assert( a->d.start == a->d.len );
     if( a->usage == 3 )
        return -1; /* EOF because a temp buffer can't do an underflow */
 
     if( a->filter_eof ) {
+       if( a->chain ) {
+           IOBUF b = a->chain;
+           m_free(a->d.buf);
+           memcpy(a, b, sizeof *a);
+           m_free(b);
+           if( DBG_IOBUF )
+               log_debug("iobuf-%d.%d: popped filter in underflow\n",
+                                                        a->no, a->subno );
+       }
+       else
+           a->filter_eof = 0;
        if( DBG_IOBUF )
-           log_debug("iobuf-%d.%d: filter eof\n", a->no, a->subno );
-       return -1;
+           log_debug("iobuf-%d.%d: underflow: eof (due to filter eof)\n",
+                                                   a->no, a->subno );
+       return -1; /* return one(!) EOF */
     }
     if( a->error ) {
        if( DBG_IOBUF )
@@ -822,8 +833,6 @@ underflow(IOBUF a)
        if( len < a->d.size ) {
            if( ferror(fp) )
                a->error = 1;
-           else if( feof( fp ) )
-               a->filter_eof = 1;
        }
        a->d.len = len;
        a->d.start = 0;
@@ -835,47 +844,48 @@ underflow(IOBUF a)
        len = a->d.size;
        rc = a->filter( a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain,
                        a->d.buf, &len );
+       if( DBG_IOBUF )
+           log_debug("iobuf-%d.%d: underflow: req=%lu got=%lu rc=%d\n",
+                   a->no, a->subno, (ulong)a->d.size, (ulong)len, rc );
        if( a->usage == 1 && rc == -1 ) { /* EOF: we can remove the filter */
            size_t dummy_len;
 
-           /* and tell the filter to free it self */
-           if( a->filter != file_filter ) {
-               if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
-                                  NULL, &dummy_len)) )
-                   log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
-               a->filter = NULL;
-               a->desc = NULL;
-               a->filter_ov = NULL;
-           }
+           /* and tell the filter to free itself */
+           if( (rc = a->filter(a->filter_ov, IOBUFCTRL_FREE, a->chain,
+                              NULL, &dummy_len)) )
+               log_error("IOBUFCTRL_FREE failed: %s\n", g10_errstr(rc) );
+           a->filter = NULL;
+           a->desc = NULL;
+           a->filter_ov = NULL;
            a->filter_eof = 1;
+           if( !len && a->chain ) {
+               IOBUF b = a->chain;
+               m_free(a->d.buf);
+               memcpy(a,b, sizeof *a);
+               m_free(b);
+               if( DBG_IOBUF )
+                   log_debug("iobuf-%d.%d: popped filter in underflow (!len)\n",
+                                                            a->no, a->subno );
+           }
        }
        else if( rc )
            a->error = 1;
 
-       if( !len )
+       if( !len ) {
+           if( DBG_IOBUF )
+               log_debug("iobuf-%d.%d: underflow: eof\n", a->no, a->subno );
            return -1;
+       }
        a->d.len = len;
        a->d.start = 0;
        return a->d.buf[a->d.start++];
     }
-    else
+    else {
+       if( DBG_IOBUF )
+           log_debug("iobuf-%d.%d: underflow: eof (no filter)\n",
+                                                   a->no, a->subno );
        return -1;  /* no filter; return EOF */
-}
-
-
-void
-iobuf_clear_eof(IOBUF a)
-{
-    if( a->directfp )
-       return;
-
-    assert(a->usage == 1);
-
-    if( a->filter )
-       log_info("iobuf-%d.%d: clear_eof `%s' with enabled filter\n", a->no, a->subno, a->desc );
-    if( !a->filter_eof )
-       log_info("iobuf-%d.%d: clear_eof `%s' with no EOF pending\n", a->no, a->subno, a->desc );
-    iobuf_pop_filter(a, NULL, NULL);
+    }
 }
 
 
@@ -1209,8 +1219,10 @@ iobuf_seek( IOBUF a, ulong newpos )
     a->ntotal = newpos;
     a->error = 0;
     /* remove filters, but the last */
+    if( a->chain )
+       log_debug("pop_filter called in iobuf_seek - please report\n");
     while( a->chain )
-       iobuf_pop_filter( a, a->filter, NULL );
+       pop_filter( a, a->filter, NULL );
 
     return 0;
 }
@@ -1263,7 +1275,8 @@ iobuf_set_block_mode( IOBUF a, size_t n )
     assert( a->usage == 1 || a->usage == 2 );
     ctx->usage = a->usage;
     if( !n ) {
-       iobuf_pop_filter(a, block_filter, NULL );
+       log_debug("pop_filter called in set_block_mode - please report\n");
+       pop_filter(a, block_filter, NULL );
     }
     else {
        ctx->size = n; /* only needed for usage 2 */
@@ -1283,7 +1296,8 @@ iobuf_set_partial_block_mode( IOBUF a, size_t len )
     assert( a->usage == 1 || a->usage == 2 );
     ctx->usage = a->usage;
     if( !len ) {
-       iobuf_pop_filter(a, block_filter, NULL );
+       log_debug("pop_filter called in set_partial_block_mode - please report\n");
+       pop_filter(a, block_filter, NULL );
     }
     else {
        ctx->partial = 1;
@@ -1307,4 +1321,62 @@ iobuf_in_block_mode( IOBUF a )
 }
 
 
+/****************
+ * Same as fgets() but if the buffer is too short a larger one will
+ * be allocated up to some limit *max_length.
+ * A line is considered a byte stream ending in a LF.
+ * Returns the length of the line. EOF is indicated by a line of
+ * length zero. The last LF may be missing due to an EOF.
+ * is max_length is zero on return, the line has been truncated.
+ *
+ * Note: The buffer is allocated with enough space to append a CR,LF,EOL
+ */
+unsigned
+iobuf_read_line( IOBUF a, byte **addr_of_buffer,
+                         unsigned *length_of_buffer, unsigned *max_length )
+{
+    int c;
+    char *buffer = *addr_of_buffer;
+    unsigned length = *length_of_buffer;
+    unsigned nbytes = 0;
+    unsigned maxlen = *max_length;
+    char *p;
+
+    if( !buffer ) { /* must allocate a new buffer */
+       length = 256;
+       buffer = m_alloc( length );
+       *addr_of_buffer = buffer;
+       *length_of_buffer = length;
+    }
+
+    length -= 3; /* reserve 3 bytes (cr,lf,eol) */
+    p = buffer;
+    while( (c=iobuf_get(a)) != -1 ) {
+       if( nbytes == length ) { /* increase the buffer */
+           if( length > maxlen  ) { /* this is out limit */
+               /* skip the rest of the line */
+               while( c != '\n' && (c=iobuf_get(a)) != -1 )
+                   ;
+               *p++ = '\n'; /* always append a LF (we have reserved space) */
+               nbytes++;
+               *max_length = 0; /* indicate truncation */
+               break;
+           }
+           length += 3; /* correct for the reserved byte */
+           length += length < 1024? 256 : 1024;
+           buffer = m_realloc( buffer, length );
+           *addr_of_buffer = buffer;
+           *length_of_buffer = length;
+           length -= 3; /* and reserve again */
+           p = buffer + nbytes;
+       }
+       *p++ = c;
+       nbytes++;
+       if( c == '\n' )
+           break;
+    }
+    *p = 0; /* make sure the line is a string */
+
+    return nbytes;
+}