Annotation of pgp/src/keyadd.c, revision 1.1.1.7

1.1.1.7 ! root        1: /*      keyadd.c  - Keyring merging routines for PGP.
        !             2:    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
1.1.1.6   root        3: 
1.1.1.7 ! root        4:    (c) Copyright 1990-1994 by Philip Zimmermann.  All rights reserved.
        !             5:    The author assumes no liability for damages resulting from the use
        !             6:    of this software, even if the damage results from defects in this
        !             7:    software.  No warranty is expressed or implied.
        !             8: 
        !             9:    Note that while most PGP source modules bear Philip Zimmermann's
        !            10:    copyright notice, many of them have been revised or entirely written
        !            11:    by contributors who frequently failed to put their names in their
        !            12:    code.  Code that has been incorporated into PGP from other authors
        !            13:    was either originally published in the public domain or is used with
        !            14:    permission from the various authors.
        !            15: 
        !            16:    PGP is available for free to the public under certain restrictions.
        !            17:    See the PGP User's Guide (included in the release package) for
        !            18:    important information about licensing, patent restrictions on
        !            19:    certain algorithms, trademarks, copyrights, and export controls.
        !            20:  */
1.1.1.6   root       21: 
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #ifdef UNIX
                     25: #include <sys/types.h>
                     26: #endif
                     27: #include <time.h>
                     28: #include "mpilib.h"
                     29: #include "crypto.h"
                     30: #include "fileio.h"
                     31: #include "keymgmt.h"
                     32: #include "charset.h"
                     33: #include "mpiio.h"
                     34: #include "language.h"
                     35: #include "pgp.h"
                     36: #include "exitpgp.h"
                     37: #include "keyadd.h"
                     38: #include "keymaint.h"
                     39: 
                     40: void gpk_close(void);
                     41: int gpk_open(char *keyfile);
1.1.1.7 ! root       42: int get_publickey(long *file_position, int *pktlen,
        !            43:                  byte * keyID, byte * timestamp,
        !            44:                  byte * userid, unitptr n, unitptr e);
1.1.1.6   root       45: 
1.1.1.7 ! root       46: static int ask_to_sign(byte * keyID, char *ringfile);
1.1.1.6   root       47: static boolean ask_first;
                     48: 
                     49: static boolean publickey;      /* if TRUE, add trust packets */
                     50: 
                     51: static int newkeys, newsigs, newids, newrvks;
                     52: static byte mykeyID[KEYFRAGSIZE];
                     53: 
                     54: static struct sig_list {
1.1.1.7 ! root       55:     struct sig_list *next;
        !            56:     long pos;
1.1.1.6   root       57: } *siglist;
1.1.1.7 ! root       58: static void sig_list_add(long pos)
1.1.1.6   root       59: {
1.1.1.7 ! root       60:     struct sig_list *p;
        !            61:     p = xmalloc(sizeof *p);
        !            62:     p->pos = pos;
        !            63:     p->next = siglist;
        !            64:     siglist = p;
        !            65: }
        !            66: static int sig_list_find(long pos)
        !            67: {
        !            68:     struct sig_list *p;
        !            69:     for (p = siglist; p; p = p->next)
        !            70:        if (p->pos == pos)
        !            71:            return 1;
        !            72:     return 0;
        !            73: }
        !            74: static void sig_list_clear(void)
        !            75: {
        !            76:     struct sig_list *p, *n;
        !            77:     for (p = siglist; p; p = n) {
        !            78:        n = p->next;
        !            79:        free(p);
        !            80:     }
        !            81:     siglist = NULL;
1.1.1.6   root       82: }
1.1.1.7 ! root       83: 
1.1.1.6   root       84: /* Merge signatures from userid in fkey (which is keyfile) at keypos with
                     85:  * userid from fring (which is ringfile) at ringpos, appending result to out.
                     86:  */
1.1.1.7 ! root       87: static int mergesigs(FILE * fkey, char *keyfile, long keypos, FILE * fring,
        !            88:                     char *ringfile, long *pringpos, FILE * out)
