added some stuff for signing keys
authorWerner Koch <wk@gnupg.org>
Tue, 16 Dec 1997 19:15:09 +0000 (19:15 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 16 Dec 1997 19:15:09 +0000 (19:15 +0000)
27 files changed:
INSTALL
README
TODO
cipher/Makefile.am
cipher/Makefile.in
configure.in
g10/encode.c
g10/g10.c
g10/getkey.c
g10/kbnode.c
g10/keydb.h
g10/keygen.c
g10/keyid.c
g10/main.h
g10/mainproc.c
g10/options.h
g10/ringedit.c
g10/seskey.c
include/iobuf.h
include/ttyio.h
mpi/Makefile.am
mpi/Makefile.in
mpi/config.links [new file with mode: 0644]
util/argparse.c
util/iobuf.c
util/miscutil.c
util/ttyio.c

diff --git a/INSTALL b/INSTALL
index e69de29..2fb9f98 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -0,0 +1,26 @@
+
+    1) Configure for your machine:
+
+        ./configure
+
+       or use
+
+        ./configure --enable-m-debug
+
+       to ebanle the integrated malloc debugging stuff.
+
+
+    2) Run make:
+
+       make
+
+
+    3) Install
+
+       make install
+
+
+    4) You end up with a binary "g10" in /usr/local/bin
+
+
+
diff --git a/README b/README
index e69de29..9318390 100644 (file)
--- a/README
+++ b/README
@@ -0,0 +1,50 @@
+
+            G10 - The GNU Enryption and Signing Tool
+           ------------------------------------------
+
+
+    THIS IS VERSION IS ONLY a TEST VERSION !  YOU SHOULD NOT
+    USE IT FOR OTHER PURPOSES THAN EVALUATING THE CURRENT CODE.
+
+    * The data format may change in the next version!
+
+    * The code to generate keys is not secure!
+
+    * Some features are not implemented
+
+
+    I provide this version as a reality check to start discussion.
+    Please subscribe to g10@net.lut.ac.uk be sending a mail with
+    the word "subscribe" in the body to "g10-request@net.lut.ac.uk".
+
+
+    See the file COPYING for copyright and warranty information.
+
+
+    Due to the fact that G10 does not use use any patented algorithm,
+    it cannot be compatible to old PGP versions, because those use
+    IDEA (which is worldwide patented) and RSA (which is patented in
+    the United States until Sep 20, 2000).  I'm sorry about this, but
+    this is the world we have created (e.g. by using propiertary software).
+
+
+    Because the OpenPGP standard is still a draft, G10 is not yet
+    compatible to it (or PGP 5) - but it will. The data structures
+    used are compatible with PGP 2.x, so it can parse an list such files
+    and PGP should be able to parse data created by G10 and complain
+    about unsupported alogorithms.
+
+    The default algorithms used by G10 are ElGamal for public-key
+    encryption and signing; Blowfish with a 160 bit key for protecting
+    the secret-key components, conventional and session encryption;
+    RIPE MD-160 to create message digest.  DSA, SHA-1 and CAST are
+    also implemented, but not used on default. I decided not
+    to use DSA as default signing algorithm, cecause it allows only for
+    1024 bit keys and this may be not enough in a couple of years.
+
+    Key generation takes a long time and should be improved!
+
+
+
+
+
diff --git a/TODO b/TODO
index 486b40f..4291480 100644 (file)
--- a/TODO
+++ b/TODO
@@ -8,14 +8,10 @@
     * keyring editing
     * add trust stuff
     * make ttyio.c work (hide passwords etc..)
-    * add option file handling.
     * use correct ASN values for DEK encoding
     * add checking of armor trailers
     * add real secure memory
     * look for a way to reuse RSA signatures
-    * find a way to remove the armor filter after it
-      has detected, that the data is not armored.
-    * Use the Chinese Remainder Theorem to speed up RSA calculations.
     * remove all "Fixmes"
     * speed up the RIPE-MD-160
     * add signal handling
     * complete cipher/cast.c
     * complete cipher/dsa.c
 
+    * define a standard way to specify keyid/userid and other stuff
+      to identify a user.  We could look at the first character and
+      say: If it's a digit, a keyid follows (need to add a zero in
+      case the keyid starts with A..F); if it is a left angle bracket,
+      this is a email address and should be used, all others are substrings
+      of the userid.
+      [can be handles in get_pubkey_by_name()]
+
index 40b131d..52de7fa 100644 (file)
@@ -24,6 +24,6 @@ cipher_SOURCES = blowfish.c   \
                 md.c           \
                 smallprime.c
 
-cipher_LIBADD = rsa.o
+##cipher_LIBADD = rsa.o
 
 
index 8391d9e..2747e16 100644 (file)
@@ -60,8 +60,6 @@ cipher_SOURCES = blowfish.c   \
                 dsa.c          \
                 md.c           \
                 smallprime.c
-
-cipher_LIBADD = rsa.o
 mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
 CONFIG_HEADER = ../config.h
 LIBRARIES = $(noinst_LIBRARIES)
@@ -80,6 +78,7 @@ LIBS = @LIBS@
 
 COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
 LINK = $(CC) $(LDFLAGS) -o $@
+cipher_LIBADD =
 cipher_OBJECTS = blowfish.o elgamal.o gost.o md5.o primegen.o random.o \
 rmd160.o sha1.o dsa.o md.o smallprime.o
 EXTRA_cipher_SOURCES =
index 4575bc8..2c09e1a 100644 (file)
@@ -22,21 +22,20 @@ fi
 CFLAGS="-g"
 
 dnl
-AC_CANONICAL_HOST
+AC_CANONICAL_SYSTEM
 AC_MSG_CHECKING(cached information)
-hostcheck="$host"
+hostcheck="$target"
 AC_CACHE_VAL(ac_cv_mpi_hostcheck, [ ac_cv_mpi_hostcheck="$hostcheck" ])
 if test "$ac_cv_mpi_hostcheck" != "$hostcheck"; then
     AC_MSG_RESULT(changed)
     AC_MSG_WARN(config.cache exists!)
     AC_MSG_ERROR(you must do 'make distclean' first to compile for
-different host or different parameters.)
+different target or different parameters.)
 else
     AC_MSG_RESULT(ok)
 fi
 
 
-
 dnl Checks for programs.
 
 AC_PROG_MAKE_SET
@@ -71,8 +70,12 @@ AC_CHECK_FUNCS(strerror strtol strtoul)
 
 
 dnl setup assembler stuff
-
-
+if test -f ./mpi/config.links ; then
+    . ./mpi/config.links
+    AC_LINK_FILES( ${mpi_ln_src}, ${mpi_ln_dst} )
+else
+    AC_MSG_ERROR([mpi/config.links missing!])
+fi
 
 
 
