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

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

unix.superglobalmegacorp.com

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