1.1.1.6   root       89: {
1.1.1.7 ! root       90:     long ringuseridpos, ringpos;
        !            91:     int ringpktlen, keypktlen;
        !            92:     int status;
        !            93:     byte ctb;
        !            94:     int copying;
        !            95:     word32 rstamp, kstamp, xstamp;
        !            96:     byte keyID[KEYFRAGSIZE];
        !            97:     char userid[256];
        !            98: 
        !            99:     /* First, copy the userid packet itself, plus any comments or ctrls */
        !           100:     ringuseridpos = ringpos = *pringpos;
        !           101:     fseek(fring, ringpos, SEEK_SET);
        !           102:     (void) readkeypacket(fring, FALSE, &ctb, NULL, userid, NULL, NULL,
        !           103:                         NULL, NULL, NULL, NULL, NULL, NULL);
        !           104:     PascalToC(userid);
        !           105:     ringpktlen = ftell(fring) - ringpos;
        !           106:     copyfilepos(fring, out, ringpktlen, ringpos);
        !           107:     for (;;) {
        !           108:        ringpos = ftell(fring);
        !           109:        status = nextkeypacket(fring, &ctb);
        !           110:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID ||
        !           111:            is_ctb_type(ctb, CTB_SKE_TYPE))
        !           112:            break;
1.1.1.6   root      113:        ringpktlen = ftell(fring) - ringpos;
1.1.1.7 ! root      114:        copyfilepos(fring, out, ringpktlen, ringpos);
        !           115:     }
        !           116:     fseek(fring, ringpos, SEEK_SET);
        !           117: 
        !           118:     /* Now, ringpos points just past userid packet and ctrl packet. */
        !           119:     /* Advance keypos to the analogous location. */
        !           120:     fseek(fkey, keypos, SEEK_SET);
        !           121:     (void) nextkeypacket(fkey, &ctb);
        !           122:     for (;;) {
        !           123:        keypos = ftell(fkey);
        !           124:        status = nextkeypacket(fkey, &ctb);
        !           125:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID ||
        !           126:            is_ctb_type(ctb, CTB_SKE_TYPE))
        !           127:            break;
        !           128:     }
        !           129:     fseek(fkey, keypos, SEEK_SET);
        !           130: 
        !           131:     /* Second, copy all keyfile signatures that aren't in ringfile.
        !           132:      */
        !           133: 
        !           134:     copying = FALSE;
        !           135:     for (;;) {
        !           136:        /* Read next sig from keyfile; see if it is in ringfile;
        !           137:         * if it is not a signature, ignore it,
        !           138:         * if it is absent from ringfile, copy it,
        !           139:         * if it is present, and the timestamp is not newer, ignore it,
        !           140:         * if present and newer, replace old with new.
        !           141:         * Loop till hit a new key or userid in keyfile, or EOF.
1.1.1.6   root      142:         */
1.1.1.7 ! root      143:        keypos = ftell(fkey);
        !           144:        status = readkeypacket(fkey, FALSE, &ctb, (byte *) & kstamp,
        !           145:                               NULL, NULL, NULL,
        !           146:                               NULL, NULL, NULL, NULL, keyID, NULL);
        !           147:        if (status == -3)       /* unrecoverable error: bad packet
        !           148:                                   length etc. */
        !           149:            return status;
        !           150:        keypktlen = ftell(fkey) - keypos;
        !           151:        if (status == -1 || is_key_ctb(ctb) || ctb == CTB_USERID)
        !           152:            break;              /* EOF or next key/userid */
        !           153:        if (status < 0)
        !           154:            continue;           /* bad packet, skip it */
        !           155:        if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !           156:            long sig_pos;
        !           157:            int sig_len;
        !           158:            /* Set copying true if signature is not in the ringfile */
        !           159:            copying = (getpubusersig(ringfile, ringuseridpos,
        !           160:                                     keyID, (byte *) & rstamp,
        !           161:                                     &sig_pos,
        !           162:                                     &sig_len) < 0);
        !           163:            if (!copying) {
        !           164:                long save_pos = ftell(fkey);
        !           165:                fseek(fkey, keypos + 6, SEEK_SET);
        !           166:                fread(&kstamp, 1, SIZEOF_TIMESTAMP, fkey);
        !           167:                fseek(fkey, save_pos, SEEK_SET);
        !           168:                convert_byteorder((byte *) & kstamp, SIZEOF_TIMESTAMP);
        !           169:                if (verbose)
        !           170:                    fprintf(pgpout, "ring: %lx  key: %lx\n", rstamp, kstamp);
        !           171:                if (kstamp > rstamp) {  /* Update, Maybe */
        !           172:                    char *signator;
        !           173:                    if ((signator = user_from_keyID(keyID)) == NULL) {
        !           174:                        fprintf(pgpout,
        !           175:               LANG("Replacing signature from keyID %s on userid \"%s\"\n"),
        !           176:                                keyIDstring(keyID), LOCAL_CHARSET(userid));
        !           177:                        /* No pubkey for KeyID, no update! */
        !           178:                    } else {
        !           179:                        long save_keypos;
        !           180:                        long save_ringpos;
        !           181:                        long KeyIDpos;
        !           182:                        int KeyIDlen;
        !           183:                        byte sigClass;
        !           184:                        fprintf(pgpout,
        !           185:                                LANG("Verifying signature from %s\n"),
        !           186:                                LOCAL_CHARSET(signator));
        !           187:                        fprintf(pgpout, LANG("on userid \"%s\"\n"),
        !           188:                                LOCAL_CHARSET(userid));
        !           189:                        save_keypos = ftell(fkey);
        !           190:                        save_ringpos = ftell(fring);
        !           191:                        status = getpublickey(GPK_GIVEUP, ringfile,
        !           192:                                              &KeyIDpos, &KeyIDlen, NULL,
        !           193:                                              NULL, (byte *) userid, NULL,
        !           194:                                              NULL);
        !           195:                        if (!status)
        !           196:                            status = check_key_sig(fring,
        !           197:                                                   KeyIDpos, KeyIDlen,
        !           198:                                                   userid, fkey, keypos,
        !           199:                                                   ringfile, signator,
        !           200:                                                   (byte *) & xstamp,
        !           201:                                                   &sigClass);
        !           202:                        PascalToC(userid);
        !           203:                        PascalToC(signator);
        !           204:                        if (!status) {
        !           205:                            fprintf(pgpout,
        !           206:                                    LANG("Replacing signature from %s\n"),
        !           207:                                    LOCAL_CHARSET(signator));
        !           208:                            fprintf(pgpout,
        !           209:                                    LANG("on userid \"%s\"\n"),
        !           210:                                    LOCAL_CHARSET(userid));
        !           211:                            sig_list_add(sig_pos);
        !           212:                            ++newsigs;
        !           213:                            copying = 1;
        !           214:                        } else
        !           215:                            fprintf(pgpout, LANG("Verification Failed\n"));
        !           216:                        fseek(fring, save_ringpos, SEEK_SET);
        !           217:                        fseek(fkey, save_keypos, SEEK_SET);
        !           218:                    }
        !           219:                }
        !           220:            } else {
        !           221:                char *signator;
        !           222:                if ((signator = user_from_keyID(keyID)) == NULL)
        !           223:                    fprintf(pgpout,
        !           224:                       LANG("New signature from keyID %s on userid \"%s\"\n"),
        !           225:                            keyIDstring(keyID), LOCAL_CHARSET(userid));
        !           226:                else {
        !           227:                    fprintf(pgpout,
        !           228:                            LANG("New signature from %s\n"),
        !           229:                            LOCAL_CHARSET(signator));
        !           230:                    fprintf(pgpout,
        !           231:                            LANG("on userid \"%s\"\n"), LOCAL_CHARSET(userid));
        !           232:                }
        !           233:                ++newsigs;
        !           234:                if (batchmode)
        !           235:                    show_update(keyIDstring(mykeyID));
        !           236:            }
        !           237:        }
        !           238:        if (copying && is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !           239:            copyfilepos(fkey, out, keypktlen, keypos);
        !           240:            if (publickey)
        !           241:                write_trust(out, KC_SIGTRUST_UNDEFINED);
        !           242:        }
        !           243:     }
        !           244: 
        !           245:     /* Third, for all ring sig's which are not replaced, copy to output */
        !           246:     fseek(fring, ringpos, SEEK_SET);
        !           247:     for (;;) {
        !           248:        ringpos = ftell(fring);
        !           249:        if (sig_list_find(ringpos)) {
        !           250:            /* skip signature packet */
        !           251:            nextkeypacket(fring, &ctb);
        !           252:            ringpos = ftell(fring);
        !           253:            /* skip trust packet, if present */
        !           254:            if (nextkeypacket(fring, &ctb) < 0 || ctb != CTB_KEYCTRL)
        !           255:                fseek(fring, ringpos, SEEK_SET);
        !           256:            continue;
1.1.1.6   root      257:        }
1.1.1.7 ! root      258:        status = nextkeypacket(fring, &ctb);
        !           259:        ringpktlen = ftell(fring) - ringpos;
        !           260:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
        !           261:            break;
        !           262:        copyfilepos(fring, out, ringpktlen, ringpos);
        !           263:     }                          /* End of loop for each sig in ringfile */
        !           264:     sig_list_clear();
        !           265:     fseek(fring, ringpos, SEEK_SET);
        !           266:     *pringpos = ringpos;
        !           267:     return 0;
        !           268: }                              /* mergesigs */