@@ -91,6 +94,7 @@ fi
 AC_SUBST(add_cipher_SOURCES)
 
 AC_OUTPUT([ Makefile scripts/Makefile util/Makefile mpi/Makefile \
+           mpi/generic/Makefile mpi/i386/Makefile \
            cipher/Makefile \
            include/Makefile \
            g10/Makefile tools/Makefile ],
index 3bcdbe9..53d03c0 100644 (file)
@@ -218,7 +218,7 @@ encode_crypt( const char *filename, STRLIST remusr )
        pkc = m_alloc_clear( sizeof *pkc );
        pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
 
-       if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
+       if( (rc = get_pubkey_byname( pkc, remusr->d )) ) {
            last_rc = rc;
            log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
            continue;
index 495875c..777220a 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -125,20 +125,21 @@ main( int argc, char **argv )
     { 510, "debug"     ,4|16, "set debugging flags" },
     { 511, "debug-all" ,0, "enable full debugging"},
     { 512, "cache-all" ,0, "hold everything in memory"},
-    { 513, "gen-prime" , 1, "\rgenerate a prime of length n" },
-    { 514, "test"      , 0, "\rdevelopment usage" },
+    { 513, "gen-prime" , 1, "\r" },
+    { 514, "test"      , 0, "\r" },
     { 515, "change-passphrase", 0, "change the passphrase of your secret keyring"},
     { 515, "fingerprint", 0, "show the fingerprints"},
     { 516, "print-mds" , 0, "print all message digests"},
     { 517, "secret-keyring" ,2, "add this secret keyring to the list" },
     { 518, "config"    , 2, "use this config file" },
+    { 519, "no-armor",   0, "\r"},
 
     {0} };
     ARGPARSE_ARGS pargs;
     IOBUF a;
     int rc;
     enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr,
-          aTest, aPrintMDs,
+          aTest, aPrintMDs, aSignKey,
     } action = aNull;
     int orig_argc;
     char **orig_argv;
@@ -189,7 +190,7 @@ main( int argc, char **argv )
        configfp = fopen( configname, "r" );
        if( !configfp ) {
            if( default_config ) {
-               if( parse_verbose )
+               if( parse_verbose > 1 )
                log_info("note: no default option file '%s'\n", configname );
            }
            else
@@ -197,7 +198,7 @@ main( int argc, char **argv )
                                    configname, strerror(errno) );
            m_free(configname); configname = NULL;
        }
-       if( parse_verbose )
+       if( parse_verbose > 1 )
            log_info("reading options from '%s'\n", configname );
        default_config = 0;
     }
@@ -209,7 +210,7 @@ main( int argc, char **argv )
                    opt.list_sigs=1;
                    break;
          case 'z': opt.compress = pargs.r.ret_int; break;
-         case 'a': opt.armor = 1; break;
+         case 'a': opt.armor = 1; opt.no_armor=0; break;
          case 'c': action = aSym; break;
          case 'o': opt.outfile = pargs.r.ret_str;
                    if( opt.outfile[0] == '-' && !opt.outfile[1] )
@@ -235,6 +236,7 @@ main( int argc, char **argv )
          case 501: opt.answer_yes = 1; break;
          case 502: opt.answer_no = 1; break;
          case 503: action = aKeygen; break;
+         case 506: action = aSignKey; break;
          case 507: action = aStore; break;
          case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
          case 509: add_keyring(pargs.r.ret_str); nrings++; break;
@@ -254,6 +256,7 @@ main( int argc, char **argv )
                goto next_pass;
            }
            break;
+         case 519: opt.no_armor=1; opt.armor=0; break;
          default : errors++; pargs.err = configfp? 1:2; break;
        }
     }
@@ -270,7 +273,7 @@ main( int argc, char **argv )
     set_debug();
     if( opt.verbose > 1 )
        set_packet_list_mode(1);
-    if( !opt.batch && isatty(fileno(stdin)) ) {
+    if( opt.verbose && isatty(fileno(stdin)) ) {
        if( *(s=strusage(10))  )
            fputs(s, stderr);
        if( *(s=strusage(30))  )
@@ -278,11 +281,14 @@ main( int argc, char **argv )
     }
 
     if( !sec_nrings ) { /* add default secret rings */
-       add_keyring("../keys/secring.g10");
+       char *p = make_filename("~/.g10", "secring.g10", NULL );
+       add_secret_keyring(p);
+       m_free(p);
     }
-    if( !nrings ) { /* add default rings */
-       add_keyring("../keys/ring.pgp");
-       add_keyring("../keys/pubring.g10");
+    if( !nrings ) { /* add default ring */
+       char *p = make_filename("~/.g10", "pubring.g10", NULL );
+       add_keyring(p);
+       m_free(p);
     }
 
     if( argc ) {
@@ -323,10 +329,21 @@ main( int argc, char **argv )
            log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
        break;
 
+
       case aSignEncr: /* sign and encrypt the given file */
        usage(1);  /* FIXME */
        break;
 
+
+      case aSignKey: /* sign the key given as argument */
+       if( argc != 1 )
+           usage(1);
+       /* note: fname is the user id! */
+       if( (rc = sign_key(fname, locusr)) )
+           log_error("sign_key('%s'): %s\n", fname_print, g10_errstr(rc) );
+       break;
+
+
       case aPrimegen:
        if( argc )
            usage(1);
@@ -356,9 +373,11 @@ main( int argc, char **argv )
            usage(1);
        if( !(a = iobuf_open(fname)) )
            log_fatal("can't open '%s'\n", fname_print);
-       /* push the armor filter, so it can peek at the input data */
-       memset( &afx, 0, sizeof afx);
-       iobuf_push_filter( a, armor_filter, &afx );
+       if( !opt.no_armor ) {
+           /* push the armor filter, so it can peek at the input data */
+           memset( &afx, 0, sizeof afx);
+           iobuf_push_filter( a, armor_filter, &afx );
+       }
        proc_packets( a );
        iobuf_close(a);
        break;
index b079cca..67b86cc 100644 (file)
@@ -83,9 +83,9 @@ add_keyring( const char *name )
      * combine it with the keyblock stuff from ringedit.c
      * For now we will simple add the filename as keyblock resource
      */
-    rc = add_keyblock_resource( name );
+    rc = add_keyblock_resource( name, 0 );
     if( rc )
-       log_error("keyblock resource '%s': %s\n", name, rc );
+       log_error("keyblock resource '%s': %s\n", name, g10_errstr(rc) );
 }
 
 void
@@ -245,7 +245,7 @@ get_pubkey( PKT_public_cert *pkc, u32 *keyid )
  * a pubkey with that algo.
  */
 int
-get_pubkey_by_name( PKT_public_cert *pkc, const char *name )
+get_pubkey_byname( PKT_public_cert *pkc, const char *name )
 {
     int internal = 0;
     int rc = 0;
@@ -304,7 +304,7 @@ get_seckey( PKT_secret_cert *skc, u32 *keyid )
  * If NAME is NULL use the default certificate
  */
 int
-get_seckey_by_name( PKT_secret_cert *skc, const char *name )
+get_seckey_byname( PKT_secret_cert *skc, const char *name, int unprotect )
 {
     STRLIST sl;
     int rc=0;
@@ -319,8 +319,9 @@ get_seckey_by_name( PKT_secret_cert *skc, const char *name )
     /* get the secret key (this may prompt for a passprase to
      * unlock the secret key
      */
-    if( (rc = check_secret_key( skc )) )
-       goto leave;
+    if( unprotect )
+       if( (rc = check_secret_key( skc )) )
+           goto leave;
 
   leave:
     return rc;
index d148cb4..a4ac40d 100644 (file)
@@ -57,6 +57,36 @@ release_kbnode( KBNODE n )
 
 
 /****************
+ * Append NODE to ROOT, ROOT must exist!
+ */
+void
+add_kbnode( KBNODE root, KBNODE node )
+{
+    KBNODE n1;
+
+    for(n1=root; n1->next; n1 = n1->next)
+       ;
+    n1->next = node;
+}
+
+/****************
+ * Append NODE to ROOT as child of ROOT
+ */
+void
+add_kbnode_as_child( KBNODE root, KBNODE node )
+{
+    KBNODE n1;
+
+    if( !(n1=root->child) )
+       root->child = node;
+    else {
+       for( ; n1->next; n1 = n1->next)
+           ;
+       n1->next = node;
+    }
+}
+
+/****************
  * Return the parent node of KBNODE from the tree with ROOT
  */
 KBNODE
@@ -72,8 +102,39 @@ find_kbparent( KBNODE root, KBNODE node )
            }
        }
     }
-    log_bug(NULL);
+    return NULL;
 }
 
 
