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

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

unix.superglobalmegacorp.com

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