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

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

unix.superglobalmegacorp.com

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