+/****************
+ * Walk through a tree of kbnodes. This functions returns
+ * the next kbnode for each call; before using the function the first
+ * time, the caller must set CONTEXT to NULL (This has simply the effect
+ * to start with ROOT).
+ */
+KBNODE
+walk_kbtree( KBNODE root, KBNODE *context )
+{
+    KBNODE n;
+
+    if( !*context ) {
+       *context = root;
+       return root;
+    }
+
+    n = *context;
+    if( n->child ) {
+       n = n->child;
+       *context = n;
+    }
+    else if( n->next ) {
+       n = n->next;
+       *context = n;
+    }
+    else if( (n = find_kbparent( root, n )) ) {
+       n = n->next;
+       *context = n;
+    }
+    return n;
+}
 
index a81b258..58e62da 100644 (file)
@@ -66,13 +66,14 @@ void add_secret_keyring( const char *name );
 void cache_public_cert( PKT_public_cert *pkc );
 void cache_user_id( PKT_user_id *uid, u32 *keyid );
 int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
-int get_pubkey_by_name( PKT_public_cert *pkc, const char *name );
+int get_pubkey_byname( PKT_public_cert *pkc, const char *name );
 int get_seckey( PKT_secret_cert *skc, u32 *keyid );
-int get_seckey_by_name( PKT_secret_cert *skc, const char *name );
+int get_seckey_byname( PKT_secret_cert *skc, const char *name, int unlock );
 char*get_user_id_string( u32 *keyid );
 char*get_user_id( u32 *keyid, size_t *rn );
 
 /*-- keyid.c --*/
+int pubkey_letter( int algo );
 u32 keyid_from_skc( PKT_secret_cert *skc, u32 *keyid );
 u32 keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid );
 u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
@@ -87,14 +88,18 @@ byte *fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len );
 /*-- kbnode.c --*/
 KBNODE new_kbnode( PACKET *pkt );
 void release_kbnode( KBNODE n );
+void add_kbnode( KBNODE root, KBNODE node );
+void add_kbnode_as_child( KBNODE root, KBNODE node );
 KBNODE find_kbparent( KBNODE root, KBNODE node );
+KBNODE walk_kbtree( KBNODE root, KBNODE *context );
 
 /*-- ringedit.c --*/
-int add_keyblock_resource( const char *filename );
+int add_keyblock_resource( const char *filename, int force );
 int get_keyblock_handle( const char *filename, KBPOS *kbpos );
 int search_keyblock( PACKET *pkt, KBPOS *kbpos );
+int search_keyblock_byname( KBPOS *kbpos, const char *username );
 int lock_keyblock( KBPOS *kbpos );
-int unlock_keyblock( KBPOS *kbpos );
+void unlock_keyblock( KBPOS *kbpos );
 int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
 int insert_keyblock( KBPOS *kbpos, KBNODE root );
 int delete_keyblock( KBPOS *kbpos );
index a4ed697..47bc2b1 100644 (file)
@@ -30,6 +30,7 @@
 #include "cipher.h"
 #include "ttyio.h"
 #include "options.h"
+#include "keydb.h"
 
 #if 0
   #define TEST_ALGO  1
@@ -88,52 +89,128 @@ checksum_mpi( MPI a )
 
 
 static void
-write_uid( IOBUF out, const char *s, PKT_user_id **upkt )
+write_uid( KBNODE root, const char *s )
 {
-    PACKET pkt;
+    PACKET *pkt = m_alloc_clear(sizeof *pkt );
     size_t n = strlen(s);
-    int rc;
 
-    pkt.pkttype = PKT_USER_ID;
-    pkt.pkt.user_id = m_alloc( sizeof *pkt.pkt.user_id + n - 1 );
-    pkt.pkt.user_id->len = n;
-    strcpy(pkt.pkt.user_id->name, s);
-    if( (rc = build_packet( out, &pkt )) )
-       log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) );
-    if( upkt ) {
-       *upkt = pkt.pkt.user_id;
-       pkt.pkt.user_id = NULL;
-    }
-    free_packet( &pkt );
+    pkt->pkttype = PKT_USER_ID;
+    pkt->pkt.user_id = m_alloc( sizeof *pkt->pkt.user_id + n - 1 );
+    pkt->pkt.user_id->len = n;
+    strcpy(pkt->pkt.user_id->name, s);
+    add_kbnode( root, new_kbnode( pkt ) );
 }
 
 
 static int
-write_selfsig( IOBUF out, PKT_public_cert *pkc, PKT_user_id *uid,
-                                               PKT_secret_cert *skc )
+write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc )
 {
-    PACKET pkt;
+    PACKET *pkt;
     PKT_signature *sig;
+    PKT_user_id *uid;
     int rc=0;
+    KBNODE kbctx, node;
+    PKT_public_cert *pkc;
 
     if( opt.verbose )
        log_info("writing self signature\n");
 
+    /* get the uid packet from the tree */
+    for( kbctx=NULL; (node=walk_kbtree( root, &kbctx)) ; ) {
+       if( node->pkt->pkttype == PKT_USER_ID )
+           break;
+    }
+    if( !node )
+       log_bug(NULL); /* no user id packet in tree */
+    uid = node->pkt->pkt.user_id;
+    /* get the pkc packet from the pub_tree */
+    for( kbctx=NULL; (node=walk_kbtree( pub_root, &kbctx)) ; ) {
+       if( node->pkt->pkttype == PKT_PUBLIC_CERT )
+           break;
+    }
+    if( !node )
+       log_bug(NULL);
+    pkc = node->pkt->pkt.public_cert;
+
+    /* and make the signature */
     rc = make_keysig_packet( &sig, pkc, uid, skc, 0x13, DIGEST_ALGO_RMD160 );
     if( rc ) {
        log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
        return rc;
     }
 
-    pkt.pkttype = PKT_SIGNATURE;
-    pkt.pkt.signature = sig;
-    if( (rc = build_packet( out, &pkt )) )
-       log_error("build_packet(signature) failed: %s\n", g10_errstr(rc) );
-    free_packet( &pkt );
+    pkt = m_alloc_clear( sizeof *pkt );
+    pkt->pkttype = PKT_SIGNATURE;
+    pkt->pkt.signature = sig;
+    add_kbnode( root, new_kbnode( pkt ) );
     return rc;
 }
 
 