1.1.1.6   root      269: 
                    270: /* Merge key from fkey (which is keyfile) at keypos with key from
                    271:  * fring (which is ringfile) at ringpos, appending result to out.
                    272:  */
1.1.1.7 ! root      273: static int mergekeys(FILE * fkey, char *keyfile, long keypos, FILE * fring,
        !           274:                     char *ringfile, long *pringpos, FILE * out)
1.1.1.6   root      275: {
1.1.1.7 ! root      276:     long ringkeypos, keykeypos, ringpos;
        !           277:     int ringpktlen, keypktlen;
        !           278:     int status;
        !           279:     byte ctb;
        !           280:     int copying;
        !           281:     boolean ring_compromise = FALSE;
        !           282:     byte userid[256];
        !           283: 
        !           284:     /* First, copy the key packet itself, plus any comments or ctrls */
        !           285:     ringkeypos = ringpos = *pringpos;
        !           286:     fseek(fring, ringpos, SEEK_SET);
        !           287:     (void) nextkeypacket(fring, &ctb);
        !           288:     ringpktlen = ftell(fring) - ringpos;
        !           289:     copyfilepos(fring, out, ringpktlen, ringpos);
        !           290:     for (;;) {
        !           291:        ringpos = ftell(fring);
        !           292:        status = nextkeypacket(fring, &ctb);
        !           293:        if (status < 0 || is_key_ctb(ctb) || ctb == CTB_USERID)
        !           294:            break;
        !           295:        if (is_ctb_type(ctb, CTB_SKE_TYPE))
        !           296:            ring_compromise = TRUE;     /* compromise cert on keyring */
1.1.1.6   root      297:        ringpktlen = ftell(fring) - ringpos;
1.1.1.7 ! root      298:        copyfilepos(fring, out, ringpktlen, ringpos);
        !           299:     }
        !           300:     fseek(fring, ringpos, SEEK_SET);
        !           301: 
        !           302:     /* Now, ringpos points just past key packet and ctrl packet. */
        !           303:     /* Advance keypos to the analogous location. */
        !           304:     fseek(fkey, keypos, SEEK_SET);
        !           305:     keykeypos = keypos;
        !           306:     (void) nextkeypacket(fkey, &ctb);
        !           307:     keypktlen = ftell(fkey) - keypos;  /* for check_key_sig() */
        !           308:     for (;;) {
        !           309:        keypos = ftell(fkey);
        !           310:        status = nextkeypacket(fkey, &ctb);
        !           311:        if (status < 0 || ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE))
        !           312:            break;
        !           313:     }
        !           314:     if (!ring_compromise && is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !           315:        /* found a compromise cert on keyfile that is not in ringfile */
        !           316:        word32 timestamp;
        !           317:        byte sig_class;
        !           318:        int cert_pktlen;
1.1.1.6   root      319: 
1.1.1.7 ! root      320:        cert_pktlen = ftell(fkey) - keypos;
        !           321:        if (check_key_sig(fkey, keykeypos, keypktlen,
        !           322:                          (char *) userid, fkey, keypos,
        !           323:                          ringfile, (char *) userid, (byte *) & timestamp,
        !           324:                          &sig_class) == 0 &&
        !           325:            sig_class == KC_SIGNATURE_BYTE) {
        !           326:            PascalToC((char *) userid);
        !           327:            fprintf(pgpout, LANG("Key revocation certificate from \"%s\".\n"),
        !           328:                    LOCAL_CHARSET((char *) userid));
        !           329:            copyfilepos(fkey, out, cert_pktlen, keypos);
        !           330:            /* Show updates */
        !           331:            if (batchmode)
        !           332:                show_key(fring, *pringpos, SHOW_CHANGE);
        !           333:            ++newrvks;
        !           334:        } else
        !           335:            fprintf(pgpout,
        !           336:      LANG("\n\007WARNING:  File '%s' contains bad revocation certificate.\n"),
        !           337:                    keyfile);
        !           338:     }
        !           339:     fseek(fkey, keypos, SEEK_SET);
        !           340: 
        !           341:     /* Second, copy all keyfile userid's plus signatures that aren't
        !           342:      * in ringfile.
        !           343:      */
        !           344: 
        !           345:     copying = FALSE;
        !           346:     for (;;) {
        !           347:        /* Read next userid from keyfile; see if it is in ringfile;
        !           348:         * set copying true/false accordingly.  If copying is true
        !           349:         * and it is a userid or a signature, copy it.  Loop till hit
        !           350:         * a new key in keyfile, or EOF.
1.1.1.6   root      351:         */
1.1.1.7 ! root      352:        keypos = ftell(fkey);
        !           353:        status = readkeypacket(fkey, FALSE, &ctb, NULL, (char *) userid, NULL,
        !           354:                               NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        !           355:        if (status == -3) /* unrecoverable error: bad packet length etc. */
        !           356:            return status;
        !           357:        keypktlen = ftell(fkey) - keypos;
        !           358:        if (status == -1 || is_key_ctb(ctb))
        !           359:            break;              /* EOF or next key */
        !           360:        if (status < 0)
        !           361:            continue;           /* bad packet, skip it */
        !           362:        if (ctb == CTB_USERID) {
        !           363:            long userid_pos;
        !           364:            int userid_len;
        !           365:            PascalToC((char *) userid);
        !           366:            /* Set copying true if userid is not in the ringfile */
        !           367:            copying = (getpubuserid(ringfile, ringkeypos, userid, &userid_pos,
        !           368:                                    &userid_len, TRUE) < 0);
        !           369:            if (copying) {
        !           370:                putc('\n', pgpout);
        !           371:                fprintf(pgpout, LANG("New userid: \"%s\".\n"),
        !           372:                        LOCAL_CHARSET((char *) userid));
        !           373:                fprintf(pgpout,
        !           374:                        LANG("\nWill be added to the following key:\n"));
        !           375:                show_key(fring, *pringpos, 0);
        !           376:                fprintf(pgpout, LANG("\nAdd this userid (y/N)? "));
        !           377:                if (batchmode || getyesno('n')) {
        !           378:                    ++newids;
        !           379:                    /* Show an update string */
        !           380:                    if (batchmode) {
        !           381:                        fprintf(pgpout, "\n");
        !           382:                        show_key(fring, *pringpos, SHOW_CHANGE);
        !           383:                    }
        !           384:                } else {
        !           385:                    copying = FALSE;
        !           386:                }
        !           387:            }
        !           388:        }
        !           389:        if (copying) {
        !           390:            if (ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !           391:                copyfilepos(fkey, out, keypktlen, keypos);
        !           392:                if (publickey) {
        !           393:                    if (is_ctb_type(ctb, CTB_SKE_TYPE))
        !           394:                        write_trust(out, KC_SIGTRUST_UNDEFINED);
        !           395:                    else
        !           396:                        write_trust(out, KC_LEGIT_UNKNOWN);
        !           397:                }
        !           398:            }
        !           399:        }
        !           400:     }
        !           401: 
        !           402:     /* Third, for all ring userid's, if not in keyfile, copy the userid
        !           403:      * plus its dependant signatures.
        !           404:      */
        !           405:     fseek(fring, ringpos, SEEK_SET);
        !           406:     /* Grab the keyID here */
        !           407:     readkeypacket(fring, FALSE, &ctb, NULL, (char *) userid, NULL, NULL,
        !           408:                  NULL, NULL, NULL, NULL, NULL, NULL);
        !           409:     fseek(fring, ringpos, SEEK_SET);
        !           410:     for (;;) {
        !           411:        ringpos = ftell(fring);
        !           412:        status = readkeypacket(fring, FALSE, &ctb, NULL,
        !           413:                               (char *) userid, NULL, NULL,
        !           414:                               NULL, NULL, NULL, NULL, NULL, NULL);
        !           415:        ringpktlen = ftell(fring) - ringpos;
        !           416:        if (status == -3)
        !           417:            return status;
        !           418:        if (status == -1 || is_key_ctb(ctb))
        !           419:            break;
        !           420:        if (ctb == CTB_USERID) {
        !           421:            long userid_pos;
        !           422:            int userid_len;
        !           423:            /* See if there is a match in keyfile */
        !           424:            PascalToC((char *) userid);
        !           425:            /* don't use substring match (exact_match = TRUE) */
        !           426:            if (getpubuserid(keyfile, keykeypos, userid,
        !           427:                             &userid_pos, &userid_len, TRUE) >= 0) {
        !           428:                if ((status = mergesigs(fkey, keyfile, userid_pos,
        !           429:                                        fring, ringfile, &ringpos, out)) < 0)
        !           430:                    return status;
        !           431:                copying = FALSE;
        !           432:            } else {
        !           433:                copying = TRUE;
        !           434:            }
        !           435:        }
        !           436:        if (copying) {
        !           437:            /* Copy ringfile userid and sigs to out */
        !           438:            copyfilepos(fring, out, ringpktlen, ringpos);
        !           439:        }
        !           440:     }                          /* End of loop for each key in ringfile */
        !           441:     fseek(fring, ringpos, SEEK_SET);
        !           442:     *pringpos = ringpos;
        !           443:     return 0;
        !           444: }                              /* mergekeys */
