--- pgp/src/keyadd.c 2018/04/24 16:38:57 1.1.1.2 +++ pgp/src/keyadd.c 2018/04/24 16:40:30 1.1.1.4 @@ -25,22 +25,30 @@ #endif #include #include "mpilib.h" -#include "idea.h" -#include "random.h" #include "crypto.h" #include "fileio.h" #include "keymgmt.h" -#include "genprime.h" -#include "rsagen.h" -#include "mpiio.h" +#include "charset.h" #include "language.h" #include "pgp.h" +#include "exitpgp.h" +#include "keyadd.h" +#include "keymaint.h" + +void gpk_close(void); +int gpk_open(char *keyfile); +int get_publickey(long *file_position, int *pktlen, byte *keyID, byte *timestamp, + byte *userid, unitptr n, unitptr e); static int ask_to_sign(byte *keyID, char *ringfile); +static boolean ask_first; + +static boolean publickey; /* if TRUE, add trust packets */ static int newkeys, newsigs, newids, newrvks; +static byte mykeyID[KEYFRAGSIZE]; -int mergesigs (FILE *fkey, char *keyfile, long keypos, FILE *fring, +static int mergesigs (FILE *fkey, char *keyfile, long keypos, FILE *fring, char *ringfile, long *pringpos, FILE *out) /* Merge signatures from userid in fkey (which is keyfile) at keypos with * userid from fring (which is ringfile) at ringpos, appending result to out. @@ -113,14 +121,24 @@ int mergesigs (FILE *fkey, char *keyfile copying = (getpubusersig (ringfile, ringuseridpos, keyID, &sig_pos, &sig_len) < 0); if (copying) - { fprintf (pgpout, PSTR("New signature from keyID %s on userid \"%s\"\n"), - keyIDstring(keyID),LOCAL_CHARSET(userid)); + { char *signator; + if ((signator = user_from_keyID(keyID)) == NULL) + fprintf(pgpout, PSTR("New signature from keyID %s on userid \"%s\"\n"), + keyIDstring(keyID), LOCAL_CHARSET(userid)); + else + { + fprintf(pgpout, PSTR("New signature from %s\n"), LOCAL_CHARSET(signator)); + fprintf(pgpout, PSTR("on userid \"%s\"\n"), LOCAL_CHARSET(userid)); + } ++newsigs; + if (batchmode) + show_update(keyIDstring(mykeyID)); } } if (copying && is_ctb_type(ctb,CTB_SKE_TYPE)) { copyfilepos (fkey, out, keypktlen, keypos); - write_trust (out, KC_SIGTRUST_UNDEFINED); + if (publickey) + write_trust (out, KC_SIGTRUST_UNDEFINED); } } @@ -140,7 +158,7 @@ int mergesigs (FILE *fkey, char *keyfile } /* mergesigs */ -int mergekeys (FILE *fkey, char *keyfile, long keypos, FILE *fring, +static int mergekeys (FILE *fkey, char *keyfile, long keypos, FILE *fring, char *ringfile, long *pringpos, FILE *out) /* Merge key from fkey (which is keyfile) at keypos with key from * fring (which is ringfile) at ringpos, appending result to out. @@ -195,13 +213,17 @@ int mergekeys (FILE *fkey, char *keyfile ringfile, (char *)userid, (byte *)×tamp, &sig_class) == 0 && sig_class == KC_SIGNATURE_BYTE) { + PascalToC((char *)userid); fprintf(pgpout, PSTR("Key revocation certificate from \"%s\".\n"), LOCAL_CHARSET((char *)userid)); copyfilepos (fkey, out, cert_pktlen, keypos); + /* Show updates */ + if (batchmode) + show_key(fring, *pringpos, SHOW_CHANGE); ++newrvks; } else - fprintf(pgpout, PSTR("\n\007WARNING: File '%s' contains bad revocation certificate.\n")); + fprintf(pgpout, PSTR("\n\007WARNING: File '%s' contains bad revocation certificate.\n"), keyfile); } fseek (fkey, keypos, SEEK_SET); @@ -234,13 +256,20 @@ int mergekeys (FILE *fkey, char *keyfile copying = (getpubuserid (ringfile, ringkeypos, userid, &userid_pos, &userid_len, TRUE) < 0); if (copying) - { fprintf (pgpout, PSTR("New userid: \"%s\".\n"), + { putc('\n', pgpout); + fprintf (pgpout, PSTR("New userid: \"%s\".\n"), LOCAL_CHARSET((char *)userid)); fprintf(pgpout, PSTR("\nWill be added to the following key:\n")); show_key(fring, *pringpos, 0); fprintf(pgpout, PSTR("\nAdd this userid (y/N)? ")); - if (getyesno('n')) + if (batchmode || getyesno('n')) { ++newids; + /* Show an update string */ + if (batchmode) { + fprintf(pgpout, "\n"); + show_key(fring, *pringpos, SHOW_CHANGE); + } + } else copying = FALSE; } @@ -248,10 +277,12 @@ int mergekeys (FILE *fkey, char *keyfile if (copying) { if (ctb==CTB_USERID || is_ctb_type(ctb,CTB_SKE_TYPE)) { copyfilepos (fkey, out, keypktlen, keypos); - if (is_ctb_type(ctb,CTB_SKE_TYPE)) - write_trust (out, KC_SIGTRUST_UNDEFINED); - else - write_trust (out, KC_LEGIT_UNKNOWN); + if (publickey) { + if (is_ctb_type(ctb,CTB_SKE_TYPE)) + write_trust (out, KC_SIGTRUST_UNDEFINED); + else + write_trust (out, KC_LEGIT_UNKNOWN); + } } } } @@ -260,6 +291,10 @@ int mergekeys (FILE *fkey, char *keyfile * plus its dependant signatures. */ fseek (fring, ringpos, SEEK_SET); + /* Grab the keyID here */ + readkeypacket(fring,FALSE,&ctb,NULL,(char *)userid,NULL,NULL, + NULL,NULL,NULL,NULL,NULL,NULL); + fseek (fring, ringpos, SEEK_SET); for ( ; ; ) { ringpos = ftell(fring); status = readkeypacket(fring,FALSE,&ctb,NULL,(char *)userid,NULL,NULL, @@ -295,12 +330,11 @@ int mergekeys (FILE *fkey, char *keyfile } /* mergekeys */ -int addto_keyring(char *keyfile, char *ringfile, boolean query) -/* Adds (prepends) key file to key ring file. If query is TRUE, ask - before doing any actual changes. */ +int _addto_keyring(char *keyfile, char *ringfile) +/* Adds (prepends) key file to key ring file. */ { FILE *f, *g, *h; long file_position,fp; - int pktlen; /* unused, just to satisfy getpublickey */ + int pktlen; byte ctb; int status; unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; @@ -309,8 +343,6 @@ int addto_keyring(char *keyfile, char *r byte userid[256]; /* key certificate userid */ byte userid1[256]; word32 tstamp; byte *timestamp = (byte *) &tstamp; /* key certificate timestamp */ - char trans_keyfile[MAX_PATH]; - boolean is_armored = FALSE; boolean userid_seen = FALSE; int commonkeys = 0; int copying; @@ -320,31 +352,30 @@ int addto_keyring(char *keyfile, char *r } *nkey, *nkeys = NULL; char *scratchf; - setoutdir(ringfile); - scratchf = tempfile(0); - - /* check if the keyfile to be added is armored */ - if ((is_armored = is_armor_file(keyfile, 0L)) == TRUE) - { /* decode it into the actual keyfile */ - boolean changed_name; - strcpy(trans_keyfile,keyfile); - keyfile = tempfile(TMP_TMPDIR|TMP_WIPE); - if (de_armor_file(trans_keyfile,keyfile,NULL) < 0) - return(-1); - } - - userid[0] = '\0'; - if (dokeycheck((char *) userid, keyfile, NULL) < 0) - { fprintf(pgpout, PSTR("\007Keyring check error. ") ); - fprintf(pgpout, PSTR("\nKey(s) will not be added to keyring.\n")); - goto err; - } - /* open file f for read, in binary (not text) mode...*/ if ((f = fopen(keyfile,FOPRBIN)) == NULL) { fprintf(pgpout,PSTR("\n\007Can't open key file '%s'\n"),keyfile); - goto err; + return -1; } + ctb = 0; + if (fread(&ctb, 1, 1, f) != 1 || !is_key_ctb(ctb)) + { + fclose(f); + return -1; + } + rewind(f); + + setoutdir(ringfile); + scratchf = tempfile(0); + + /* + * get userids from both files, maybe should also use the default public + * keyring if ringfile is not the default ring. + */ + setkrent(ringfile); + setkrent(keyfile); + init_userhash(); + if (!file_exists(ringfile)) { /* ringfile does not exist. Can it be created? */ /* open file g for writing, in binary (not text) mode...*/ @@ -367,7 +398,13 @@ int addto_keyring(char *keyfile, char *r /* Pass 1 - copy all keys from f which aren't in ring file */ /* Also copy userid and signature packets. */ + fprintf(pgpout, PSTR("\nLooking for new keys...\n")); copying = FALSE; + if (gpk_open(ringfile) < 0) + { fclose(f); /* close key file */ + fclose(g); + goto err; + } for ( ; ; ) { file_position = ftell(f); @@ -376,7 +413,7 @@ int addto_keyring(char *keyfile, char *r /* Note that readkeypacket has called set_precision */ if (status == -1) /* EOF */ break; - if (status == -3) + if (status == -2 || status == -3) { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), keyfile); fclose(f); /* close key file */ @@ -393,61 +430,49 @@ int addto_keyring(char *keyfile, char *r if (is_key_ctb(ctb)) { extract_keyID(keyID, n); /* from keyfile, not ringfile */ + publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); /* Check for duplicate key in key ring: */ - if (getpublickey(TRUE, FALSE, ringfile, &fp, &pktlen, keyID, timestamp, userid, n1, e) >= 0) + status = get_publickey(&fp, NULL, keyID, timestamp, userid, n1, e); + if (status == 0) /* key in both keyring and keyfile */ { if (mp_compare (n, n1) != 0) { fprintf(pgpout, PSTR("\n\007Warning: Key ID %s matches key ID of key already on \n\ key ring '%s', but the keys themselves differ.\n\ This is highly suspicious. This key will not be added to ring.\n\ Acknowledge by pressing return: "), keyIDstring(keyID), ringfile); getyesno('n'); - fclose(f); /* close key file */ - fclose(g); - goto err; } else - { if (verbose) - fprintf(pgpout,PSTR("Key ID %s is already included in key ring '%s'.\n"), - keyIDstring(keyID), ringfile); ++commonkeys; - } copying = FALSE; } - else + else if (status == -1) /* key NOT in keyring */ { ++newkeys; -#if 0 - if (query) - { if (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) - fprintf (pgpout, PSTR ("\nAdd secret key to key ring '%s' (y/N)? "), - ringfile); - else - fprintf (pgpout, PSTR ("\nAdd public key to key ring '%s' (y/N)? "), - ringfile); - - if (! getyesno( 'n' )) - { fclose(f); - fclose(g); - rmtemp(scratchf); - return(0); /* user chose to abort */ - } - query = FALSE; /* Don't ask subsequently */ + if (interactive_add) + { show_key(f, file_position, SHOW_ALL); + fprintf(pgpout, PSTR("\nDo you want to add this key to keyring '%s' (y/N)? "), ringfile); + copying = getyesno('n'); + } + else + { + show_key(f, file_position, SHOW_LISTFMT); + copying = TRUE; } -#endif - if ((nkey = (struct nkey *) malloc(sizeof(struct nkey))) == NULL) + /* If batchmode, output an update message */ + if (batchmode) + show_key(f, file_position, SHOW_CHANGE); + if (copying) { - fprintf(stderr, PSTR("\n\007Out of memory.\n")); - exitPGP(7); + nkey = xmalloc(sizeof(struct nkey)); + memcpy(nkey->keyID, keyID, KEYFRAGSIZE); + nkey->next = nkeys; + nkeys = nkey; } - memcpy(nkey->keyID, keyID, KEYFRAGSIZE); - nkey->next = nkeys; - nkeys = nkey; - - fprintf(pgpout, PSTR("New key ID: %s\n"), keyIDstring(keyID)); - copying = TRUE; } + else /* unknown version or bad key */ + copying = FALSE; } /* Now, we copy according to the copying flag */ /* The key is prepended to the ring to give it search precedence @@ -457,27 +482,30 @@ Acknowledge by pressing return: "), keyI is_ctb_type(ctb,CTB_SKE_TYPE))) { pktlen = (int) (ftell(f) - file_position); copyfilepos(f,g,pktlen,file_position); /* copy packet from f */ - /* Initialize trust packets after keys and signatures */ - if (is_key_ctb(ctb)) - { - write_trust (g, KC_OWNERTRUST_UNDEFINED); - userid_seen = FALSE; - } - else if (is_ctb_type(ctb,CTB_SKE_TYPE)) - { - if (userid_seen) - write_trust (g, KC_SIGTRUST_UNDEFINED); - else - /* signature certificate before userid must be compromise cert. */ - fprintf(pgpout, PSTR("Key has been revoked.\n")); - } - else if (is_ctb_type(ctb,CTB_USERID_TYPE)) - { - write_trust (g, KC_LEGIT_UNKNOWN); - userid_seen = TRUE; + if (publickey) + { /* Initialize trust packets after keys and signatures */ + if (is_key_ctb(ctb)) + { + write_trust (g, KC_OWNERTRUST_UNDEFINED); + userid_seen = FALSE; + } + else if (is_ctb_type(ctb,CTB_SKE_TYPE)) + { + if (userid_seen) + write_trust (g, KC_SIGTRUST_UNDEFINED); + else + /* signature certificate before userid must be compromise cert. */ + fprintf(pgpout, PSTR("Key has been revoked.\n")); + } + else if (is_ctb_type(ctb,CTB_USERID_TYPE)) + { + write_trust (g, KC_LEGIT_UNKNOWN); + userid_seen = TRUE; + } } } } + gpk_close(); /* Now copy the remainder of the ringfile, h, to g. commonkeys tells how many keys are common to keyfile and ringfile. As long as that is @@ -485,7 +513,14 @@ Acknowledge by pressing return: "), keyI in keyfile. */ if ((h = fopen(ringfile,FOPRBIN)) != NULL) - { while (commonkeys) /* Loop for each key in ringfile */ + { + if (gpk_open(keyfile) < 0) + { fclose(f); + fclose(g); + fclose(h); + goto err; + } + while (commonkeys) /* Loop for each key in ringfile */ { file_position = ftell(h); status = readkeypacket(h,FALSE,&ctb,NULL,(char *)userid,n,e, NULL,NULL,NULL,NULL,NULL,NULL); @@ -504,27 +539,28 @@ Acknowledge by pressing return: "), keyI pktlen = ftell(h) - file_position; if (is_key_ctb(ctb)) { long tfp; - int tpktlen; - /* See if there is a match in keyfile */ - extract_keyID(keyID, n); /* from ringfile, not keyfile */ - /* unknow version or bad data: copy (don't remove packets from ringfile) */ - if (status == 0 && (getpublickey(TRUE, FALSE, keyfile, &tfp, &tpktlen, - keyID, timestamp, userid1, n1, e) >= 0) && - (mp_compare(n, n1) == 0)) + /* unknown version or bad data: copy (don't remove packets from ringfile) */ + copying = TRUE; + if (status == 0) { - if (verbose) - fprintf (pgpout, PSTR("Merging key ID: %s\n"),keyIDstring(keyID)); - if (mergekeys (f,keyfile,tfp, h,ringfile,&file_position, g) < 0) - { fclose(f); - fclose(g); - fclose(h); - goto err; + /* See if there is a match in keyfile */ + extract_keyID(keyID, n); /* from ringfile, not keyfile */ + extract_keyID(mykeyID, n); /* save this */ + publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE); + if (get_publickey(&tfp, NULL, keyID, timestamp, userid1, n1, e) >= 0) + { + if (verbose) + fprintf (pgpout, "Merging key ID: %s\n",keyIDstring(keyID)); + if (mergekeys (f,keyfile,tfp, h,ringfile,&file_position, g) < 0) + { fclose(f); + fclose(g); + fclose(h); + goto err; + } + copying = FALSE; + --commonkeys; } - copying = FALSE; - --commonkeys; } - else - copying = TRUE; } if (copying) { /* Copy ringfile key to g, without its sigs */ @@ -532,6 +568,7 @@ Acknowledge by pressing return: "), keyI file_position += pktlen; } } /* End of loop for each key in ringfile */ + gpk_close(); copyfile(h,g,-1L); /* copy rest of file from file h to g */ fclose(h); } @@ -545,14 +582,17 @@ Acknowledge by pressing return: "), keyI { fprintf(pgpout, PSTR("No new keys or signatures in keyfile.\n")); rmtemp(scratchf); + endkrent(); return(0); } - for (nkey = nkeys; nkey; nkey = nkey->next) - { - if (dokeycheck(NULL, scratchf, nkey->keyID)) - goto err; + if (status = dokeycheck(NULL, scratchf, CHECK_NEW)) + { if (verbose) + fprintf(pgpout, "addto_keyring: dokeycheck returned %d\n", status); + goto err; } + endkrent(); + fprintf(pgpout, PSTR("\nKeyfile contains:\n")); if (newkeys) fprintf(pgpout, PSTR("%4d new key(s)\n"), newkeys); @@ -562,36 +602,64 @@ Acknowledge by pressing return: "), keyI fprintf(pgpout, PSTR("%4d new user ID(s)\n"), newids); if (newrvks) fprintf(pgpout, PSTR("%4d new revocation(s)\n"), newrvks); - if (query) - { - fprintf(pgpout, PSTR("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile); - if (!getyesno('n')) - { rmtemp(scratchf); - return(1); - } - } - if ((status = maintenance(scratchf, MAINT_SILENT)) == 0) + + ask_first = TRUE; + if ((status = maint_update(scratchf)) >= 0 && !filter_mode && !batchmode) for (nkey = nkeys; nkey; nkey = nkey->next) - { fprintf(pgpout,PSTR("Adding key ID %s from file '%s' to key ring '%s'.\n"), - keyIDstring(nkey->keyID),(is_armored?trans_keyfile:keyfile),ringfile); - ask_to_sign(nkey->keyID, scratchf); - } + if (ask_to_sign(nkey->keyID, scratchf) != 0) + break; + if (status && verbose) + fprintf(pgpout, "addto_keyring: maint_update returned %d\n", status); + + for (nkey = nkeys; nkey; ) + { nkey = nkey->next; + free(nkeys); + nkeys = nkey; + } savetempbak(scratchf,ringfile); - if (is_armored) - rmtemp(keyfile); /* zap decoded keyfile */ return(0); /* normal return */ err: + gpk_close(); /* save to call if not opened */ + endkrent(); /* make sure we remove any garbage files we may have created */ - if (is_armored) - rmtemp(keyfile); /* zap decoded keyfile */ rmtemp(scratchf); return(-1); } /* addto_keyring */ +int addto_keyring(char *keyfile, char *ringfile) +{ + long armorline = 0; + char *tempf; + int addflag = 0; + + if (_addto_keyring(keyfile, ringfile) == 0) + return 0; + /* check if the keyfile to be added is armored */ + while (is_armor_file(keyfile,armorline)) + { + tempf = tempfile(TMP_TMPDIR|TMP_WIPE); + if (de_armor_file(keyfile,tempf,&armorline)) + { rmtemp(tempf); + return -1; + } + if (_addto_keyring(tempf, ringfile) == 0) + addflag = 1; + rmtemp(tempf); + } + if (!addflag) + { + fprintf(pgpout, PSTR("\nNo keys found in '%s'.\n"), keyfile); + return -1; + } + else + return 0; +} + + static int ask_to_sign(byte *keyID, char *ringfile) { FILE *f; @@ -600,12 +668,11 @@ static int ask_to_sign(byte *keyID, char unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION]; byte userid[256]; long fpos; - int pktlen; /* unused, just to satisfy getpublickey */ int status; extern char my_name[]; - if (getpublickey(TRUE, FALSE, ringfile, &fpos, &pktlen, - keyID, (byte *)×tamp, userid, n, e) < 0) + if (getpublickey(GPK_GIVEUP, ringfile, &fpos, NULL, keyID, + (byte *)×tamp, userid, n, e) < 0) return(-1); if ((f = fopen(ringfile, FOPRBIN)) == NULL) @@ -643,14 +710,195 @@ static int ask_to_sign(byte *keyID, char fclose(f); return(0); } - show_key(f, fpos, SHOW_ALL); + if (ask_first) /* shortcut for adding big keyfile */ + { fprintf(pgpout, PSTR("\nOne or more of the new keys are not fully certified.\n\ +Do you want to certify any of these keys yourself (y/N)? ")); + if (!getyesno('n')) + { + fclose(f); + return 1; + } + } + ask_first = FALSE; + show_key(f, fpos, SHOW_ALL|SHOW_HASH); fclose(f); PascalToC((char *)userid); fprintf(pgpout, PSTR("\nDo you want to certify this key yourself (y/N)? ")); if (getyesno('n')) { if (signkey((char *)userid, my_name, ringfile) == 0) - maintenance(ringfile, MAINT_SILENT); + maint_update(ringfile); } return(0); } + + + +/**** faster version of getpublickey() ****/ + +static long find_keyID(byte *keyID); + +static FILE *gpkf = NULL; + +/* + * speedup replacement for getpublickey(), does not have the arguments + * giveup, showkey and keyfile (giveup = TRUE, showkey = FALSE, keyfile + * is set with gpk_open(). + * only searches on keyID + */ +int get_publickey(long *file_position, int *pktlen, byte *keyID, byte *timestamp, + byte *userid, unitptr n, unitptr e) +{ + byte ctb; /* returned by readkeypacket */ + int status, keystatus = -1; + long fpos; + + if ((fpos = find_keyID(keyID)) == -1) + return -1; + fseek(gpkf, fpos, SEEK_SET); + + while (TRUE) + { + fpos = ftell(gpkf); + status = readkeypacket(gpkf,FALSE,&ctb,timestamp,(char *)userid,n,e, + NULL,NULL,NULL,NULL,NULL,NULL); + /* Note that readkeypacket has called set_precision */ + + if (status < 0 && status != -4 && status != -6) + return(status); + + /* Remember packet position and size for last key packet */ + if (is_key_ctb(ctb)) + { if (file_position) + *file_position = fpos; + if (pktlen) + *pktlen = (int)(ftell(gpkf) - fpos); + if (keystatus != -1) + return -3; /* should not happen, probably missing userid pkt */ + keystatus = status; + } + if (ctb == CTB_USERID) + return keystatus; + } /* while TRUE */ + return -1; +} + +#define PK_HASHSIZE 256 /* must be power of 2 */ +#define PK_HASH(x) (*(byte *) (x) & (PK_HASHSIZE - 1)) +#define HASH_ALLOC 400 + +static VOID * allocbuf(int size); +static void freebufpool(void); + +static struct hashent { + struct hashent *next; + byte keyID[KEYFRAGSIZE]; + long offset; +} **hashtbl = NULL, *hashptr; + +static int hashleft = 0; + +int +gpk_open(char *keyfile) +{ + int status; + long fpos = 0; + byte keyID[KEYFRAGSIZE]; + byte ctb; + + if (gpkf) { + fprintf(pgpout, "gpk_open: already open\n"); + return -1; + } + default_extension(keyfile,PGP_EXTENSION); + if ((gpkf = fopen(keyfile,FOPRBIN)) == NULL) + return(-1); /* error return */ + hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *)); + memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *)); + while ((status = readkpacket(gpkf, &ctb, NULL, keyID, NULL)) != -1) { + if (status == -2 || status == -3) + { fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"), + keyfile); + fclose(gpkf); /* close key file */ + return -1; + } + if (is_key_ctb(ctb)) { + if (find_keyID(keyID) != -1) + fprintf(pgpout, "warning: duplicate key in keyring '%s'\n", keyfile); + if (!hashleft) { + hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent)); + hashleft = HASH_ALLOC; + } + memcpy(hashptr->keyID, keyID, KEYFRAGSIZE); + hashptr->offset = fpos; + hashptr->next = hashtbl[PK_HASH(keyID)]; + hashtbl[PK_HASH(keyID)] = hashptr; + ++hashptr; + --hashleft; + } + fpos = ftell(gpkf); + } + return 0; +} + +void +gpk_close(void) +{ + if (!gpkf) + return; + hashleft = 0; + hashtbl = NULL; + freebufpool(); + fclose(gpkf); /* close key file */ + gpkf = NULL; +} + +/* + * Lookup file position in hash table by keyID, returns -1 if not found + */ +static long +find_keyID(byte *keyID) +{ + struct hashent *p; + + for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next) + if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0) + return p->offset; + return -1; +} + + +static struct bufpool { + struct bufpool *next; + char buf[1]; /* variable size */ +} *bufpool = NULL; + +/* + * allocate buffer, all buffers allocated with this function can be + * freed with one call to freebufpool() + */ +static VOID * +allocbuf(int size) +{ + struct bufpool *p; + + p = xmalloc(size + sizeof(struct bufpool *)); + p->next = bufpool; + bufpool = p; + return p->buf; +} + +/* + * free all memory obtained with allocbuf() + */ +static void +freebufpool(void) +{ + struct bufpool *p; + + while (bufpool) { + p = bufpool; + bufpool = bufpool->next; + free(p); + } +}