+static int
+gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+       PKT_secret_cert **ret_skc )
+{
+    int rc;
+    PACKET *pkt;
+    PKT_secret_cert *skc;
+    PKT_public_cert *pkc;
+    ELG_public_key pk;
+    ELG_secret_key sk;
+    unsigned nbytes;
+
+    elg_generate( &pk, &sk, nbits );
+
+    skc = m_alloc( sizeof *skc );
+    pkc = m_alloc( sizeof *pkc );
+    skc->timestamp = pkc->timestamp = make_timestamp();
+    skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
+    skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL;
+                      memset(&pkc->mfx, 0, sizeof pkc->mfx);
+                      pkc->d.elg.p = pk.p;
+                      pkc->d.elg.g = pk.g;
+                      pkc->d.elg.y = pk.y;
+    skc->d.elg.p = sk.p;
+    skc->d.elg.g = sk.g;
+    skc->d.elg.y = sk.y;
+    skc->d.elg.x = sk.x;
+
+    skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
+    /* return an unprotected version of the skc */
+    *ret_skc = copy_secret_cert( NULL, skc );
+
+    if( !dek ) {
+       skc->d.elg.is_protected = 0;
+       skc->d.elg.protect_algo = 0;
+    }
+    else {
+       skc->d.elg.is_protected = 0;
+       skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
+       randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
+       rc = protect_secret_key( skc, dek );
+       if( rc ) {
+           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
+           free_public_cert(pkc);
+           free_secret_cert(skc);
+           return rc;
+       }
+    }
+
+    pkt = m_alloc_clear(sizeof *pkt);
+    pkt->pkttype = PKT_PUBLIC_CERT;
+    pkt->pkt.public_cert = pkc;
+    add_kbnode(pub_root, new_kbnode( pkt ));
+
+    pkt = m_alloc_clear(sizeof *pkt);
+    pkt->pkttype = PKT_SECRET_CERT;
+    pkt->pkt.secret_cert = skc;
+    add_kbnode(sec_root, new_kbnode( pkt ));
+
+    return 0;
+}
+
+
+
 #ifdef HAVE_RSA_CIPHER
 static int
 gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
@@ -210,79 +287,12 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
 }
 #endif /*HAVE_RSA_CIPHER*/
 
+
 static int
-gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
-       PKT_public_cert **ret_pkc, PKT_secret_cert **ret_skc )
+gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+       PKT_secret_cert **ret_skc )
 {
-    int rc;
-    PACKET pkt1, pkt2;
-    PKT_secret_cert *skc, *unprotected_skc;
-    PKT_public_cert *pkc;
-    ELG_public_key pk;
-    ELG_secret_key sk;
-    unsigned nbytes;
-
-    init_packet(&pkt1);
-    init_packet(&pkt2);
-
-    elg_generate( &pk, &sk, nbits );
-
-    skc = m_alloc( sizeof *skc );
-    pkc = m_alloc( sizeof *pkc );
-    skc->timestamp = pkc->timestamp = make_timestamp();
-    skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
-    skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_ELGAMAL;
-                      memset(&pkc->mfx, 0, sizeof pkc->mfx);
-                      pkc->d.elg.p = pk.p;
-                      pkc->d.elg.g = pk.g;
-                      pkc->d.elg.y = pk.y;
-    skc->d.elg.p = sk.p;
-    skc->d.elg.g = sk.g;
-    skc->d.elg.y = sk.y;
-    skc->d.elg.x = sk.x;
-
-    skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
-    unprotected_skc = copy_secret_cert( NULL, skc );
-    if( !dek ) {
-       skc->d.elg.is_protected = 0;
-       skc->d.elg.protect_algo = 0;
-    }
-    else {
-       skc->d.elg.is_protected = 0;
-       skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
-       randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
-       rc = protect_secret_key( skc, dek );
-       if( rc ) {
-           log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
-           goto leave;
-       }
-    }
-
-    pkt1.pkttype = PKT_PUBLIC_CERT;
-    pkt1.pkt.public_cert = pkc;
-    pkt2.pkttype = PKT_SECRET_CERT;
-    pkt2.pkt.secret_cert = skc;
-
-    if( (rc = build_packet( pub_io, &pkt1 )) ) {
-       log_error("build public_cert packet failed: %s\n", g10_errstr(rc) );
-       goto leave;
-    }
-    if( (rc = build_packet( sec_io, &pkt2 )) ) {
-       log_error("build secret_cert packet failed: %s\n", g10_errstr(rc) );
-       goto leave;
-    }
-    *ret_pkc = pkt1.pkt.public_cert;
-    pkt1.pkt.public_cert = NULL;
-    *ret_skc = unprotected_skc;
-    unprotected_skc = NULL;
-
-
-  leave:
-    free_packet(&pkt1);
-    free_packet(&pkt2);
-    if( unprotected_skc )
-       free_secret_cert( unprotected_skc );
-    return rc;
+    return G10ERR_GENERAL;
 }
 
 
@@ -295,14 +305,14 @@ generate_keypair()
 {
     char *answer;
     unsigned nbits;
-    char *pub_fname = "./pubring.g10";
-    char *sec_fname = "./secring.g10";
+    char *pub_fname = NULL;
+    char *sec_fname = NULL;
     char *uid = NULL;
     IOBUF pub_io = NULL;
     IOBUF sec_io = NULL;
-    PKT_public_cert *pkc = NULL;
+    KBNODE pub_root = NULL;
+    KBNODE sec_root = NULL;
     PKT_secret_cert *skc = NULL;
-    PKT_user_id *upkt = NULL;
     DEK *dek = NULL;
     int rc;
     int algo;
@@ -315,8 +325,9 @@ generate_keypair()
     tty_printf("Please select the algorithm to use:\n"
               "   (1) ElGamal is the suggested one.\n"
           #ifdef HAVE_RSA_CIPHER
-              "   (2) RSA cannot be used inthe U.S.\n"
+              "   (2) RSA cannot be used in the U.S.\n"
           #endif
+              "   (3) DSA can only be used for signatures.\n"
               );
   #endif
 
@@ -324,7 +335,11 @@ generate_keypair()
       #ifdef TEST_ALGO
        algo = TEST_ALGO;
       #else
-       answer = tty_get("Your selection? (1,2) ");
+       answer = tty_get("Your selection? (1"
+                                          #ifdef HAVE_RSA_CIPHER
+                                            ",2"
+                                          #endif
+                                              ",3) ");
        tty_kill_prompt();
        algo = *answer? atoi(answer): 1;
        m_free(answer);
@@ -341,6 +356,11 @@ generate_keypair()
            break;
        }
       #endif
+       else if( algo == 3 ) {
+           algo = PUBKEY_ALGO_DSA;
+           algo_name = "DSA";
+           break;
+       }
     }
 
 
@@ -361,7 +381,9 @@ generate_keypair()
        nbits = *answer? atoi(answer): 1024;
        m_free(answer);
       #endif