1.1.1.6   root      445: 
                    446: /* Adds (prepends) key file to key ring file. */
1.1.1.7 ! root      447: int _addto_keyring(char *keyfile, char *ringfile)
1.1.1.6   root      448: {
1.1.1.7 ! root      449:     FILE *f, *g, *h;
        !           450:     long file_position, fp;
        !           451:     int pktlen;
        !           452:     byte ctb;
        !           453:     int status;
        !           454:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
        !           455:     unit n1[MAX_UNIT_PRECISION];
        !           456:     byte keyID[KEYFRAGSIZE];
        !           457:     byte userid[256];          /* key certificate userid */
        !           458:     byte userid1[256];
        !           459:     word32 tstamp;
        !           460:     byte *timestamp = (byte *) & tstamp;       /* key certificate timestamp */
        !           461:     boolean userid_seen = FALSE;
        !           462:     int commonkeys = 0;
        !           463:     int copying;
        !           464:     struct newkey *nkey, *nkeys = NULL;
        !           465:     char *scratchf;
        !           466: 
        !           467:     /* open file f for read, in binary (not text) mode... */
        !           468:     if ((f = fopen(keyfile, FOPRBIN)) == NULL) {
        !           469:        fprintf(pgpout, LANG("\n\007Can't open key file '%s'\n"), keyfile);
        !           470:        return -1;
        !           471:     }
        !           472:     ctb = 0;
        !           473:     if (fread(&ctb, 1, 1, f) != 1 || !is_key_ctb(ctb)) {
        !           474:        fclose(f);
        !           475:        return -1;
        !           476:     }
        !           477:     rewind(f);
1.1.1.6   root      478: 
1.1.1.7 ! root      479:     setoutdir(ringfile);
        !           480:     scratchf = tempfile(0);
1.1.1.6   root      481: 
1.1.1.7 ! root      482:     /*
        !           483:      * get userids from both files, maybe should also use the default public
        !           484:      * keyring if ringfile is not the default ring.
        !           485:      */
        !           486:     setkrent(ringfile);
        !           487:     setkrent(keyfile);
        !           488:     init_userhash();
        !           489: 
        !           490:     if (!file_exists(ringfile)) {
        !           491:        /* ringfile does not exist.  Can it be created? */
        !           492:        /* open file g for writing, in binary (not text) mode... */
        !           493:        g = fopen(ringfile, FOPWBIN);
        !           494:        if (g == NULL) {
        !           495:            fprintf(pgpout,
        !           496:                    LANG("\nKey ring file '%s' cannot be created.\n"),
        !           497:                    ringfile);
        !           498:            fclose(f);
        !           499:            goto err;
1.1.1.6   root      500:        }
1.1.1.7 ! root      501:        fclose(g);
        !           502:     }
        !           503:     /* Create working output file */
        !           504:     /* open file g for writing, in binary (not text) mode... */
        !           505:     if ((g = fopen(scratchf, FOPWBIN)) == NULL) {
        !           506:        fclose(f);
        !           507:        goto err;
        !           508:     }
        !           509:     newkeys = newsigs = newids = newrvks = 0;
        !           510: 
        !           511:     /* Pass 1 - copy all keys from f which aren't in ring file */
        !           512:     /* Also copy userid and signature packets. */
        !           513:     fprintf(pgpout, LANG("\nLooking for new keys...\n"));
        !           514:     copying = FALSE;
        !           515:     if (gpk_open(ringfile) < 0) {
        !           516:        fclose(f);              /* close key file */
        !           517:        fclose(g);
        !           518:        goto err;
        !           519:     }
        !           520:     for (;;) {
        !           521:        file_position = ftell(f);
        !           522: 
        !           523:        status = readkeypacket(f, FALSE, &ctb,
        !           524:                               timestamp, (char *) userid, n, e,
        !           525:                               NULL, NULL, NULL, NULL, NULL, NULL);
        !           526:        /* Note that readkeypacket has called set_precision */
        !           527:        if (status == -1)       /* EOF */
        !           528:            break;
        !           529:        if (status == -2 || status == -3) {
        !           530:            fprintf(pgpout,
        !           531:                    LANG("\n\007Could not read key from file '%s'.\n"),
        !           532:                    keyfile);
        !           533:            fclose(f);          /* close key file */
        !           534:            fclose(g);
        !           535:            goto err;
        !           536:        }
        !           537:        if (status < 0) {
        !           538:            copying = FALSE;
        !           539:            continue;   /* don't merge keys from unrecognized version */
        !           540:        }
        !           541:        /* Check to see if key is already on key ring */
        !           542:        if (is_key_ctb(ctb)) {
        !           543:            extract_keyID(keyID, n);    /* from keyfile, not ringfile */
        !           544:            publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE);
        !           545: 
        !           546:            /*      Check for duplicate key in key ring: */
        !           547:            status = get_publickey(&fp, NULL, keyID, timestamp, userid, n1, e);
        !           548:            if (status == 0) {
        !           549:                /* key in both keyring and keyfile */
        !           550:                if (mp_compare(n, n1) != 0) {
        !           551:                    fprintf(pgpout,
        !           552: LANG("\n\007Warning: Key ID %s matches key ID of key already on \n\
1.1.1.6   root      553: key ring '%s', but the keys themselves differ.\n\
                    554: This is highly suspicious.  This key will not be added to ring.\n\
                    555: Acknowledge by pressing return: "), keyIDstring(keyID), ringfile);
1.1.1.7 ! root      556:                    getyesno('n');
        !           557:                } else {
        !           558:                    ++commonkeys;
        !           559:                }
        !           560:                copying = FALSE;
        !           561:            } else if (status == -1) {  /* key NOT in keyring */
        !           562:                ++newkeys;
        !           563:                if (interactive_add) {
        !           564:                    if (!show_key(f, file_position, SHOW_ALL)) {
        !           565:                        fprintf(pgpout,
        !           566:               LANG("\nDo you want to add this key to keyring '%s' (y/N)? "),
        !           567:                            ringfile);
        !           568:                        copying = getyesno('n');
        !           569:                    } else
        !           570:                        copying = FALSE;
        !           571:                } else {
        !           572:                    if (!show_key(f, file_position, SHOW_LISTFMT)) 
        !           573:                        copying = TRUE;
        !           574:                    else
        !           575:                        copying = FALSE;
        !           576:                }
        !           577: 
        !           578:                /* If batchmode, output an update message */
        !           579:                if (batchmode)
        !           580:                    show_key(f, file_position, SHOW_CHANGE);
        !           581:                if (copying) {
        !           582:                    nkey = xmalloc(sizeof(*nkey));
        !           583:                    memcpy(nkey->keyID, keyID, KEYFRAGSIZE);
        !           584:                    nkey->next = nkeys;
        !           585:                    nkeys = nkey;
        !           586:                }
        !           587:            } else {
        !           588:                /* unknown version or bad key */
        !           589:                copying = FALSE;
        !           590:            }
1.1.1.6   root      591:        }
                    592:        /*
1.1.1.7 ! root      593:         * Now, we copy according to the copying flag
        !           594:         * The key is prepended to the ring to give it search
        !           595:         *  precedence over other keys with that same userid.
1.1.1.6   root      596:         */
1.1.1.7 ! root      597:        if (copying && (is_key_ctb(ctb) || ctb == CTB_USERID ||
        !           598:                        is_ctb_type(ctb, CTB_SKE_TYPE))) {
        !           599:            pktlen = (int) (ftell(f) - file_position);
        !           600:            copyfilepos(f, g, pktlen, file_position); /* copy packet from f */
        !           601:            if (publickey) {
        !           602:                /* Initialize trust packets after keys and signatures */
        !           603:                if (is_key_ctb(ctb)) {
        !           604:                    write_trust(g, KC_OWNERTRUST_UNDEFINED);
        !           605:                    userid_seen = FALSE;
        !           606:                } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !           607:                    if (userid_seen) {
        !           608:                        write_trust(g, KC_SIGTRUST_UNDEFINED);
        !           609:                    } else {
        !           610:            /* signature certificate before userid must be compromise cert. */
        !           611:                        fprintf(pgpout, LANG("Key has been revoked.\n"));
        !           612:                    }
        !           613:                } else if (is_ctb_type(ctb, CTB_USERID_TYPE)) {
        !           614:                    write_trust(g, KC_LEGIT_UNKNOWN);
        !           615:                    userid_seen = TRUE;
        !           616:                }
        !           617:            }
        !           618:        }
        !           619:     }
        !           620:     gpk_close();
        !           621: 
        !           622:     /*
        !           623:      * Now copy the remainder of the ringfile, h, to g.  commonkeys tells
        !           624:      * how many keys are common to keyfile and ringfile.  As long as that
        !           625:      * is nonzero we will check each key in ringfile to see if it has a
        !           626:      * match in keyfile.
        !           627:      */
        !           628:     if ((h = fopen(ringfile, FOPRBIN)) != NULL) {
        !           629:        if (gpk_open(keyfile) < 0) {
        !           630:            fclose(f);
        !           631:            fclose(g);
        !           632:            fclose(h);
        !           633:            goto err;
        !           634:        }
        !           635:        while (commonkeys) {
        !           636:            /* Loop for each key in ringfile */
        !           637:            file_position = ftell(h);
        !           638:            status = readkeypacket(h, FALSE, &ctb, NULL, (char *) userid, n, e,
        !           639:                                   NULL, NULL, NULL, NULL, NULL, NULL);
        !           640:            if (status == -1 || status == -3) {
        !           641:                if (status == -1)       /* hit EOF */
        !           642:                    fprintf(pgpout,
        !           643: LANG("\n\007Key file contains duplicate keys: cannot be added to keyring\n"));
        !           644:                else
        !           645:                    fprintf(pgpout,
        !           646: LANG("\n\007Could not read key from file '%s'.\n"),
        !           647:                            ringfile);
        !           648:                fclose(f);
1.1.1.6   root      649:                fclose(g);
1.1.1.7 ! root      650:                fclose(h);
1.1.1.6   root      651:                goto err;
1.1.1.7 ! root      652:            }
        !           653:            PascalToC((char *) userid);
        !           654:            pktlen = ftell(h) - file_position;
        !           655:            if (is_key_ctb(ctb)) {
        !           656:                long tfp;
        !           657: /* unknown version or bad data: copy (don't remove packets from ringfile) */
        !           658:                copying = TRUE;
        !           659:                if (status == 0) {
        !           660:                    /* See if there is a match in keyfile */
        !           661:                    extract_keyID(keyID, n);    /* from ringfile,
        !           662:                                                   not keyfile */
        !           663:                    extract_keyID(mykeyID, n);  /* save this */
        !           664:                    publickey = is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE);
        !           665:                    if (get_publickey(&tfp, NULL, keyID,
        !           666:                                      timestamp, userid1, n1, e) >= 0) {
        !           667:                        if (verbose)
        !           668:                            fprintf(pgpout, 
        !           669:                                    "Merging key ID: %s\n",
        !           670:                                    keyIDstring(keyID));
        !           671:                        if (mergekeys(f, keyfile, tfp, h,
        !           672:                                      ringfile, &file_position, g) < 0) {
        !           673:                            fclose(f);
        !           674:                            fclose(g);
        !           675:                            fclose(h);
        !           676:                            goto err;
        !           677:                        }
        !           678:                        copying = FALSE;
        !           679:                        --commonkeys;
        !           680:                    }
        !           681:                }
        !           682:            }
        !           683:            if (copying) {
        !           684:                /* Copy ringfile key to g, without its sigs */
        !           685:                copyfilepos(h, g, pktlen, file_position);
        !           686:                file_position += pktlen;
        !           687:            }
        !           688:        }                       /* End of loop for each key in ringfile */
        !           689:        gpk_close();
        !           690:        copyfile(h, g, -1L);    /* copy rest of file from file h to g */
        !           691:        fclose(h);
        !           692:     }
        !           693:     fclose(f);
        !           694:     if (write_error(g)) {
1.1.1.6   root      695:        fclose(g);
1.1.1.7 ! root      696:        goto err;
        !           697:     }
        !           698:     fclose(g);
        !           699:     if (newsigs == 0 && newkeys == 0 && newids == 0 && newrvks == 0) {
        !           700:        fprintf(pgpout, LANG("No new keys or signatures in keyfile.\n"));
1.1.1.6   root      701:        rmtemp(scratchf);
1.1.1.7 ! root      702:        endkrent();
        !           703:        return 0;
        !           704:     }
        !           705:     if (status = dokeycheck(NULL, scratchf, CHECK_NEW)) {
        !           706:        if (verbose)
        !           707:            fprintf(pgpout, "addto_keyring: dokeycheck returned %d\n", status);
        !           708:        goto err;
        !           709:     }
        !           710:     endkrent();
        !           711: 
        !           712:     fprintf(pgpout, LANG("\nKeyfile contains:\n"));
        !           713:     if (newkeys)
        !           714:        fprintf(pgpout, LANG("%4d new key(s)\n"), newkeys);
        !           715:     if (newsigs)
        !           716:        fprintf(pgpout, LANG("%4d new signatures(s)\n"), newsigs);
        !           717:     if (newids)
        !           718:        fprintf(pgpout, LANG("%4d new user ID(s)\n"), newids);
        !           719:     if (newrvks)
        !           720:        fprintf(pgpout, LANG("%4d new revocation(s)\n"), newrvks);
        !           721: 
        !           722:     ask_first = TRUE;
        !           723:     status = maint_update(scratchf, nkeys);
        !           724:     if (status >= 0 && !filter_mode && !batchmode)
        !           725:        for (nkey = nkeys; nkey; nkey = nkey->next)
        !           726:            if (ask_to_sign(nkey->keyID, scratchf) != 0)
        !           727:                break;
        !           728:     if (status && verbose)
        !           729:        fprintf(pgpout, "addto_keyring: maint_update returned %d\n", status);
        !           730: 
        !           731:     free_newkeys(nkeys);
        !           732: 
        !           733:     savetempbak(scratchf, ringfile);
        !           734: 
        !           735:     return 0;                  /* normal return */
        !           736: 
        !           737:   err:
        !           738:     gpk_close();               /* save to call if not opened */
        !           739:     endkrent();
        !           740:     /* make sure we remove any garbage files we may have created */
        !           741:     rmtemp(scratchf);
        !           742:     return -1;
        !           743: }                              /* _addto_keyring */
1.1.1.6   root      744: 
                    745: int addto_keyring(char *keyfile, char *ringfile)
                    746: {
1.1.1.7 ! root      747:     long armorline = 0;
        !           748:     char *tempf;
        !           749:     int addflag = 0;
1.1.1.6   root      750: 
1.1.1.7 ! root      751:     if (_addto_keyring(keyfile, ringfile) == 0)
        !           752:        return 0;
        !           753:     /* check if the keyfile to be added is armored */
        !           754:     while (is_armor_file(keyfile, armorline)) {
        !           755:        tempf = tempfile(TMP_TMPDIR | TMP_WIPE);
        !           756:        if (de_armor_file(keyfile, tempf, &armorline)) {
        !           757:            rmtemp(tempf);
        !           758:            return -1;
        !           759:        }
        !           760:        if (_addto_keyring(tempf, ringfile) == 0)
        !           761:            addflag = 1;
        !           762:        rmtemp(tempf);
        !           763:     }
        !           764:     if (!addflag) {
        !           765:        fprintf(pgpout, LANG("\nNo keys found in '%s'.\n"), keyfile);
        !           766:        return -1;
        !           767:     } else {
        !           768:        return 0;
        !           769:     }
        !           770: }
1.1.1.6   root      771: 
1.1.1.7 ! root      772: static int ask_to_sign(byte * keyID, char *ringfile)
1.1.1.6   root      773: {
1.1.1.7 ! root      774:     FILE *f;
        !           775:     word32 timestamp;
        !           776:     byte ctb, trust;
        !           777:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
        !           778:     byte userid[256];
        !           779:     long fpos;
        !           780:     int status;
        !           781:     extern char my_name[];
1.1.1.6   root      782: 
1.1.1.7 ! root      783:     if (getpublickey(GPK_GIVEUP, ringfile, &fpos, NULL, keyID,
        !           784:                     (byte *) & timestamp, userid, n, e) < 0)
        !           785:        return -1;
1.1.1.6   root      786: 
1.1.1.7 ! root      787:     if ((f = fopen(ringfile, FOPRBIN)) == NULL)
        !           788:        return -1;
1.1.1.6   root      789: 
1.1.1.7 ! root      790:     fseek(f, fpos, SEEK_SET);
        !           791:     if (is_compromised(f)) {
1.1.1.6   root      792:        fclose(f);
                    793:        return 0;
1.1.1.7 ! root      794:     }
        !           795:     if (nextkeypacket(f, &ctb) < 0) {
        !           796:        fclose(f);
        !           797:        return -1;
        !           798:     }
        !           799:     if (ctb != CTB_CERT_PUBKEY) {
        !           800:        fclose(f);
        !           801:        return 0;               /* don't ask to sign secret key */
        !           802:     }
        !           803:     while (nextkeypacket(f, &ctb) == 0 && !is_key_ctb(ctb))
        !           804:        if (ctb == CTB_USERID)  /* check first userid */
        !           805:            break;
        !           806:     if (ctb != CTB_USERID) {
        !           807:        fclose(f);
        !           808:        return -1;
        !           809:     }
        !           810:     if ((status = read_trust(f, &trust)) < 0) {
        !           811:        fclose(f);
        !           812:        return status;
        !           813:     }
        !           814:     if ((trust & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE) {
        !           815:        fclose(f);
        !           816:        return 0;
        !           817:     }
        !           818:     if (ask_first) {
        !           819:        /* shortcut for adding big keyfile */
        !           820:        fprintf(pgpout,
        !           821:        LANG("\nOne or more of the new keys are not fully certified.\n\
        !           822: Do you want to certify any of these keys yourself (y/N)? "));
        !           823:        if (!getyesno('n')) {
        !           824:            fclose(f);
        !           825:            return 1;
        !           826:        }
        !           827:     }
        !           828:     ask_first = FALSE;
        !           829:     show_key(f, fpos, SHOW_ALL | SHOW_HASH);
        !           830:     fclose(f);
        !           831:     PascalToC((char *) userid);
        !           832:     fprintf(pgpout,
        !           833:            LANG("\nDo you want to certify this key yourself (y/N)? "));
        !           834:     if (getyesno('n')) {
        !           835:        if (signkey((char *) userid, my_name, ringfile) == 0)
        !           836:            maint_update(ringfile, 0);
        !           837:     }
        !           838:     return 0;
1.1.1.6   root      839: }
                    840: 
                    841: /**** faster version of getpublickey() ****/
                    842: 
1.1.1.7 ! root      843: static long find_keyID(byte * keyID);
1.1.1.6   root      844: 
                    845: static FILE *gpkf = NULL;
                    846: 
                    847: /*
                    848:  * speedup replacement for getpublickey(), does not have the arguments
                    849:  * giveup, showkey and keyfile (giveup = TRUE, showkey = FALSE, keyfile
                    850:  * is set with gpk_open().
                    851:  * only searches on keyID
                    852:  */
1.1.1.7 ! root      853: int get_publickey(long *file_position, int *pktlen, byte * keyID,
        !           854:                  byte * timestamp, byte * userid, unitptr n, unitptr e)
1.1.1.6   root      855: {
1.1.1.7 ! root      856:     byte ctb;                  /* returned by readkeypacket */
        !           857:     int status, keystatus = -1;
        !           858:     long fpos;
1.1.1.6   root      859: 
1.1.1.7 ! root      860:     if ((fpos = find_keyID(keyID)) == -1)
        !           861:        return -1;
        !           862:     fseek(gpkf, fpos, SEEK_SET);
1.1.1.6   root      863: 
1.1.1.7 ! root      864:     for (;;) {
        !           865:        fpos = ftell(gpkf);
        !           866:        status = readkeypacket(gpkf, FALSE, &ctb, timestamp,
        !           867:                               (char *) userid, n, e,
        !           868:                               NULL, NULL, NULL, NULL, NULL, NULL);
        !           869:        /* Note that readkeypacket has called set_precision */
        !           870: 
        !           871:        if (status < 0 && status != -4 && status != -6)
        !           872:            return status;
        !           873: 
        !           874:        /* Remember packet position and size for last key packet */
        !           875:        if (is_key_ctb(ctb)) {
        !           876:            if (file_position)
        !           877:                *file_position = fpos;
        !           878:            if (pktlen)
        !           879:                *pktlen = (int) (ftell(gpkf) - fpos);
        !           880:            if (keystatus != -1)
        !           881:                return -3; /* should not happen, probably missing userid pkt */
        !           882:            keystatus = status;
        !           883:        }
        !           884:        if (ctb == CTB_USERID)
        !           885:            return keystatus;
        !           886:     }
1.1.1.6   root      887: }
                    888: 
1.1.1.7 ! root      889: #define        PK_HASHSIZE     256     /* must be power of 2 */
1.1.1.6   root      890: #define        PK_HASH(x)              (*(byte *) (x) & (PK_HASHSIZE - 1))
                    891: #define        HASH_ALLOC      400
                    892: 
1.1.1.7 ! root      893: static VOID *allocbuf(int size);
1.1.1.6   root      894: static void freebufpool(void);
                    895: 
                    896: static struct hashent {
1.1.1.7 ! root      897:     struct hashent *next;
        !           898:     byte keyID[KEYFRAGSIZE];
        !           899:     long offset;
1.1.1.6   root      900: } **hashtbl = NULL, *hashptr;
                    901: 
                    902: static int hashleft = 0;
                    903: 
1.1.1.7 ! root      904: int gpk_open(char *keyfile)
1.1.1.6   root      905: {
1.1.1.7 ! root      906:     int status;
        !           907:     long fpos = 0;
        !           908:     byte keyID[KEYFRAGSIZE];
        !           909:     byte ctb;
1.1.1.6   root      910: 
1.1.1.7 ! root      911:     if (gpkf) {
        !           912:        fprintf(pgpout, "gpk_open: already open\n");
        !           913:        return -1;
        !           914:     }
        !           915:     default_extension(keyfile, PGP_EXTENSION);
        !           916:     if ((gpkf = fopen(keyfile, FOPRBIN)) == NULL)
        !           917:        return -1;              /* error return */
        !           918:     hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *));
        !           919:     memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *));
        !           920:     while ((status = readkpacket(gpkf, &ctb, NULL, keyID, NULL)) != -1) {
        !           921:        if (status == -2 || status == -3) {
        !           922:            fprintf(pgpout, LANG("\n\007Could not read key from file '%s'.\n"),
        !           923:                    keyfile);
        !           924:            fclose(gpkf);       /* close key file */
        !           925:            return -1;
        !           926:        }
        !           927:        if (is_key_ctb(ctb)) {
        !           928:          if (status != -4) {
        !           929:            if (find_keyID(keyID) != -1)
        !           930:                fprintf(pgpout,
        !           931:                        "Warning: duplicate key in keyring '%s'\n", keyfile);
        !           932:            if (!hashleft) {
        !           933:                hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent));
        !           934:                hashleft = HASH_ALLOC;
        !           935:            }
        !           936:            memcpy(hashptr->keyID, keyID, KEYFRAGSIZE);
        !           937:            hashptr->offset = fpos;
        !           938:            hashptr->next = hashtbl[PK_HASH(keyID)];
        !           939:            hashtbl[PK_HASH(keyID)] = hashptr;
        !           940:            ++hashptr;
        !           941:            --hashleft;
        !           942:          }
        !           943:        }
        !           944:        fpos = ftell(gpkf);
        !           945:     }
        !           946:     return 0;
        !           947: }
        !           948: 
        !           949: void gpk_close(void)
        !           950: {
        !           951:     if (!gpkf)
        !           952:        return;
        !           953:     hashleft = 0;
        !           954:     hashtbl = NULL;
        !           955:     freebufpool();
        !           956:     fclose(gpkf);              /* close key file */
        !           957:     gpkf = NULL;
1.1.1.6   root      958: }
                    959: 
                    960: /*
                    961:  * Lookup file position in hash table by keyID, returns -1 if not found
                    962:  */