-       if( nbits < 128 ) /* FIXME: change this to 768 */
+       if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
+           tty_printf("DSA does only allow keysizes from 512 to 1024\n");
+       else if( nbits < 128 ) /* FIXME: change this to 768 */
            tty_printf("keysize too small; please select a larger one\n");
        else if( nbits > 2048 ) {
            tty_printf("Keysizes larger than 2048 are not suggested, because "
@@ -381,7 +403,11 @@ generate_keypair()
            break;
     }
     tty_printf("Requested keysize is %u bits\n", nbits );
-    if( (nbits % 32) ) {
+    if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
+       nbits = ((nbits + 63) / 64) * 64;
+       tty_printf("rounded up to %u bits\n", nbits );
+    }
+    else if( (nbits % 32) ) {
        nbits = ((nbits + 31) / 32) * 32;
        tty_printf("rounded up to %u bits\n", nbits );
     }
@@ -435,74 +461,103 @@ generate_keypair()
     }
 
 
-    /* now check wether we a are allowed to write the keyrings */
-    if( !(rc=overwrite_filep( pub_fname )) ) {
-       if( !(pub_io = iobuf_create( pub_fname )) )
-           log_error("can't create %s: %s\n", pub_fname, strerror(errno) );
-       else if( opt.verbose )
-           log_info("writing to '%s'\n", pub_fname );
-    }
-    else if( rc != -1 ) {
-       log_error("Oops: overwrite_filep(%s): %s\n", pub_fname, g10_errstr(rc) );
-       m_free(uid);
-       return;
-    }
-    else {
-       m_free(uid);
-       return;
-    }
-    if( !(rc=overwrite_filep( sec_fname )) ) {
-       if( !(sec_io = iobuf_create( sec_fname )) )
-           log_error("can't create %s: %s\n", sec_fname, strerror(errno) );
-       else if( opt.verbose )
-           log_info("writing to '%s'\n", sec_fname );
-    }
-    else if( rc != -1 ) {
-       log_error("Oops: overwrite_filep(%s): %s\n", sec_fname, g10_errstr(rc) );
-       m_free(uid);
-       return;
-    }
-    else {
-       iobuf_cancel(pub_io);
-       m_free(uid);
-       return;
+    /* now check wether we a are allowed to write to the keyrings */
+    pub_fname = make_filename("~/.g10", "pubring.g10", NULL );
+    sec_fname = make_filename("~/.g10", "secring.g10", NULL );
+    if( opt.verbose ) {
+       tty_printf("writing public certificate to '%s'\n", pub_fname );
+       tty_printf("writing secret certificate to '%s'\n", sec_fname );
     }
 
-    write_comment( pub_io, "#public key created by G10 pre-release " VERSION );
-    write_comment( sec_io, "#secret key created by G10 pre-release " VERSION );
+    /* we create the packets as a tree of kbnodes. Because the structure
+     * we create is known in advance we simply generate a linked list
+     * The first packet is a comment packet, followed by the userid and
+     * the self signature.
+     */
+    pub_root = make_comment_node("#created by G10 pre-release " VERSION );
+    sec_root = make_comment_node("#created by G10 pre-release " VERSION );
 
     if( algo == PUBKEY_ALGO_ELGAMAL )
-       rc = gen_elg(nbits, pub_io, sec_io, dek, &pkc, &skc);
+       rc = gen_elg(nbits, pub_root, sec_root, dek, &skc );
   #ifdef HAVE_RSA_CIPHER
     else if( algo == PUBKEY_ALGO_RSA )
-       rc = gen_rsa(nbits, pub_io, sec_io, dek, &pkc, &skc);
+       rc = gen_rsa(nbits, pub_io, sec_io, dek, &skc );
   #endif
+    else if( algo == PUBKEY_ALGO_DSA )
+       rc = gen_dsa(nbits, pub_root, sec_root, dek, &skc );
     else
        log_bug(NULL);
     if( !rc )
-       write_uid(pub_io, uid, &upkt );
+       write_uid(pub_root, uid );
+    if( !rc )
+       write_uid(sec_root, uid );
     if( !rc )
-       write_uid(sec_io, uid, NULL );
+       rc = write_selfsig(pub_root, pub_root, skc);
     if( !rc )
-       rc = write_selfsig(pub_io, pkc, upkt, skc );
+       rc = write_selfsig(sec_root, pub_root, skc);
 
-    if( rc ) {
-       iobuf_cancel(pub_io);
-       iobuf_cancel(sec_io);
-       tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
-    }
-    else {
-       iobuf_close(pub_io);
-       iobuf_close(sec_io);
-       tty_printf("public and secret key created and signed.\n" );
+    if( !rc ) {
+       KBPOS pub_kbpos;
+       KBPOS sec_kbpos;
+       int rc1 = -1;
+       int rc2 = -1;
+
+       /* we can now write the certificates */
+       /* FIXME: should we check wether the user-id already exists? */
+
+       if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
+           if( add_keyblock_resource( pub_fname, 1 ) ) {
+               log_error("can add keyblock file '%s'\n", pub_fname );
+               rc = G10ERR_CREATE_FILE;
+           }
+           else if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
+               log_error("can get keyblock handle for '%s'\n", pub_fname );
+               rc = G10ERR_CREATE_FILE;
+           }
+       }
+       if( rc )
+           ;
+       else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
+           if( add_keyblock_resource( sec_fname, 1 ) ) {
+               log_error("can add keyblock file '%s'\n", sec_fname );
+               rc = G10ERR_CREATE_FILE;
+           }
+           else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
+               log_error("can get keyblock handle for '%s'\n", sec_fname );
+               rc = G10ERR_CREATE_FILE;
+           }
+       }
+
+       if( rc )
+           ;
+       else if( (rc=rc1=lock_keyblock( &pub_kbpos )) )
+           log_error("can't lock public keyring: %s\n", g10_errstr(rc) );
+       else if( (rc=rc2=lock_keyblock( &sec_kbpos )) )
+           log_error("can't lock secret keyring: %s\n", g10_errstr(rc) );
+       else if( (rc=insert_keyblock( &pub_kbpos, pub_root )) )
+           log_error("can't write public key: %s\n", g10_errstr(rc) );
+       else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) )
+           log_error("can't write secret key: %s\n", g10_errstr(rc) );
+       else {
+           tty_printf("public and secret key created and signed.\n" );
+       }
+
+       if( !rc1 )
+           unlock_keyblock( &pub_kbpos );
+       if( !rc2 )
+           unlock_keyblock( &sec_kbpos );
     }
-    if( pkc )
-       free_public_cert( pkc );
-    if( skc )
-       free_secret_cert( skc );
-    if( upkt )
-       free_user_id( upkt );
+
+
+    if( rc )
+       tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
+    release_kbnode( pub_root );
+    release_kbnode( sec_root );
+    if( skc ) /* the unprotected  secret certificate */
+       free_secret_cert(skc);
     m_free(uid);
     m_free(dek);
+    m_free(pub_fname);
+    m_free(sec_fname);
 }
 
index e3a16d8..307e28c 100644 (file)
 #include "keydb.h"
 
 
+int
+pubkey_letter( int algo )
+{
+    switch( algo ) {
+      case PUBKEY_ALGO_RSA:    return 'R' ;
+      case PUBKEY_ALGO_RSA_E:  return 'r' ;
+      case PUBKEY_ALGO_RSA_S:  return 's' ;
+      case PUBKEY_ALGO_ELGAMAL: return 'G' ;
+      case PUBKEY_ALGO_DSA:    return 'D' ;
+      default: return '?';
+    }
+}
 
 
 /****************
index 8be922b..13e20a7 100644 (file)
@@ -22,6 +22,7 @@
 #include "types.h"
 #include "iobuf.h"
 #include "cipher.h"
+#include "keydb.h"
 
 #define DEFAULT_CIPHER_ALGO  CIPHER_ALGO_BLOWFISH
 #define DEFAULT_PUBKEY_ALGO  PUBKEY_ALGO_ELGAMAL
@@ -34,6 +35,7 @@ int encode_crypt( const char *filename, STRLIST remusr );
 
 /*-- sign.c --*/
 int sign_file( const char *filename, int detached, STRLIST locusr );
+int sign_key( const char *username, STRLIST locusr );
 
 /*-- keygen.c --*/
 void generate_keypair(void);
@@ -49,5 +51,7 @@ MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits );
 MPI encode_md5_value( byte *md, unsigned len, unsigned nbits );
 MPI encode_md_value( MD_HANDLE *md, unsigned nbits );
 
+/*-- comment.c --*/
+KBNODE make_comment_node( const char *s );
 
 #endif /*G10_MAIN_H*/
index a8b6212..8bee0de 100644 (file)
@@ -56,19 +56,6 @@ typedef struct {
 static void list_node( CTX c, KBNODE node );
 static void proc_tree( CTX c, KBNODE node );
 
-static int
-pubkey_letter( int algo )
-{
-    switch( algo ) {
-      case PUBKEY_ALGO_RSA:    return 'R' ;
-      case PUBKEY_ALGO_RSA_E:  return 'r' ;
-      case PUBKEY_ALGO_RSA_S:  return 's' ;
-      case PUBKEY_ALGO_ELGAMAL: return 'G' ;
-      case PUBKEY_ALGO_DSA:    return 'D' ;
-      default: return '?';
-    }
-}
-
 
 static void
 release_cert( CTX c )
@@ -509,7 +496,6 @@ proc_packets( IOBUF a )
     CTX c = m_alloc_clear( sizeof *c );
     PACKET *pkt = m_alloc( sizeof *pkt );
     int rc, result;
-    char *ustr;
     int lvl0, lvl1;
     u32 keyid[2];
     int newpkt;
index a23412f..3be6c92 100644 (file)
@@ -34,7 +34,7 @@ struct {
     int cache_all;
     int fingerprint; /* list fingerprints */
     int list_sigs;   /* list signatures */
-    int reserved4;
+    int no_armor;
     int reserved5;
     int reserved6;
     int reserved7;
index e4380c3..10aa7c9 100644 (file)
@@ -60,9 +60,10 @@ struct resource_table_struct {
     char *fname;
     IOBUF iobuf;
 };
+typedef struct resource_table_struct RESTBL;
 
 #define MAX_RESOURCES 10
-static struct resource_table_struct resource_table[MAX_RESOURCES];
+static RESTBL resource_table[MAX_RESOURCES];
 
 
 static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
@@ -72,14 +73,14 @@ static int keyring_delete( KBPOS *kbpos );
 
 
 
-static int
+static RESTBL *
 check_pos( KBPOS *kbpos )
 {
     if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
-       return G10ERR_GENERAL;
+       return NULL;
     if( !resource_table[kbpos->resno].used )
-       return G10ERR_GENERAL;
-    return 0;
+       return NULL;
+    return resource_table + kbpos->resno;
 }
 
 
@@ -92,7 +93,7 @@ check_pos( KBPOS *kbpos )
  * Register a resource (which currently may ionly be a keyring file).
  */
 int
-add_keyblock_resource( const char *filename )
+add_keyblock_resource( const char *filename, int force )
 {
     IOBUF iobuf;
     int i;
@@ -104,7 +105,7 @@ add_keyblock_resource( const char *filename )
        return G10ERR_RESOURCE_LIMIT;
 
     iobuf = iobuf_open( filename );
-    if( !iobuf )
+    if( !iobuf && !force )
        return G10ERR_OPEN_FILE;
     resource_table[i].used = 1;
     resource_table[i].fname = m_strdup(filename);
@@ -170,6 +171,31 @@ search_keyblock( PACKET *pkt, KBPOS *kbpos )
 }
 
 
+/****************
+ * Combined function to search for a username and get the position
+ * of the keyblock.
+ */
+int
+search_keyblock_byname( KBPOS *kbpos, const char *username )
+{
+    PACKET pkt;
+    PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+    int rc;
+
+    rc = get_pubkey_byname( pkc, username );
+    if( rc ) {
+       free_public_cert(pkc);
+       return rc;
+    }
+
+    init_packet( &pkt );
+    pkt.pkttype = PKT_PUBLIC_CERT;
+    pkt.pkt.public_cert = pkc;
+    rc = search_keyblock( &pkt, kbpos );
+    free_public_cert(pkc);
+    return rc;
+}
+
 
 /****************
  * Lock the keyblock; wait until it's available
@@ -182,22 +208,19 @@ lock_keyblock( KBPOS *kbpos )
 {
     int rc;
 
-    if( (rc=check_pos(kbpos)) )
-       return rc;
+    if( !check_pos(kbpos) )
+       return G10ERR_GENERAL;
     return 0;
 }
 
 /****************
  * Release a lock on a keyblock
  */
-int
+void
 unlock_keyblock( KBPOS *kbpos )
 {
-    int rc;
-
-    if( (rc=check_pos(kbpos)) )
-       return rc;
-    return 0;
+    if( !check_pos(kbpos) )
+       log_bug(NULL);
 }
 
 /****************
@@ -206,10 +229,8 @@ unlock_keyblock( KBPOS *kbpos )
 int
 read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
 {
-    int rc;
-
-    if( (rc=check_pos(kbpos)) )
-       return rc;
+    if( !check_pos(kbpos) )
+       return G10ERR_GENERAL;
     return keyring_read( kbpos, ret_root );
 }
 
@@ -222,8 +243,8 @@ insert_keyblock( KBPOS *kbpos, KBNODE root )
 {
     int rc;
 
-    if( (rc=check_pos(kbpos)) )
-       return rc;
+    if( !check_pos(kbpos) )
+       return G10ERR_GENERAL;
 
     rc = keyring_insert( kbpos, root );
 
@@ -241,8 +262,8 @@ delete_keyblock( KBPOS *kbpos )
 {
     int rc;
 
-    if( (rc=check_pos(kbpos)) )
-       return rc;
+    if( !check_pos(kbpos) )
+       return G10ERR_GENERAL;
 
     rc = keyring_delete( kbpos );
 
@@ -358,13 +379,26 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
 {
     PACKET *pkt;
     int rc;
+    RESTBL *rentry;
     KBNODE root = NULL;
     KBNODE node, n1, n2;
     IOBUF a;
 
-    if( (rc=check_pos(kbpos)) )
-       return rc;
-    a = resource_table[kbpos->resno].iobuf;
+    if( !(rentry=check_pos(kbpos)) )
+       return G10ERR_GENERAL;
+
+    a = iobuf_open( rentry->fname );
+    if( !a ) {
+       log_error("can't open '%s'\n", rentry->fname );
+       return G10ERR_OPEN_FILE;
+    }
+
+    if( iobuf_seek( a, kbpos->offset ) ) {
+       log_error("can't seek to %lu: %s\n", kbpos->offset, g10_errstr(rc));
+       iobuf_close(a);
+       return G10ERR_KEYRING_OPEN;
+    }
+
 
     pkt = m_alloc( sizeof *pkt );
     init_packet(pkt);
@@ -377,7 +411,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
          case PKT_PUBLIC_CERT:
          case PKT_SECRET_CERT:
            if( root )
-               break;
+               goto ready;
            root = new_kbnode( pkt );
            pkt = m_alloc( sizeof *pkt );
            init_packet(pkt);
@@ -386,8 +420,8 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
          case PKT_USER_ID:
            if( !root ) {
                log_error("read_keyblock: orphaned user id\n" );
-               rc = G10ERR_INV_KEYRING; /* or wron kbpos */
-               break;
+               rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
+               goto ready;
            }
            /* append the user id */
            node = new_kbnode( pkt );
@@ -434,6 +468,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
            break;
        }
     }