1.1.1.7 ! root      963: static long find_keyID(byte * keyID)
1.1.1.6   root      964: {
1.1.1.7 ! root      965:     struct hashent *p;
1.1.1.6   root      966: 
1.1.1.7 ! root      967:     for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next)
        !           968:        if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0)
        !           969:            return p->offset;
        !           970:     return -1;
1.1.1.6   root      971: }
                    972: 
                    973: 
                    974: static struct bufpool {
1.1.1.7 ! root      975:     struct bufpool *next;
        !           976:     char buf[1];               /* variable size */
1.1.1.6   root      977: } *bufpool = NULL;
                    978: 
                    979: /*
                    980:  * allocate buffer, all buffers allocated with this function can be
                    981:  * freed with one call to freebufpool()
                    982:  */
                    983: static VOID *
1.1.1.7 ! root      984:  allocbuf(int size)
1.1.1.6   root      985: {
1.1.1.7 ! root      986:     struct bufpool *p;
1.1.1.6   root      987: 
1.1.1.7 ! root      988:     p = xmalloc(size + sizeof(struct bufpool *));
        !           989:     p->next = bufpool;
        !           990:     bufpool = p;
        !           991:     return p->buf;
1.1.1.6   root      992: }
                    993: 
                    994: /*
                    995:  * free all memory obtained with allocbuf()
                    996:  */
1.1.1.7 ! root      997: static void freebufpool(void)
1.1.1.6   root      998: {
1.1.1.7 ! root      999:     struct bufpool *p;
1.1.1.6   root     1000: 
1.1.1.7 ! root     1001:     while (bufpool) {
        !          1002:        p = bufpool;
        !          1003:        bufpool = bufpool->next;
        !          1004:        free(p);
        !          1005:     }
1.1.1.6   root     1006: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.