+  ready:
     kbpos->last_block = rc == -1; /* flag, that this is the last block */
     if( rc == -1 && root )
        rc = 0;
@@ -446,14 +481,49 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
     }
     free_packet( pkt );
     m_free( pkt );
+    iobuf_close(a);
     return rc;
 }
 
 
+/****************
+ * Insert the keyblock described by ROOT into the keyring described
+ * by KBPOS.  This actually appends the data to the keyfile.
+ */
 static int
 keyring_insert( KBPOS *kbpos, KBNODE root )
 {
-    return -1;
+    RESTBL *rentry;
+    IOBUF fp;
+    KBNODE kbctx, node;
+    int rc;
+
+    if( !(rentry = check_pos( kbpos )) )
+       return G10ERR_GENERAL;
+
+    /* FIXME: we must close the file if it's already open, due to
+     *       2 reasons:
+     *        - cannot open the same file twice on DOSish OSes
+     *        - must sync with iobufs somehow
+     */
+    /* open the file for append */
+    fp = iobuf_append( rentry->fname );
+    if( !fp ) {
+       log_error("can't append to '%s'\n", rentry->fname );
+       return G10ERR_OPEN_FILE;
+    }
+
+    kbctx=NULL;
+    while( (node = walk_kbtree( root, &kbctx )) ) {
+       if( (rc = build_packet( fp, node->pkt )) ) {
+           log_error("build_packet(%d) failed: %s\n",
+                       node->pkt->pkttype, g10_errstr(rc) );
+           return G10ERR_WRITE_FILE;
+       }
+    }
+    iobuf_close(fp);
+
+    return 0;
 }
 
 static int
index cf34295..325234c 100644 (file)
@@ -49,7 +49,7 @@ make_session_key( DEK *dek )
 
 /****************
  * Encode the session key. NBITS is the number of bits which should be used
- * for packing teh session key.
+ * for packing the session key.
  * returns: A mpi with the session key (caller must free)
  */
 MPI
index f2e6b3f..71819c8 100644 (file)
@@ -64,6 +64,7 @@ IOBUF iobuf_alloc(int usage, size_t bufsize);
 IOBUF iobuf_temp(void);
 IOBUF iobuf_open( const char *fname );
 IOBUF iobuf_create( const char *fname );
+IOBUF iobuf_append( const char *fname );
 int   iobuf_close( IOBUF iobuf );
 int   iobuf_cancel( IOBUF iobuf );
 
index 80f66d8..6d59987 100644 (file)
@@ -21,6 +21,7 @@
 #define G10_TTYIO_H
 
 void tty_printf( const char *fmt, ... );
+void tty_print_string( byte *p, size_t n );
 char *tty_get( const char *prompt );
 char *tty_get_hidden( const char *prompt );
 void tty_kill_prompt(void);
index f05972c..33e1ac4 100644 (file)
@@ -5,6 +5,10 @@ CFLAGS += -O2
 
 SUFFIXES = .S .s
 
+SUBDIRS = generic i386
+EXTRA_DIST = config.links
+
+
 noinst_LIBRARIES = mpi
 noinst_HEADERS  = sysdep.h
 
index d51dcd0..382a222 100644 (file)
@@ -42,6 +42,9 @@ INCLUDES =  -I$(top_srcdir)/include
 
 SUFFIXES = .S .s
 
+SUBDIRS = generic i386
+EXTRA_DIST = config.links
+
 noinst_LIBRARIES = mpi
 noinst_HEADERS  = sysdep.h
 
@@ -158,13 +161,45 @@ libmpi.a: $(mpi_OBJECTS) $(mpi_LIBADD)
        $(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD)
        $(RANLIB) libmpi.a
 
-ID: $(HEADERS) $(SOURCES)
-       here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+       for subdir in $(SUBDIRS); do            \
+         target=`echo $@ | sed s/-recursive//`; \
+         echo making $$target in $$subdir;     \
+         (cd $$subdir && $(MAKE) $$target)     \
+          || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
+       done && test -z "$$fail"
 
 tags: TAGS
 
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
-       here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+tags-recursive:
+       list="$(SUBDIRS)"; for subdir in $$list; do \
+         (cd $$subdir && $(MAKE) tags); \
+       done
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(CONFIG_HEADER) \
+               $(TAGS_DEPENDENCIES)
+       tags=; \
+       here=`pwd`; \
+       for subdir in $(SUBDIRS); do \
+         test -f $$subdir/TAGS && { \
+           tags="$$tags -i $$here/$$subdir/TAGS"; \
+         }; \
+       done; \
+       test -z "$(ETAGS_ARGS)$(CONFIG_HEADER)$(SOURCES)$(HEADERS)$$tags" \
+         || etags $(ETAGS_ARGS) $$tags $(CONFIG_HEADER) $(SOURCES) $(HEADERS)
 
 mostlyclean-tags:
 
@@ -183,6 +218,14 @@ distdir: $(DEP_DISTFILES)
          || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
          || cp -p $(srcdir)/$$file $(distdir)/$$file; \
        done
+       for subdir in $(SUBDIRS); do            \
+         test -d $(distdir)/$$subdir           \
+         || mkdir $(distdir)/$$subdir          \
+         || exit 1;                            \
+         chmod 777 $(distdir)/$$subdir;        \
+         (cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \
+           || exit 1; \
+       done
 
 # This fragment is probably only useful for maintainers.  It relies on
 # GNU make and gcc.  It is only included in the generated Makefile.in
@@ -210,28 +253,30 @@ $(srcdir)/.deps/%.P: $(srcdir)/%.c
        fi
 
 # End of maintainer-only section
-info:
+info: info-recursive
+
+dvi: dvi-recursive
 
-dvi:
+check: all check-recursive
 
-check: all
+installcheck: installcheck-recursive
 
-installcheck:
+all-am: $(LIBFILES) $(HEADERS) Makefile
 
-install-exec: 
+install-exec: install-exec-recursive
 
-install-data: 
+install-data: install-data-recursive
 
-install: install-exec install-data all
+install: install-recursive
        @:
 
-uninstall: 
+uninstall: uninstall-recursive
 
-all: $(LIBFILES) $(HEADERS) Makefile
+all: all-recursive all-am
 
 install-strip:
        $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
-installdirs:
+installdirs: installdirs-recursive
 
 
 mostlyclean-generic:
@@ -247,29 +292,42 @@ distclean-generic:
 maintainer-clean-generic:
        test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
        test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-mostlyclean:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
+mostlyclean-am:  mostlyclean-noinstLIBRARIES mostlyclean-compile \
                mostlyclean-tags mostlyclean-generic
 
-clean:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
-               mostlyclean 
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+               mostlyclean-am 
 
-distclean:  distclean-noinstLIBRARIES distclean-compile distclean-tags \
-               distclean-generic clean 
-       rm -f config.status
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+               distclean-tags distclean-generic clean-am 
 
-maintainer-clean:  maintainer-clean-noinstLIBRARIES \
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
                maintainer-clean-compile maintainer-clean-tags \
-               maintainer-clean-generic distclean 
+               maintainer-clean-generic distclean-am 
+
+mostlyclean:  mostlyclean-am mostlyclean-recursive
+
+clean:  clean-am clean-recursive
+
+distclean:  distclean-am distclean-recursive
+       rm -f config.status
+
+maintainer-clean:  maintainer-clean-am maintainer-clean-recursive
        @echo "This command is intended for maintainers to use;"
        @echo "it deletes files that may require special tools to rebuild."
 
 .PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
 clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
 mostlyclean-compile distclean-compile clean-compile \
-maintainer-clean-compile tags mostlyclean-tags distclean-tags \
-clean-tags maintainer-clean-tags distdir info dvi check installcheck \
-install-exec install-data install uninstall all installdirs \
-mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-compile install-data-recursive \
+uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi check \
+installcheck all-am install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
 maintainer-clean-generic clean mostlyclean distclean maintainer-clean
 
 CFLAGS += -O2
diff --git a/mpi/config.links b/mpi/config.links
new file mode 100644 (file)
index 0000000..e48cf7a
--- /dev/null
@@ -0,0 +1,51 @@
+# sourced my ../configure to get the list of files to link
+# this should set $mpi_ln_src and mpi_ln_dst.
+# Note: this is called from the above directory.
+
+echo '# created by config.links - do not edit' >./mpi/asm-syntax.h
+
+case "${target}" in
+    i[3456]86*-*-*)
+       echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
+       echo '#include "./i386/syntax.h"' >>./mpi/asm-syntax.h
+       path="i386"
+       ;;
+    i[56]86*-*-* | pentium-*-* | pentiumpro-*-*)
+       echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
+       echo '#include "./i586/syntax.h"' >>./mpi/asm-syntax.h
+       path="i586"
+       ;;
+    *)
+       echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h
+       path=""
+       ;;
+esac
+
+
+# fixme: grep these modules from Makefile.in
+mpi_ln_modules="mpih-add1 mpih-mul1 mpih-mul2 mpih-mul3 \
+                mpih-shift mpih-sub1"
+
+mpi_ln_objects=
+mpi_ln_src=
+mpi_ln_dst=
+
+# try to get file to link from the assembler subdirectory and
+# if this fails get it from the generic subdirectory.
+path="$path generic"
+for fn in $mpi_ln_modules ; do
+    mpi_ln_objects="$mpi_ln_objects $fn.o"
+    for dir in $path ; do
+       rm -f ./mpi/$fn.[Sc]
+       if test -f ./mpi/$dir/$fn.S ; then
+           mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.S"
+           mpi_ln_dst="$mpi_ln_dst mpi/$fn.S"
+           break;
+       elif test -f ./mpi/$dir/$fn.c ; then
+           mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.c"
+           mpi_ln_dst="$mpi_ln_dst mpi/$fn.c"
+           break;
+       fi
+    done
+done
+
index 10cfd5c..80b7fcd 100644 (file)
@@ -194,6 +194,7 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
     char keyword[100];
     char *buffer = NULL;
     size_t buflen = 0;
+    int inverse=0;
 
     if( !fp ) /* same as arg_parse() in this case */
        return arg_parse( arg, opts );
@@ -216,6 +217,8 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
                        break;
                index = i;
                arg->r_opt = opts[index].short_opt;
+               if( inverse )
+                   arg->r_opt = -arg->r_opt;
                if( !opts[index].short_opt )
                    arg->r_opt = -2;           /* unknown option */
                else if( (opts[index].flags & 8) )  /* no optional argument */
index da8fea4..1c35db6 100644 (file)
@@ -371,6 +371,36 @@ iobuf_create( const char *fname )
 }
 
 /****************
+ * append to a iobuf if the file does not exits; create it.
+ * cannont be used for stdout.
+ */
+IOBUF
+iobuf_append( const char *fname )
+{
+    IOBUF a;
+    FILE *fp;
+    file_filter_ctx_t *fcx;
+    size_t len;
+
+    if( !fname )
+       return NULL;
+    else if( !(fp = fopen(fname, "ab")) )
+       return NULL;
+    a = iobuf_alloc(2, 8192 );
+    fcx = m_alloc( sizeof *fcx + strlen(fname) );
+    fcx->fp = fp;
+    strcpy(fcx->fname, fname );
+    a->filter = file_filter;
+    a->filter_ov = fcx;
+    file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+    file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+    if( DBG_IOBUF )
+       log_debug("iobuf-%d.%d: append '%s'\n", a->no, a->subno, a->desc );
+
+    return a;
+}
+
+/****************
  * Register an i/o filter.
  */
 int
@@ -709,8 +739,25 @@ iobuf_tell( IOBUF a )
 int
 iobuf_seek( IOBUF a, ulong newpos )
 {
+    file_filter_ctx_t *b = NULL;
 
-    return -1;
+    for( ; a; a = a->chain ) {
+       if( !a->chain && a->filter == file_filter ) {
+           b = a->filter_ov;
+           break;
+       }
+    }
+    if( !a )
+       return -1;
+
+    if( fseek( b->fp, newpos, SEEK_SET ) ) {
+       log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
+       return -1;
+    }
+
+    /* FIXME: flush all buffers (and remove filters?)*/
+
+    return 0;
 }
 
 
index 18fff2c..327eae8 100644 (file)
@@ -46,7 +46,7 @@ print_string( FILE *fp, byte *p, size_t n )
            else if( !*p )
                putc('0', fp);
            else
-               printf("x%02x", *p );
+               fprintf(fp, "x%02x", *p );
        }
        else
            putc(*p, fp);
index 39ad5a6..74d31d1 100644 (file)
@@ -60,6 +60,28 @@ tty_printf( const char *fmt, ... )
 }
 
 
+/****************
+ * Print a string, but filter all control characters out.
+ */
+void
+tty_print_string( byte *p, size_t n )
+{
+    for( ; n; n--, p++ )
+       if( iscntrl( *p ) ) {
+           putc('\\', stderr);
+           if( *p == '\n' )
+               putc('n', stderr);
+           else if( !*p )
+               putc('0', stderr);
+           else
+               fprintf(stderr, "x%02x", *p );
+       }
+       else
+           putc(*p, stderr);
+}
+
+
+
 char *
 tty_get( const char *prompt )
 {