Annotation of pgp/src/keymaint.c, revision 1.1.1.8

1.1.1.8 ! root        1: /*      keymaint.c  - Keyring maintenance pass 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:    keymaint.c implemented by Branko Lankester.
        !            22:  */
        !            23: 
        !            24: #include <stdio.h>
        !            25: #include <time.h>
        !            26: #include <stdlib.h>
        !            27: #include "mpilib.h"
        !            28: #include "random.h"
        !            29: #include "crypto.h"
        !            30: #include "fileio.h"
        !            31: #include "keymgmt.h"
        !            32: #include "keymaint.h"
        !            33: #include "mpiio.h"
        !            34: #include "charset.h"
        !            35: #include "language.h"
        !            36: #include "pgp.h"
        !            37: #ifdef MACTC5
        !            38: #include "Macutil3.h"
        !            39: #include "PGPDialogs.h"
        !            40: #include "MyBufferedStdio.h"
        !            41: #include "ReplaceStdio.h"
        !            42: #endif
        !            43: 
        !            44: #if 1                          /* def DEBUG */
        !            45: #include <assert.h>
        !            46: #else
        !            47: #define assert(x)
        !            48: #endif
        !            49: 
        !            50: /* Helper functions to work on newkey lists */
        !            51: void free_newkeys(struct newkey *nkeys)
        !            52: {
        !            53:     struct newkey *nkey;
        !            54: 
        !            55:     while (nkeys) {
        !            56:        nkey = nkeys;
        !            57:        nkeys = nkeys->next;
        !            58:        free(nkey);
        !            59:     }
        !            60: }
        !            61: 
        !            62: int ismember_newkeys(byte const keyid[KEYFRAGSIZE], struct newkey const *nkeys)
        !            63: {
        !            64:     while (nkeys) {
        !            65:        if (memcmp(keyid, nkeys->keyID, KEYFRAGSIZE) == 0)
        !            66:            return 1;
        !            67:        nkeys = nkeys->next;
        !            68:     }
        !            69:     return 0;
        !            70: }
        !            71: 
        !            72: /* The main checking code... */
        !            73: 
        !            74: struct userid;
        !            75: struct signature;
        !            76: 
        !            77: struct pubkey {
        !            78:     struct pubkey *pk_next;
        !            79:     struct pubkey *pk_hash;    /* hash list for keyID */
        !            80:     struct userid *pk_userids;
        !            81:     struct signature *pk_signed;       /* signatures this key made */
        !            82:     byte pk_keyid[KEYFRAGSIZE];
        !            83:     byte pk_owntrust;
        !            84:     byte pk_depth;             /* shortest cert. path to buckstop key */
        !            85: };
        !            86: 
        !            87: struct userid {
        !            88:     struct userid *uid_next;
        !            89:     struct pubkey *uid_key;    /* backlink to key */
        !            90:     struct signature *uid_signatures;
        !            91:     char *uid_userid;
        !            92:     byte uid_legit;
        !            93: };
        !            94: 
        !            95: struct signature {
        !            96:     struct signature *sig_next;        /* list of signatures on a userid */
        !            97:     struct userid *sig_uid;    /* the userid it signs */
        !            98:     struct pubkey *sig_from;   /* key that made this signature */
        !            99:     /* list of sigs made by the same key (sig_from) */
        !           100:     struct signature *sig_nextfrom;
        !           101:     byte sig_trust;
        !           102: };
        !           103: 
        !           104: 
        !           105: int maint_list(char *ringfile);
        !           106: void init_trust_lst(void);
        !           107: long lookup_by_keyID(FILE * f, byte * srch_keyID);
        !           108: void show_userid(FILE * f, byte * keyID);
        !           109: 
        !           110: static int maintenance(char *ringfile, struct newkey const *nkeys);
        !           111: static int maint_read_data(char *ringfile, struct newkey const *nkeys);
        !           112: static int maint_trace_chain(void);
        !           113: static int trace_sig_chain(struct pubkey *pk, int depth);
        !           114: static int maint_final(char *ringfile);
        !           115: static struct pubkey *getpubkey(byte * keyID);
        !           116: static void setup_trust(void);
        !           117: static int check_secretkey(FILE * f, long keypos, byte keyctrl);
        !           118: static void maint_init_mem(void);
        !           119: static void maint_release_mem(void);
        !           120: static VOID *allocn(int size);
        !           121: static char *store_str(char *str);
        !           122: static VOID *allocbuf(int size);
        !           123: static void freebufpool(void);
        !           124: static void compute_legit(struct userid *id);
        !           125: 
        !           126: 
        !           127: #define        ALLOC_UNIT 4000 /* memory will be allocated in chunks of this size */
        !           128: 
        !           129: #define        MAX_DEPTH  8            /* max. value of max_cert_depth */
        !           130: 
        !           131: /* returned when trying to do a maintenance pass on a
        !           132:    secret keyring or keyfile */
        !           133: #define        ERR_NOTRUST     -7
        !           134: 
        !           135: #define TRUST_MASK     7       /* mask for userid/signature trust bytes */
        !           136: #define SET_TRUST(b,v) (*(b) = (*(b) & ~TRUST_MASK) | (v))
        !           137: #define TRUST_LEV(b)   ((b) & TRUST_MASK)
        !           138: 
        !           139: #define        TRUST_FAC(x)    (trust_tbl[TRUST_LEV(x)])
        !           140: 
        !           141: #define ctb_type(c)    ((c&CTB_TYPE_MASK)>>2)
        !           142: /*
        !           143:  * table for tuning user paranoia index.
        !           144:  * values represent contribution of one signature indexed by the
        !           145:  * SIGTRUST of a signature
        !           146:  */
        !           147: static int trust_tbl[8];
        !           148: 
        !           149: static int marginal_min;
        !           150: static int complete_min;       /* total count needed for a fully legit key */
        !           151: 
        !           152: int marg_min = 2;              /* number of marginally trusted signatures
        !           153:                                   needed for a fully legit key
        !           154:                                   (can be set in config.pgp). */
        !           155: int compl_min = 1;             /* number of fully trusted signatures needed */
        !           156: 
        !           157: char trust_lst[8][16] =
        !           158: {
        !           159:     "undefined",               /* LANG("undefined") */
        !           160:     "unknown",                 /* LANG("unknown") */
        !           161:     "untrusted",               /* LANG("untrusted") */
        !           162:     "<3>",                     /* unused */
        !           163:     "<4>",                     /* unused */
        !           164:     "marginal",                        /* LANG("marginal") */
        !           165:     "complete",                        /* LANG("complete") */
        !           166:     "ultimate",                        /* LANG("ultimate") */
        !           167: };
        !           168: 
        !           169: char legit_lst[4][16] =
        !           170: {
        !           171:     "undefined",
        !           172:     "untrusted",
        !           173:     "marginal",
        !           174:     "complete"
        !           175: };
        !           176: 
        !           177: static int trustlst_len = 9;   /* length of longest trust word */
        !           178: static int legitlst_len = 9;   /* length of longest legit word */
        !           179: 
        !           180: char floppyring[MAX_PATH] = "";
        !           181: int max_cert_depth = 4;                /* maximum nesting of signatures */
        !           182: 
        !           183: static boolean check_only = FALSE;
        !           184: static boolean mverbose;
        !           185: static FILE *sec_fp;
        !           186: static FILE *floppy_fp = NULL;
        !           187: static int undefined_trust;    /* number of complete keys with undef. trust */
        !           188: 
        !           189: /*
        !           190:  * Update trust parameters in a keyring, should be called after all
        !           191:  * key management functions which can affect the trust parameters.
        !           192:  * Changes are done "inplace", the file must be writable.
        !           193:  *
        !           194:  * nkeys is a list of new keys.  Any key on this list is checked to
        !           195:  * see if it on the secret keyring.  If it is, and the BUCKSTOP bit
        !           196:  * is not set, the user is prompted to set it.
        !           197:  */
        !           198: int maint_update(char *ringfile, struct newkey const *nkeys)
        !           199: {
        !           200:     check_only = mverbose = FALSE;
        !           201:     return maintenance(ringfile, nkeys);
        !           202: }
        !           203: 
        !           204: /*
        !           205:  * Check trust parameters in ringfile
        !           206:  * options can be:
        !           207:  *      MAINT_CHECK     check only, don't ask if keyring should be updated
        !           208:  *      MAINT_VERBOSE   verbose output, shows signature chains
        !           209:  */
        !           210: int maint_check(char *ringfile, int options)
        !           211: {
        !           212:     int status;
        !           213:     char *fixfile;
        !           214: 
        !           215:     mverbose = ((options & MAINT_VERBOSE) != 0);
        !           216: 
        !           217:     if (moreflag)
        !           218:        open_more();
        !           219:     if (*floppyring != '\0' && (floppy_fp = fopen(floppyring, FOPRBIN))
        !           220:        == NULL)
        !           221:        fprintf(pgpout, LANG("\nCan't open backup key ring file '%s'\n"),
        !           222:                floppyring);
        !           223:     check_only = TRUE;
        !           224:     status = maintenance(ringfile, NULL);
        !           225:     if (floppy_fp) {
        !           226:        fclose(floppy_fp);
        !           227:        floppy_fp = NULL;
        !           228:     }
        !           229:     if (status <= 0) {
        !           230:        if (status == 0)
        !           231:            maint_list(ringfile);
        !           232:        close_more();
        !           233:        return status;
        !           234:     }
        !           235: #ifdef xDEBUG
        !           236:     if (status > 0 && (options & MAINT_CHECK)) {
        !           237:        FILE *sav = pgpout;
        !           238:        if (pgpout = fopen("before.lst", "w")) {
        !           239:            maint_list(ringfile);
        !           240:            fclose(pgpout);
        !           241:        }
        !           242:        pgpout = sav;
        !           243:     }
        !           244: #endif
        !           245:     /* Inform user of trust parameters to be changed... */
        !           246:     if (undefined_trust) {
        !           247: 
        !           248:        /* If we are just going to check, then exit now... */
        !           249:        if (options & MAINT_CHECK) {
        !           250:            maint_list(ringfile);
        !           251:        }
        !           252:        fprintf(pgpout,
        !           253:                LANG("\n%d \"trust parameter(s)\" need to be changed.\n"),
        !           254:                undefined_trust);
        !           255: 
        !           256:        if (options & MAINT_CHECK) {
        !           257:            close_more();
        !           258:            return status;
        !           259:        }
        !           260:        fprintf(pgpout, LANG("Continue with '%s' (Y/n)? "),
        !           261:                ringfile);
        !           262:        if (!getyesno('y')) {
        !           263:            close_more();
        !           264:            return status;
        !           265:        }
        !           266:     }
        !           267:     /* do the fixes in a scratch file */
        !           268:     fixfile = tempfile(0);
        !           269:     if (copyfiles_by_name(ringfile, fixfile) < 0) {
        !           270:        close_more();
        !           271:        return -1;
        !           272:     }
        !           273:     check_only = mverbose = FALSE;
        !           274:     if ((status = maintenance(fixfile, NULL)) >= 0) {
        !           275:        maint_list(fixfile);
        !           276:        fprintf(pgpout,
        !           277:                LANG("\n%d \"trust parameter(s)\" changed.\n"), status);
        !           278:     }
        !           279:     close_more();
        !           280:     if (status > 0 && !(options & MAINT_CHECK)) {
        !           281:        fprintf(pgpout, LANG("Update public keyring '%s' (Y/n)? "), ringfile);
        !           282:        if (getyesno('y'))
        !           283:            return savetempbak(fixfile, ringfile);
        !           284:     }
        !           285:     rmtemp(fixfile);
        !           286:     return status;
        !           287: }                              /* maint_check */
        !           288: 
        !           289: 
        !           290: static int maintenance(char *ringfile, struct newkey const *nkeys)
        !           291: {
        !           292:     int status;
        !           293:     undefined_trust = 0;       /* None so far... */
        !           294: 
        !           295:     if (max_cert_depth > MAX_DEPTH)
        !           296:        max_cert_depth = MAX_DEPTH;
        !           297:     if ((sec_fp = fopen(globalSecringName, FOPRBIN)) == NULL)
        !           298:        fprintf(pgpout, LANG("\nCan't open secret key ring file '%s'\n"),
        !           299:                globalSecringName);
        !           300: 
        !           301:     setkrent(ringfile);
        !           302:     setup_trust();
        !           303:     maint_init_mem();
        !           304:     if (mverbose || verbose)
        !           305:        fprintf(pgpout,
        !           306:         LANG("\nPass 1: Looking for the \"ultimately-trusted\" keys...\n"));
        !           307:     status = maint_read_data(ringfile, nkeys);
        !           308:     if (sec_fp) {
        !           309:        fclose(sec_fp);
        !           310:        sec_fp = NULL;
        !           311:     }
        !           312:     if (status < 0)
        !           313:        goto failed;
        !           314: 
        !           315:     if (mverbose || verbose)
        !           316:        fprintf(pgpout, LANG("\nPass 2: Tracing signature chains...\n"));
        !           317:     if ((status = maint_trace_chain()) < 0)
        !           318:        goto failed;
        !           319: 
        !           320:     if (verbose)
        !           321:        fprintf(pgpout, "\nPass 3: %s keyring...\n",
        !           322:                (check_only ? "Checking with" : "Updating"));
        !           323:     if ((status = maint_final(ringfile)) < 0)
        !           324:        goto failed;
        !           325: 
        !           326:     endkrent();
        !           327:     maint_release_mem();
        !           328:     return status + undefined_trust;
        !           329: 
        !           330:   failed:
        !           331:     if (verbose)
        !           332:        fprintf(pgpout, "maintenance pass: error exit = %d\n", status);
        !           333:     endkrent();
        !           334:     maint_release_mem();
        !           335:     return status;
        !           336: }                              /* maintenance */
        !           337: 
        !           338: 
        !           339: static struct pubkey *pklist, **pkhash = NULL;
        !           340: 
        !           341: #define        PK_HASHSIZE     256     /* must be power of 2 */
        !           342: #define        PK_HASH(x)              (*(byte *) (x) & (PK_HASHSIZE - 1))
        !           343: 
        !           344: /*
        !           345:  * get the pubkey struct for keyID from hash table, allocate a new
        !           346:  * node and insert in hash table if necessary.
        !           347:  */
        !           348: static struct pubkey *
        !           349:  getpubkey(byte * keyID)
        !           350: {
        !           351:     struct pubkey *pk;
        !           352:     for (pk = pkhash[PK_HASH(keyID)]; pk; pk = pk->pk_hash)
        !           353:        if (memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE) == 0)
        !           354:            return pk;
        !           355:     pk = allocn(sizeof(struct pubkey));
        !           356:     memset(pk, 0, sizeof(struct pubkey));
        !           357:     memcpy(pk->pk_keyid, keyID, KEYFRAGSIZE);
        !           358:     pk->pk_hash = pkhash[PK_HASH(keyID)];
        !           359:     pkhash[PK_HASH(keyID)] = pk;
        !           360:     return pk;
        !           361: }
        !           362: 
        !           363: /*
        !           364:  * Read in keyring, a graph of keys, userids and signatures is built.
        !           365:  * Also check if axiomatic keys are present in the secret keyring and
        !           366:  * compare them with the floppy ring if this is requested.
        !           367:  */
        !           368: static int maint_read_data(char *ringfile, struct newkey const *nkeys)
        !           369: {
        !           370:     FILE *f;
        !           371:     int status;
        !           372:     char userid[256];
        !           373:     byte keyID[KEYFRAGSIZE];
        !           374:     byte sigkeyID[KEYFRAGSIZE];
        !           375:     byte ctb;
        !           376:     byte keyctrl;
        !           377:     boolean buckstop = FALSE, show_user = FALSE;
        !           378:     int buckstopcount = 0;
        !           379:     long keypos = 0;
        !           380:     int skip = 0;
        !           381:     struct pubkey *pk = NULL;
        !           382:     struct userid *id = NULL;
        !           383:     struct signature *sig = NULL;
        !           384: 
        !           385:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
        !           386:        fprintf(pgpout,
        !           387:                LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
        !           388:        return -1;
        !           389:     }
        !           390:     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
        !           391:        if (status == -3 || status == -2) {
        !           392:            fclose(f);
        !           393:            return status;
        !           394:        }
        !           395:        if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
        !           396:            skip = 1;           /* version error or bad key */
        !           397:            continue;
        !           398:        }
        !           399:        if (skip) {
        !           400:            if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
        !           401:                skip = 0;
        !           402:            else
        !           403:                continue;
        !           404:        }
        !           405:        if (is_ctb_type(ctb, CTB_COMMENT_TYPE) || ctb == CTB_KEYCTRL)
        !           406:            continue;
        !           407: 
        !           408:        if (pk && is_ctb_type(ctb, CTB_SKE_TYPE) && !pk->pk_userids) {
        !           409:            /* sig. cert before userids can only be compromise cert. */
        !           410:            pk->pk_owntrust = KC_OWNERTRUST_NEVER;
        !           411:            continue;
        !           412:        }
        !           413:        /* other packets should have trust byte */
        !           414:        if (read_trust(f, &keyctrl) < 0) {
        !           415:            fclose(f);
        !           416:            return ERR_NOTRUST; /* not a public keyring */
        !           417:        }
        !           418:        switch (ctb_type(ctb)) {
        !           419:        case CTB_CERT_PUBKEY_TYPE:
        !           420:            if (pk)
        !           421:                pk = pk->pk_next = getpubkey(keyID);
        !           422:            else
        !           423:                pk = pklist = getpubkey(keyID);
        !           424: 
        !           425:            if (pk->pk_next) {
        !           426:                fprintf(pgpout,
        !           427:                        LANG("Keyring contains duplicate key: %s\n"),
        !           428:                        keyIDstring(keyID));
        !           429:                fclose(f);
        !           430:                return -1;
        !           431:            }
        !           432:            if (keyctrl & KC_BUCKSTOP ||
        !           433:                ismember_newkeys(keyID, nkeys)) {
        !           434:                if (check_secretkey(f, keypos, keyctrl) == 0) {
        !           435:                    ++buckstopcount;
        !           436:                    keyctrl |= KC_BUCKSTOP;
        !           437:                    SET_TRUST(&keyctrl, KC_OWNERTRUST_ULTIMATE);
        !           438:                    buckstop = TRUE;
        !           439:                    if (mverbose)
        !           440:                        fprintf(pgpout, "* %s", keyIDstring(keyID));
        !           441:                } else {        /* not in secret keyring */
        !           442:                    keyctrl &= ~KC_BUCKSTOP;
        !           443:                    if (TRUST_LEV(keyctrl) == KC_OWNERTRUST_ULTIMATE)
        !           444:                        keyctrl = KC_OWNERTRUST_ALWAYS;
        !           445:                    if (mverbose)
        !           446:                        fprintf(pgpout, ". %s", keyIDstring(keyID));
        !           447:                }
        !           448:                show_user = mverbose;
        !           449:            } else {
        !           450:                buckstop = FALSE;
        !           451:                show_user = FALSE;
        !           452:            }
        !           453:            pk->pk_owntrust = keyctrl;
        !           454:            pk->pk_userids = id = NULL;
        !           455:            break;
        !           456:        case CTB_USERID_TYPE:
        !           457: #ifdef MACTC5
        !           458:                mac_poll_for_break();
        !           459: #endif
        !           460:            if (!pk)
        !           461:                break;
        !           462:            if (show_user) {
        !           463:                if (pk->pk_userids)     /* more than one user ID */
        !           464:                    fprintf(pgpout, "        ");
        !           465:                fprintf(pgpout, "  %s\n", LOCAL_CHARSET(userid));
        !           466:            }
        !           467:            if (id)
        !           468:                id = id->uid_next = allocn(sizeof(struct userid));
        !           469:            else
        !           470:                id = pk->pk_userids = allocn(sizeof(struct userid));
        !           471: 
        !           472:            if (mverbose)
        !           473:                id->uid_userid = store_str(userid);
        !           474:            keyctrl &= ~KC_LEGIT_MASK;
        !           475:            if (buckstop)
        !           476:                keyctrl |= KC_LEGIT_COMPLETE;
        !           477:            else
        !           478:                keyctrl |= KC_LEGIT_UNKNOWN;
        !           479:            id->uid_next = NULL;
        !           480:            id->uid_key = pk;
        !           481:            id->uid_legit = keyctrl;
        !           482:            id->uid_signatures = sig = NULL;
        !           483:            break;
        !           484:        case CTB_SKE_TYPE:
        !           485:            if (!pk || !id)
        !           486:                break;
        !           487:            if (sig)
        !           488:                sig = sig->sig_next = allocn(sizeof(struct signature));
        !           489:            else
        !           490:                sig = id->uid_signatures = allocn(sizeof(struct signature));
        !           491:            sig->sig_next = NULL;
        !           492:            sig->sig_uid = id;
        !           493:            sig->sig_from = getpubkey(sigkeyID);
        !           494:            sig->sig_nextfrom = sig->sig_from->pk_signed;
        !           495:            sig->sig_from->pk_signed = sig;
        !           496:            sig->sig_trust = keyctrl & KC_SIG_CHECKED;
        !           497:            break;
        !           498:        }                       /* switch ctb_type */
        !           499:        keypos = ftell(f);
        !           500:     }
        !           501:     if (buckstopcount == 0 && mverbose)
        !           502:        fprintf(pgpout, LANG("No ultimately-trusted keys.\n"));
        !           503:     fclose(f);
        !           504:     return 0;
        !           505: }                              /* maint_read_data */
        !           506: 
        !           507: /*
        !           508:  * scan keyring for buckstop keys and start the recursive trace_sig_chain()
        !           509:  * on them
        !           510:  */
        !           511: static int maint_trace_chain(void)
        !           512: {
        !           513:     char *userid;
        !           514:     struct pubkey *pk;
        !           515: 
        !           516:     for (pk = pklist; pk; pk = pk->pk_next) {
        !           517:        if (!(pk->pk_owntrust & KC_BUCKSTOP))
        !           518:            continue;
        !           519:        if (mverbose)
        !           520:            fprintf(pgpout,
        !           521:                    "* %s\n", LOCAL_CHARSET(pk->pk_userids->uid_userid));
        !           522:        if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED) {
        !           523:            userid = user_from_keyID(pk->pk_keyid);
        !           524:            SET_TRUST(&pk->pk_owntrust, ask_owntrust(userid, pk->pk_owntrust));
        !           525:        }
        !           526:        trace_sig_chain(pk, 0);
        !           527:     }
        !           528:     return 0;
        !           529: }                              /* maint_trace_chain */
        !           530: 
        !           531: 
        !           532: /*
        !           533:  * Find all signatures made with the key pk.
        !           534:  * If a trusted signature makes a key fully legit then signatures made
        !           535:  * with this key are also recursively traced on down the tree.
        !           536:  *
        !           537:  * depth is the level of recursion, it is used to indent the userIDs
        !           538:  * and to check if we don't exceed the limit "max_cert_depth"
        !           539:  *
        !           540:  * NOTE: a signature made with a key with pk_depth == max_cert_depth will
        !           541:  * not be counted here to limit the maximum chain length, but will be
        !           542:  * counted when the validity of a key is computed in maint_final()
        !           543:  */
        !           544: static int trace_sig_chain(struct pubkey *pk, int depth)
        !           545: {
        !           546:     int d, trust_count = 0;
        !           547:     int counts[MAX_DEPTH];
        !           548:     struct signature *sig, *s;
        !           549:     struct pubkey *p;
        !           550:     struct userid *id;
        !           551: 
        !           552:     assert(depth <= max_cert_depth);
        !           553:     if (pk->pk_depth && pk->pk_depth <= depth)
        !           554:        return 0;
        !           555:     pk->pk_depth = depth;
        !           556: 
        !           557:     /* Should we ask for trust.  If this key is legit, then go for
        !           558:      * it!  Ask the user....
        !           559:      */
        !           560:     if (TRUST_LEV(pk->pk_owntrust) == KC_OWNERTRUST_UNDEFINED)
        !           561:        for (id = pk->pk_userids; id; id = id->uid_next) {
        !           562:            compute_legit(id);
        !           563:            if ((id->uid_legit & KC_LEGIT_MASK) ==
        !           564:                KC_LEGIT_COMPLETE) {
        !           565:                SET_TRUST(&pk->pk_owntrust,
        !           566:                          ask_owntrust(user_from_keyID(pk->pk_keyid),
        !           567:                                       pk->pk_owntrust));
        !           568:                break;
        !           569:            }
        !           570:        }
        !           571:     /* Return if I haven't signed anyone's keys, since I
        !           572:      * don't need to check any further..  -warlord 93-04-11
        !           573:      */
        !           574:     if (!pk->pk_signed)
        !           575:        return 0;
        !           576: 
        !           577: #ifdef DEBUG
        !           578:     if (mverbose)
        !           579:        fprintf(pgpout, "%*s%d-v  %s\n", 2 * depth, "",
        !           580:                depth, pk->pk_userids->uid_userid);
        !           581: #endif
        !           582: 
        !           583:     /* all keys signed by pk */
        !           584:     for (sig = pk->pk_signed; sig; sig = sig->sig_nextfrom) {
        !           585: 
        !           586:        /* If signature is good, copy trust from signator */
        !           587:        /* CONTIG bit currently unused */
        !           588:        if (sig->sig_trust & KC_SIG_CHECKED) {
        !           589:            SET_TRUST(&sig->sig_trust, TRUST_LEV(pk->pk_owntrust));
        !           590:            sig->sig_trust |= KC_CONTIG; /* CONTIG bit currently unused */
        !           591:            if (mverbose)
        !           592:                fprintf(pgpout, "%*s  > %s\n", 2 * depth, "",
        !           593:                        LOCAL_CHARSET(sig->sig_uid->uid_userid));
        !           594:        } else {
        !           595:            SET_TRUST(&sig->sig_trust, KC_SIGTRUST_UNTRUSTED);
        !           596:            sig->sig_trust &= ~KC_CONTIG;
        !           597:            if (mverbose)
        !           598:                fprintf(pgpout, "%*s  X %s\n", 2 * depth, "",
        !           599:                        LOCAL_CHARSET(sig->sig_uid->uid_userid));
        !           600:        }
        !           601: 
        !           602:        if (TRUST_FAC(sig->sig_trust) == 0)
        !           603:            continue;
        !           604:        p = sig->sig_uid->uid_key;      /* this key signed by pk */
        !           605:        if (p->pk_owntrust & KC_BUCKSTOP)
        !           606:            continue;           /* will be handled from main loop */
        !           607:        if (p->pk_depth && p->pk_depth <= depth + 1)
        !           608:            continue;           /* already handled this key at a lower level */
        !           609: 
        !           610:        for (d = 0; d < max_cert_depth; ++d)
        !           611:            counts[d] = 0;
        !           612:        for (s = sig->sig_uid->uid_signatures; s; s = s->sig_next) {
        !           613:            d = s->sig_from->pk_depth;
        !           614:            if (d < max_cert_depth)
        !           615:                counts[d] += TRUST_FAC(s->sig_trust);
        !           616:        }
        !           617:        /*
        !           618:         * find a combination of signatures that will make the key
        !           619:         * valid through the shortest cert. path.
        !           620:         */
        !           621:        trust_count = 0;
        !           622:        for (d = 0; d < max_cert_depth; ++d) {
        !           623:            trust_count += counts[d];
        !           624:            if (trust_count >= complete_min) {
        !           625:                trace_sig_chain(p, d + 1);
        !           626:                break;
        !           627:            }
        !           628:        }
        !           629:     }
        !           630: 
        !           631: #ifdef DEBUG
        !           632:     if (mverbose)
        !           633:        fprintf(pgpout, "%*s%d-^  %s\n", 2 * depth, "",
        !           634:                depth, pk->pk_userids->uid_userid);
        !           635: #endif
        !           636:     return 0;
        !           637: }                              /* trace_sig_chain */
        !           638: 
        !           639: /*
        !           640:  * compute validity of userid/key pair, the number of signatures and the
        !           641:  * trust level of these signatures determines the validity.
        !           642:  */
        !           643: static void compute_legit(struct userid *id)
        !           644: {
        !           645:     struct signature *s;
        !           646:     int trust_count, legit;
        !           647: 
        !           648:     if (id->uid_key->pk_owntrust & KC_BUCKSTOP)
        !           649:        legit = KC_LEGIT_COMPLETE;
        !           650:     else {
        !           651:        trust_count = 0;
        !           652:        for (s = id->uid_signatures; s; s = s->sig_next)
        !           653:            trust_count += TRUST_FAC(s->sig_trust);
        !           654: 
        !           655:        if (trust_count == 0)
        !           656:            legit = KC_LEGIT_UNKNOWN;
        !           657:        else if (trust_count < marginal_min)
        !           658:            legit = KC_LEGIT_UNTRUSTED;
        !           659:        else if (trust_count < complete_min)
        !           660:            legit = KC_LEGIT_MARGINAL;
        !           661:        else
        !           662:            legit = KC_LEGIT_COMPLETE;
        !           663:     }
        !           664:     id->uid_legit = (id->uid_legit & ~KC_LEGIT_MASK) | legit;
        !           665: }                              /* compute_legit */
        !           666: 
        !           667: /* 
        !           668:  * check if the maintenance pass changed anything
        !           669:  * returns 0 if files f and g are equal and the number of changed
        !           670:  * trust bytes if the files are different or a negative value on error
        !           671:  */
        !           672: static int maint_final(char *ringfile)
        !           673: {
        !           674:     int status;
        !           675:     FILE *f;
        !           676:     long trust_pos = 0;
        !           677:     char userid[256];
        !           678:     byte keyID[KEYFRAGSIZE];
        !           679:     byte sigkeyID[KEYFRAGSIZE];
        !           680:     byte ctb;
        !           681:     byte kc_orig, kc_new = 0, mask;
        !           682:     int changed = 0;
        !           683:     int skip = 0;
        !           684:     struct pubkey *pk;
        !           685:     struct userid *id = NULL;
        !           686:     struct signature *sig = NULL;
        !           687: 
        !           688:     if (check_only)
        !           689:        f = fopen(ringfile, FOPRBIN);
        !           690:     else
        !           691:        f = fopen(ringfile, FOPRWBIN);
        !           692:     if (f == NULL) {
        !           693:        fprintf(pgpout,
        !           694:                LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
        !           695:        return -1;
        !           696:     }
        !           697:     pk = pklist;
        !           698:     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
        !           699:        if (status == -3 || status == -2)
        !           700:            break;
        !           701:        if (status < 0 || is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE)) {
        !           702:            skip = 1;
        !           703:            continue;
        !           704:        }
        !           705:        if (skip) {
        !           706:            if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE))
        !           707:                skip = 0;
        !           708:            else
        !           709:                continue;
        !           710:        }
        !           711:        if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) ||
        !           712:            is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) {
        !           713:            trust_pos = ftell(f);
        !           714:            if (read_trust(f, &kc_orig) < 0) {
        !           715:                status = ERR_NOTRUST;
        !           716:                if (is_ctb_type(ctb, CTB_SKE_TYPE))
        !           717:                    continue;   /* skip compr. cert. */
        !           718:                else
        !           719:                    break;
        !           720:            }
        !           721:        }
        !           722:        switch (ctb_type(ctb)) {
        !           723:        case CTB_CERT_PUBKEY_TYPE:
        !           724:            assert(pk && !memcmp(pk->pk_keyid, keyID, KEYFRAGSIZE));
        !           725:            assert(!sig && !id);
        !           726:            id = pk->pk_userids;
        !           727:            kc_new = pk->pk_owntrust;
        !           728: #ifdef DEBUG
        !           729:            if (mverbose)
        !           730:                fprintf(pgpout, "  ------ %d\n", pk->pk_depth);
        !           731: #endif
        !           732:            pk = pk->pk_next;
        !           733:            mask = KC_OWNERTRUST_MASK | KC_BUCKSTOP;
        !           734:            break;
        !           735:        case CTB_USERID_TYPE:
        !           736:            assert(id && !sig);
        !           737: #ifdef MACTC5
        !           738:            mac_poll_for_break();
        !           739: #endif
        !           740:            sig = id->uid_signatures;
        !           741:            compute_legit(id);
        !           742:            kc_new = id->uid_legit;
        !           743: #ifdef DEBUG
        !           744:            if (mverbose)
        !           745:                fprintf(pgpout, "%c %02x  %02x  %s\n",
        !           746:                        ' ' + (kc_new != kc_orig),
        !           747:                        kc_orig, kc_new, id->uid_userid);
        !           748: #endif
        !           749:            id = id->uid_next;
        !           750:            mask = KC_LEGIT_MASK;
        !           751:            break;
        !           752:        case CTB_SKE_TYPE:
        !           753:            assert(sig);
        !           754:            assert(!memcmp(sig->sig_from->pk_keyid, sigkeyID, KEYFRAGSIZE));
        !           755:            kc_new = sig->sig_trust;
        !           756: #ifdef DEBUG
        !           757:            if (mverbose && sig->sig_from->pk_userids)
        !           758:                fprintf(pgpout, "%c %02x  %02x    %s\n",
        !           759:                        ' ' + (kc_new != kc_orig),
        !           760:                 kc_orig, kc_new, sig->sig_from->pk_userids->uid_userid);
        !           761: #endif
        !           762:            sig = sig->sig_next;
        !           763:            mask = KC_SIGTRUST_MASK | KC_CONTIG;
        !           764:            break;
        !           765:        default:
        !           766:            mask = 0;
        !           767:        }
        !           768:        if ((kc_new & mask) != (kc_orig & mask)) {
        !           769:            if (!check_only)
        !           770:                write_trust_pos(f, kc_new, trust_pos);
        !           771:            ++changed;
        !           772:        }
        !           773:     }
        !           774:     fclose(f);
        !           775:     if (status < -1)           /* -1 is OK, EOF */
        !           776:        return status;
        !           777:     if (pk || sig || id) {
        !           778:        fprintf(pgpout, "maint_final: internal error\n");
        !           779:        return -1;
        !           780:     }
        !           781:     return changed;
        !           782: }                              /* maint_final */
        !           783: 
        !           784: int maint_list(char *ringfile)
        !           785: {
        !           786:     int status;
        !           787:     FILE *f;
        !           788:     char userid[256];
        !           789:     byte keyID[KEYFRAGSIZE];
        !           790:     byte sigkeyID[KEYFRAGSIZE];
        !           791:     char *signator;
        !           792:     char tchar = 0;
        !           793:     byte ctb, kc;
        !           794:     int owntrust = 0;
        !           795:     int usercount = 0;
        !           796: 
        !           797:     if ((f = fopen(ringfile, FOPRBIN)) == NULL) {
        !           798:        fprintf(pgpout,
        !           799:                LANG("\n\007Can't open key ring file '%s'\n"), ringfile);
        !           800:        return -1;
        !           801:     }
        !           802:     init_trust_lst();
        !           803:     setkrent(ringfile);
        !           804:     init_userhash();
        !           805: 
        !           806:     fprintf(pgpout, LANG("  KeyID    Trust     Validity  User ID\n"));
        !           807:     while ((status = readkpacket(f, &ctb, userid, keyID, sigkeyID)) != -1) {
        !           808:        if (status == -3 || status == -2)
        !           809:            break;
        !           810:        if (status < 0)
        !           811:            continue;
        !           812: 
        !           813:        if (is_ctb_type(ctb, CTB_CERT_PUBKEY_TYPE) ||
        !           814:            is_ctb_type(ctb, CTB_SKE_TYPE) || ctb == CTB_USERID) {
        !           815:            if (read_trust(f, &kc) < 0) {
        !           816:                status = ERR_NOTRUST;
        !           817:                /* compromise cert. don't have trust byte */
        !           818:                if (!is_ctb_type(ctb, CTB_SKE_TYPE))
        !           819:                    break;
        !           820:            }
        !           821:        }
        !           822: #ifdef MACTC5
        !           823:        {
        !           824:                extern int BreakCntl;
        !           825:                if (!BreakCntl) BreakCntl = 35;
        !           826:                mac_poll_for_break();
        !           827:        }
        !           828: #endif
        !           829: 
        !           830:        switch (ctb_type(ctb)) {
        !           831:        case CTB_CERT_PUBKEY_TYPE:
        !           832:            tchar = (kc & KC_BUCKSTOP ? '*' : ' ');
        !           833:            owntrust = TRUST_LEV(kc);
        !           834:            usercount = 0;
        !           835:            userid[0] = '\0';
        !           836:            break;
        !           837:        case CTB_USERID_TYPE:
        !           838:            if (!usercount) {   /* first userid */
        !           839:                fprintf(pgpout, "%c %s ", tchar, keyIDstring(keyID));
        !           840:                fprintf(pgpout, "%-*s ", trustlst_len, trust_lst[owntrust]);
        !           841:            } else
        !           842:                fprintf(pgpout, "  %s %*s ", blankkeyID, trustlst_len, "");
        !           843:            fprintf(pgpout, "%-*s ", legitlst_len,
        !           844:                    legit_lst[kc & KC_LEGIT_MASK]);
        !           845:            if (usercount)
        !           846:                putc(' ', pgpout);
        !           847:            ++usercount;
        !           848:            fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid));
        !           849:            break;
        !           850:        case CTB_SKE_TYPE:
        !           851:            if (!usercount) {   /* sig before userid: compromise cert. */
        !           852:                tchar = '#';
        !           853:                break;
        !           854:            }
        !           855:            fprintf(pgpout, "%c %s ",
        !           856:                    (kc & KC_CONTIG) ? 'c' : ' ', blankkeyID);
        !           857:            fprintf(pgpout, "%-*s ", trustlst_len, trust_lst[TRUST_LEV(kc)]);
        !           858:            fprintf(pgpout, "%*s  ", legitlst_len, "");
        !           859:            if ((signator = user_from_keyID(sigkeyID)) == NULL)
        !           860:                fprintf(pgpout, LANG("(KeyID: %s)\n"), keyIDstring(sigkeyID));
        !           861:            else
        !           862:                fprintf(pgpout, "%s\n", LOCAL_CHARSET(signator));
        !           863:            break;
        !           864:        }
        !           865:     }
        !           866:     endkrent();
        !           867:     fclose(f);
        !           868:     if (status < -1)           /* -1 is OK, EOF */
        !           869:        return status;
        !           870:     return 0;
        !           871: }                              /* maint_list */
        !           872: 
        !           873: /*
        !           874:  * translate the messages in the arrays trust_lst and legit_lst.
        !           875:  * trustlst_len and legitlst_len will be set to the length of
        !           876:  * the longest translated string.
        !           877:  */
        !           878: void init_trust_lst(void)
        !           879: {
        !           880:     static int initialized = 0;
        !           881:     int i, len;
        !           882:     char *s;
        !           883: 
        !           884:     if (initialized)
        !           885:        return;
        !           886:     for (i = 0; i < 8; ++i) {
        !           887:        if (trust_lst[i][0]) {
        !           888:            s = LANG(trust_lst[i]);
        !           889:            if (s != trust_lst[i])
        !           890:                strncpy(trust_lst[i], s, sizeof(trust_lst[0]) - 1);
        !           891:            len = strlen(s);
        !           892:            if (len > trustlst_len)
        !           893:                trustlst_len = len;
        !           894:        }
        !           895:     }
        !           896:     for (i = 0; i < 4; ++i) {
        !           897:        s = LANG(legit_lst[i]);
        !           898:        if (s != legit_lst[i])
        !           899:            strncpy(legit_lst[i], s, sizeof(legit_lst[0]) - 1);
        !           900:        len = strlen(s);
        !           901:        if (len > legitlst_len)
        !           902:            legitlst_len = len;
        !           903:     }
        !           904:     initialized = 1;
        !           905: }                              /* init_trust_lst */
        !           906: 
        !           907: 
        !           908: 
        !           909: /*
        !           910:  * compare the key in file f at keypos with the matching key in the
        !           911:  * secret keyring, the global variable sec_fp must contain the file pointer
        !           912:  * for of the secret keyring.
        !           913:  *
        !           914:  * returns 1 if the key was not found, -2 if the keys were different
        !           915:  * and 0 if the keys compared OK
        !           916:  */
        !           917: static int check_secretkey(FILE * f, long keypos, byte keyctrl)
        !           918: {
        !           919:     int status = -1;
        !           920:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
        !           921:     unit nsec[MAX_UNIT_PRECISION], esec[MAX_UNIT_PRECISION];
        !           922:     char userid[256];
        !           923:     byte keyID[KEYFRAGSIZE];
        !           924:     long savepos, pktlen;
        !           925:     byte ctb;
        !           926: 
        !           927:     if (sec_fp == NULL)
        !           928:        return -1;
        !           929: 
        !           930:     savepos = ftell(f);
        !           931:     fseek(f, keypos, SEEK_SET);
        !           932:     if (readkeypacket(f, FALSE, &ctb, NULL, NULL, n, e,
        !           933:                      NULL, NULL, NULL, NULL, NULL, NULL) < 0)
        !           934:        goto ex;
        !           935:     extract_keyID(keyID, n);
        !           936: 
        !           937:     do {                       /* get userid */
        !           938:        status = readkpacket(f, &ctb, userid, NULL, NULL);
        !           939:        if (status == -1 || status == -3)
        !           940:            goto ex;
        !           941:     } while (ctb != CTB_USERID);
        !           942: 
        !           943:     if (lookup_by_keyID(sec_fp, keyID) < 0) {
        !           944: #if 0
        !           945:        if (!check_only) {
        !           946:            fprintf(pgpout,
        !           947: LANG("\nAn \"axiomatic\" key is one which does not need certifying by\n\
        !           948: anyone else.  Usually this special status is reserved only for your\n\
        !           949: own keys, which should also appear on your secret keyring.  The owner\n\
        !           950: of an axiomatic key (who is typically yourself) is \"ultimately trusted\"\n\
        !           951: by you to certify any or all other keys.\n"));
        !           952:            fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\
        !           953: is designated as an \"ultimately-trusted\" introducer, but the key\n\
        !           954: does not appear in the secret keyring.\n\
        !           955: Use this key as an ultimately-trusted introducer (y/N)? "),
        !           956:                    LOCAL_CHARSET(userid));
        !           957:            status = (getyesno('n') ? 0 : 1);
        !           958:        }
        !           959: #else
        !           960:        status = 1;
        !           961: #endif
        !           962:     } else {
        !           963:        long kpos = ftell(sec_fp);
        !           964:        if (readkeypacket(sec_fp, FALSE, &ctb, NULL, NULL, nsec, esec,
        !           965:                          NULL, NULL, NULL, NULL, NULL, NULL) < 0) {
        !           966:            fprintf(pgpout, LANG("\n\007Cannot read from secret keyring.\n"));
        !           967:            status = -3;
        !           968:            goto ex;
        !           969:        }
        !           970:        if (mp_compare(n, nsec) || mp_compare(e, esec)) {
        !           971:            /* Red Alert! */
        !           972:            fprintf(pgpout,
        !           973:                    LANG("\n\007WARNING: Public key for user ID: \"%s\"\n\
        !           974: does not match the corresponding key in the secret keyring.\n"),
        !           975:                    LOCAL_CHARSET(userid));
        !           976:            fprintf(pgpout,
        !           977: LANG("This is a serious condition, indicating possible keyring tampering.\n"));
        !           978:            status = -2;
        !           979:        } else {
        !           980:            status = 0;
        !           981:        }
        !           982: 
        !           983:        /* Okay, key is in secret key ring, and it matches. */
        !           984:        if (!(keyctrl & KC_BUCKSTOP)) {
        !           985:            if (batchmode) {
        !           986:                status = -1;
        !           987:            } else {
        !           988:                fprintf(pgpout, LANG("\nKey for user ID \"%s\"\n\
        !           989: also appears in the secret key ring."), LOCAL_CHARSET(userid));
        !           990:                fputs(
        !           991:          LANG("\nUse this key as an ultimately-trusted introducer (y/N)? "),
        !           992:                      pgpout);
        !           993:                status = getyesno('n') ? 0 : -1;
        !           994:            }
        !           995:        }
        !           996:        if (status == 0 && floppy_fp) {
        !           997:            if (lookup_by_keyID(floppy_fp, keyID) < 0) {
        !           998:                fprintf(pgpout, LANG("Public key for: \"%s\"\n\
        !           999: is not present in the backup keyring '%s'.\n"),
        !          1000:                        LOCAL_CHARSET(userid), floppyring);
        !          1001:            } else {
        !          1002:                pktlen = ftell(sec_fp) - kpos;
        !          1003:                fseek(sec_fp, kpos, SEEK_SET);
        !          1004:                while (--pktlen >= 0 && getc(sec_fp) == getc(floppy_fp));
        !          1005:                if (pktlen != -1) {
        !          1006:                    fprintf(pgpout,
        !          1007:                            LANG("\n\007WARNING: Secret key for: \"%s\"\n\
        !          1008: does not match the key in the backup keyring '%s'.\n"),
        !          1009:                            LOCAL_CHARSET(userid), floppyring);
        !          1010:                    fprintf(pgpout,
        !          1011: LANG("This is a serious condition, indicating possible keyring tampering.\n"));
        !          1012:                    status = -2;
        !          1013:                }
        !          1014:            }
        !          1015:        }
        !          1016:     }
        !          1017:   ex:
        !          1018:     fseek(f, savepos, SEEK_SET);
        !          1019:     return status;
        !          1020: }                              /* check_secretkey */
        !          1021: 
        !          1022: /*
        !          1023:  * setup tables for trust scoring.
        !          1024:  */
        !          1025: static void setup_trust(void)
        !          1026: {
        !          1027:     /* initialize trust table */
        !          1028:     if (marg_min == 0) {       /* marginally trusted signatures are ignored */
        !          1029:        trust_tbl[5] = 0;
        !          1030:        trust_tbl[6] = 1;
        !          1031:        complete_min = compl_min;
        !          1032:     } else {
        !          1033:        if (marg_min < compl_min)
        !          1034:            marg_min = compl_min;
        !          1035:        trust_tbl[5] = compl_min;
        !          1036:        trust_tbl[6] = marg_min;
        !          1037:        complete_min = compl_min * marg_min;
        !          1038:     }
        !          1039:     trust_tbl[7] = complete_min;       /* ultimate trust */
        !          1040:     marginal_min = complete_min / 2;
        !          1041: }                              /* setup_trust */
        !          1042: 
        !          1043: /* Ask for a wetware decision from the human on how much to trust 
        !          1044:    this key's owner to certify other keys.  Returns trust value. */
        !          1045: int ask_owntrust(char *userid, byte cur_trust)
        !          1046: {
        !          1047:     char buf[8];
        !          1048: 
        !          1049:     if (check_only || filter_mode || batchmode) {
        !          1050:        /* not interactive */
        !          1051:        ++undefined_trust;      /* We complete/undefined. Why?  */
        !          1052:        return KC_OWNERTRUST_UNDEFINED;
        !          1053:     }
        !          1054: #ifdef MACTC5
        !          1055:        get_trust(buf,userid);
        !          1056: #endif
        !          1057:     fprintf(pgpout,
        !          1058: LANG("\nMake a determination in your own mind whether this key actually\n\
        !          1059: belongs to the person whom you think it belongs to, based on available\n\
        !          1060: evidence.  If you think it does, then based on your estimate of\n\
        !          1061: that person's integrity and competence in key management, answer\n\
        !          1062: the following question:\n"));
        !          1063:     fprintf(pgpout, LANG("\nWould you trust \"%s\"\n\
        !          1064: to act as an introducer and certify other people's public keys to you?\n\
        !          1065: (1=I don't know. 2=No. 3=Usually. 4=Yes, always.) ? "),
        !          1066:            LOCAL_CHARSET(userid));
        !          1067:     fflush(pgpout);
        !          1068: #ifdef MACTC5
        !          1069:        Putchar(buf[0]);
        !          1070:        Putchar('\n');
        !          1071: #else
        !          1072:     getstring(buf, sizeof(buf) - 1, TRUE);
        !          1073: #endif
        !          1074:     switch (buf[0]) {
        !          1075:     case '1':
        !          1076:        return KC_OWNERTRUST_UNKNOWN;
        !          1077:     case '2':
        !          1078:        return KC_OWNERTRUST_NEVER;
        !          1079:     case '3':
        !          1080:        return KC_OWNERTRUST_USUALLY;
        !          1081:     case '4':
        !          1082:        return KC_OWNERTRUST_ALWAYS;
        !          1083:     default:
        !          1084:        return TRUST_LEV(cur_trust);
        !          1085:     }
        !          1086: }                              /* ask_owntrust */
        !          1087: 
        !          1088: /*
        !          1089:  * scan keyfile f for keyID srch_keyID.
        !          1090:  * returns the file position of the key if it is found, and sets the
        !          1091:  * file pointer to the start of the key packet.
        !          1092:  * returns -1 if the key was not found or < -1 if there was an error
        !          1093:  */
        !          1094: long lookup_by_keyID(FILE * f, byte * srch_keyID)
        !          1095: {
        !          1096:     int status;
        !          1097:     long keypos = 0;
        !          1098:     byte keyID[KEYFRAGSIZE];
        !          1099:     byte ctb;
        !          1100: 
        !          1101:     rewind(f);
        !          1102:     while ((status = readkpacket(f, &ctb, NULL, keyID, NULL)) != -1) {
        !          1103:        if (status == -3 || status == -2)
        !          1104:            break;
        !          1105:        if (status < 0)
        !          1106:            continue;
        !          1107:        if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0) {
        !          1108:            fseek(f, keypos, SEEK_SET);
        !          1109:            return keypos;
        !          1110:        }
        !          1111:        keypos = ftell(f);
        !          1112:     }
        !          1113:     return status;
        !          1114: }                              /* lookup_by_keyID */
        !          1115: 
        !          1116: /*
        !          1117:  * look up the key matching "keyID" and print the first userID
        !          1118:  * of this key.  File position of f is saved.
        !          1119:  */
        !          1120: void show_userid(FILE * f, byte * keyID)
        !          1121: {
        !          1122:     int status;
        !          1123:     long filepos;
        !          1124:     char userid[256];
        !          1125:     byte ctb;
        !          1126: 
        !          1127:     filepos = ftell(f);
        !          1128:     if (lookup_by_keyID(f, keyID) >= 0)
        !          1129:        while ((status = readkpacket(f, &ctb, userid, NULL, NULL)) != -1
        !          1130:               && status != -3)
        !          1131:            if (ctb == CTB_USERID) {
        !          1132:                fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid));
        !          1133:                fseek(f, filepos, SEEK_SET);
        !          1134:                return;
        !          1135:            }
        !          1136:     fprintf(pgpout, LANG("(KeyID: %s)\n"), keyIDstring(keyID));
        !          1137:     fseek(f, filepos, SEEK_SET);
        !          1138: }                              /* show_userid */
        !          1139: 
        !          1140: /*
        !          1141:  * messages printed by show_key()
        !          1142:  */
        !          1143: static char *owntrust_msg[] =
        !          1144: {
        !          1145:     "",                                /* Just don't say anything in this case */
        !          1146:     "",
        !          1147:     _LANG("This user is untrusted to certify other keys.\n"),
        !          1148:     "",                                /* reserved */
        !          1149:     "",                                /* reserved */
        !          1150:     _LANG("This user is generally trusted to certify other keys.\n"),
        !          1151:     _LANG("This user is completely trusted to certify other keys.\n"),
        !          1152:     _LANG("This axiomatic key is ultimately trusted to certify other keys.\n"),
        !          1153: };
        !          1154: static char *keylegit_msg[] =
        !          1155: {
        !          1156:     _LANG("This key/userID association is not certified.\n"),
        !          1157:     _LANG("This key/userID association is not certified.\n"),
        !          1158:     _LANG("This key/userID association is marginally certified.\n"),
        !          1159:     _LANG("This key/userID association is fully certified.\n"),
        !          1160: };
        !          1161: static char *sigtrust_msg[] =
        !          1162: {
        !          1163:     _LANG("  Questionable certification from:\n  "),
        !          1164:     _LANG("  Questionable certification from:\n  "),
        !          1165:     _LANG("  Untrusted certification from:\n  "),
        !          1166:     "",                                /* reserved */
        !          1167:     "",                                /* reserved */
        !          1168:     _LANG("  Generally trusted certification from:\n  "),
        !          1169:     _LANG("  Completely trusted certification from:\n  "),
        !          1170:     _LANG("  Axiomatically trusted certification from:\n  "),
        !          1171: };
        !          1172: 
        !          1173: /*
        !          1174:  * show the key in file f at file position keypos.
        !          1175:  * 'what' controls the info that will be shown:
        !          1176:  *   SHOW_TRUST: show trust byte info
        !          1177:  *   SHOW_SIGS:  show signatures
        !          1178:  *   SHOW_HASH:  show key fingerprint
        !          1179:  * these constants can be or'ed
        !          1180:  *
        !          1181:  * 'what' can also be SHOW_LISTFMT to get the same format as for pgp -kv
        !          1182:  * no signatures or extra userids will be printed in this case.
        !          1183:  *
        !          1184:  * 'what' can be SHOW_CHANGE, in which case it will take the keyID and
        !          1185:  * call show_update();
        !          1186:  */
        !          1187: int show_key(FILE * f, long keypos, int what)
        !          1188: {
        !          1189:     int status, keystatus = -1;
        !          1190:     long filepos;
        !          1191:     char userid[256];
        !          1192:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
        !          1193:     byte sigkeyID[KEYFRAGSIZE];
        !          1194:     word32 timestamp;
        !          1195:     byte ctb, keyctb = 0, keyctrl;
        !          1196:     int userids = 0;
        !          1197:     int keyids = 0;
        !          1198:     byte savekeyID[KEYFRAGSIZE];
        !          1199:     boolean print_trust = FALSE;
        !          1200:     byte hash[16];
        !          1201:     int precision = global_precision;
        !          1202:     int compromised = 0;
        !          1203:     int disabled = 0;
        !          1204: 
        !          1205:     filepos = ftell(f);
        !          1206:     fseek(f, keypos, SEEK_SET);
        !          1207:     while ((status = readkeypacket(f, FALSE, &ctb, (byte *) & timestamp,
        !          1208:                                   userid,
        !          1209:              n, e, NULL, NULL, NULL, NULL, sigkeyID, &keyctrl)) != -1) {
        !          1210:        if (status == -2 || status == -3)
        !          1211:            break;
        !          1212:        if (is_key_ctb(ctb)) {
        !          1213: 
        !          1214:            if (keyids)
        !          1215:                break;
        !          1216:            extract_keyID(savekeyID, n);
        !          1217:            keyids++;
        !          1218:            if (what & SHOW_HASH)
        !          1219:                getKeyHash(hash, n, e);
        !          1220:            keyctb = ctb;
        !          1221:            keystatus = status; /* remember status, could be version error */
        !          1222: 
        !          1223:        } else if (ctb == CTB_KEYCTRL) {
        !          1224: 
        !          1225:            /* trust bytes only in public keyrings */
        !          1226:            if (keystatus >= 0 && !userids)     /* key packet trust byte */
        !          1227:                if (keyctrl & KC_DISABLED)
        !          1228:                    disabled = 1;
        !          1229:            if (what & SHOW_TRUST)
        !          1230:                print_trust = TRUE;
        !          1231: 
        !          1232:        } else if (ctb == CTB_USERID) {
        !          1233: 
        !          1234:            if (userids == 0) {
        !          1235:                PascalToC(userid);      /* for display */
        !          1236:                ++userids;
        !          1237:                if (what & SHOW_CHANGE) {
        !          1238:                    show_update(key2IDstring(n));
        !          1239:                    break;
        !          1240:                }
        !          1241:                if (what & SHOW_LISTFMT) {
        !          1242:                    if (is_ctb_type(keyctb, CTB_CERT_PUBKEY_TYPE))
        !          1243:                        fprintf(pgpout, LANG("pub"));
        !          1244:                    else if (is_ctb_type(keyctb, CTB_CERT_SECKEY_TYPE))
        !          1245:                        fprintf(pgpout, LANG("sec"));
        !          1246:                    else
        !          1247:                        fprintf(pgpout, "???");
        !          1248:                    if (keystatus < 0)
        !          1249:                        fprintf(pgpout, "? ");
        !          1250:                    else if (compromised)
        !          1251:                        fprintf(pgpout, "# ");
        !          1252:                    else if (disabled)
        !          1253:                        fprintf(pgpout, "- ");
        !          1254:                    else
        !          1255:                        fprintf(pgpout, "  ");
        !          1256:                    fprintf(pgpout, "%4d/%s %s  ",
        !          1257:                       countbits(n), key2IDstring(n), cdate(&timestamp));
        !          1258:                    fprintf(pgpout, "%s\n", LOCAL_CHARSET(userid));
        !          1259:                    break;      /* only print default userid */
        !          1260:                }
        !          1261:                fprintf(pgpout, LANG("\nKey for user ID: %s\n"),
        !          1262:                        LOCAL_CHARSET(userid));
        !          1263:                fprintf(pgpout, LANG("%d-bit key, key ID %s, created %s\n"),
        !          1264:                        countbits(n), key2IDstring(n), cdate(&timestamp));
        !          1265:                if (keystatus == -4)
        !          1266:                    fprintf(pgpout, LANG("Bad key format.\n"));
        !          1267:                else if (keystatus == -6)
        !          1268:                    fprintf(pgpout, LANG("Unrecognized version.\n"));
        !          1269:                else if (what & SHOW_HASH)
        !          1270:                    printKeyHash(hash, FALSE);
        !          1271:                if (compromised)
        !          1272:                    fprintf(pgpout, LANG("Key has been revoked.\n"));
        !          1273:                if (disabled)
        !          1274:                    fprintf(pgpout, LANG("Key is disabled.\n"));
        !          1275:                if (print_trust && *owntrust_msg[TRUST_LEV(keyctrl)] != '\0')
        !          1276:                    fprintf(pgpout, LANG(owntrust_msg[TRUST_LEV(keyctrl)]));
        !          1277:            } else {
        !          1278:                PascalToC(userid);
        !          1279:                if (what != 0)
        !          1280:                    fprintf(pgpout, "\n");
        !          1281:                fprintf(pgpout, LANG("Also known as: %s\n"),
        !          1282:                        LOCAL_CHARSET(userid));
        !          1283:            }
        !          1284:            if (print_trust) {
        !          1285:                read_trust(f, &keyctrl);
        !          1286:                fprintf(pgpout, LANG(keylegit_msg[keyctrl & KC_LEGIT_MASK]));
        !          1287:            }                   /* print_trust */
        !          1288:        } else if (is_ctb_type(ctb, CTB_SKE_TYPE)) {
        !          1289: 
        !          1290:            if (userids == 0)
        !          1291:                compromised = 1;
        !          1292:            if (what & SHOW_CHANGE) {
        !          1293:                show_update(key2IDstring(n));
        !          1294:                break;
        !          1295:            }
        !          1296:            if (what & SHOW_SIGS) {
        !          1297:                if (print_trust) {
        !          1298:                    read_trust(f, &keyctrl);
        !          1299:                    fprintf(pgpout, LANG(sigtrust_msg[TRUST_LEV(keyctrl)]));
        !          1300:                } else {
        !          1301:                    fprintf(pgpout, LANG("  Certified by: "));
        !          1302:                }
        !          1303:                show_userid(f, sigkeyID);
        !          1304:            }
        !          1305:        }
        !          1306:     }
        !          1307:     if (status == -1 && userids)
        !          1308:        status = 0;
        !          1309:     if (!userids && !compromised && (what != SHOW_CHANGE)) {
        !          1310:        status = -1;
        !          1311:        fprintf(pgpout, LANG("\nWarning: keyid %4d/%s %s  has no user id!\n"),
        !          1312:                countbits(n), keyIDstring(savekeyID), cdate(&timestamp));
        !          1313:     }
        !          1314:     set_precision(precision);
        !          1315:     fseek(f, filepos, SEEK_SET);
        !          1316:     return status;
        !          1317: }                              /* show_key */
        !          1318: 
        !          1319: /* show_update -- this function just prints an update message to
        !          1320:  * pgpout to inform the user that an update happened.
        !          1321:  */
        !          1322: void show_update(char *s)
        !          1323: {
        !          1324:     fprintf(pgpout, LANG("Updated keyID: 0x%s\n"), s);
        !          1325: }
        !          1326: 
        !          1327: /*
        !          1328:  * stripped down version of readkeypacket(), the output userid
        !          1329:  * is a null terminated string.
        !          1330:  */
        !          1331: int readkpacket(FILE * f, byte * ctb, char *userid,
        !          1332:                byte * keyID, byte * sigkeyID)
        !          1333: {
        !          1334:     int status;
        !          1335:     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
        !          1336: 
        !          1337:     status = readkeypacket(f, FALSE, ctb, NULL, userid, n, e,
        !          1338:                           NULL, NULL, NULL, NULL, sigkeyID, NULL);
        !          1339: 
        !          1340:     if (status < 0) {
        !          1341: #ifdef DEBUG
        !          1342:        if (status < -1)
        !          1343:            fprintf(stderr, "readkeypacket returned %d\n", status);
        !          1344: #endif
        !          1345:        return status;
        !          1346:     }
        !          1347:     if (keyID && is_key_ctb(*ctb))
        !          1348:        extract_keyID(keyID, n);
        !          1349: 
        !          1350:     if (userid && *ctb == CTB_USERID)
        !          1351:        PascalToC(userid);
        !          1352: 
        !          1353:     return 0;
        !          1354: }                              /* readkpacket */
        !          1355: 
        !          1356: /*
        !          1357:  * write trust byte "keyctrl" to file f at file position "pos"
        !          1358:  */
        !          1359: void write_trust_pos(FILE * f, byte keyctrl, long pos)
        !          1360: {
        !          1361:     long fpos;
        !          1362: 
        !          1363:     fpos = ftell(f);
        !          1364:     fseek(f, pos, SEEK_SET);
        !          1365:     write_trust(f, keyctrl);
        !          1366:     fseek(f, fpos, SEEK_SET);
        !          1367: }                              /* write_trust_pos */
        !          1368: 
        !          1369: /*
        !          1370:  * read a trust byte packet from file f, the trust byte will be
        !          1371:  * stored in "keyctrl".
        !          1372:  * returns -1 on EOF, -3 on corrupt input, and ERR_NOTRUST if
        !          1373:  * the packet was not a trust byte (this can be used to check if
        !          1374:  * a file is a keyring (with trust bytes) or a keyfile).
        !          1375:  * The current file position is left unchanged in this case.
        !          1376:  */
        !          1377: int read_trust(FILE * f, byte * keyctrl)
        !          1378: {
        !          1379:     unsigned char buf[3];
        !          1380: 
        !          1381:     if (fread(buf, 1, 3, f) != 3)
        !          1382:        return -1;
        !          1383:     if (buf[0] != CTB_KEYCTRL) {
        !          1384:        if (is_ctb(buf[0])) {
        !          1385:            fseek(f, -3L, SEEK_CUR);
        !          1386:            return ERR_NOTRUST;
        !          1387:        } else
        !          1388:            return -3;          /* bad data */
        !          1389:     }
        !          1390:     if (buf[1] != 1)           /* length must be 1 */
        !          1391:        return -3;
        !          1392:     if (keyctrl)
        !          1393:        *keyctrl = buf[2];
        !          1394:     return 0;
        !          1395: }                              /* read_trust */
        !          1396: 
        !          1397: 
        !          1398: 
        !          1399: /****** userid lookup ******/
        !          1400: 
        !          1401: #define        HASH_ALLOC      (ALLOC_UNIT / sizeof(struct hashent))
        !          1402: 
        !          1403: static char *store_str(char *str);
        !          1404: static VOID *allocbuf(int size);
        !          1405: static void freebufpool();
        !          1406: 
        !          1407: static struct hashent {
        !          1408:     struct hashent *next;
        !          1409:     byte keyID[KEYFRAGSIZE];
        !          1410:     char *userid;
        !          1411: } **hashtbl = NULL, *hashptr;
        !          1412: 
        !          1413: static char *strptr;
        !          1414: static int strleft = 0;
        !          1415: static int hashleft = 0;
        !          1416: static int nleft = 0;
        !          1417: 
        !          1418: #define MAXKR  8       /* max. number of keyrings for user_from_keyID() */
        !          1419: static char *krnames[MAXKR];
        !          1420: static int nkr = 0;
        !          1421: 
        !          1422: /*
        !          1423:  * Lookup userid by keyID without using the in-memory hash table.
        !          1424:  */
        !          1425: static char *
        !          1426:  _user_from_keyID(byte * srch_keyID)
        !          1427: {
        !          1428:     FILE *f;
        !          1429:     int i, status, found = 0;
        !          1430:     byte keyID[KEYFRAGSIZE];
        !          1431:     static char userid[256];
        !          1432:     byte ctb;
        !          1433: 
        !          1434:     /* search all keyfiles set with setkrent() */
        !          1435:     for (i = 0; !found && i < nkr; ++i) {
        !          1436:        if ((f = fopen(krnames[i], FOPRBIN)) == NULL)
        !          1437:            continue;
        !          1438:        while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) {
        !          1439:            if (status == -2 || status == -3)
        !          1440:                break;
        !          1441:            if (is_key_ctb(ctb) && memcmp(keyID, srch_keyID, KEYFRAGSIZE) == 0)
        !          1442:                found = 1;
        !          1443:            if (found && ctb == CTB_USERID)
        !          1444:                break;
        !          1445:        }
        !          1446:        fclose(f);
        !          1447:     }
        !          1448:     return found ? userid : NULL;
        !          1449: }                              /* _user_from_keyID */
        !          1450: 
        !          1451: /*
        !          1452:  * Lookup userid by keyID, use hash table if initialized.
        !          1453:  */
        !          1454: char *
        !          1455:  user_from_keyID(byte * keyID)
        !          1456: {
        !          1457:     struct hashent *p;
        !          1458: 
        !          1459:     if (!hashtbl)
        !          1460:        return _user_from_keyID(keyID);
        !          1461:     for (p = hashtbl[PK_HASH(keyID)]; p; p = p->next)
        !          1462:        if (memcmp(keyID, p->keyID, KEYFRAGSIZE) == 0)
        !          1463:            return p->userid;
        !          1464:     return NULL;
        !          1465: }                              /* user_from_keyID */
        !          1466: 
        !          1467: /*
        !          1468:  * add keyfile to userid hash table, userids are added, endkrent() clears
        !          1469:  * the hash table.
        !          1470:  */
        !          1471: int setkrent(char *keyring)
        !          1472: {
        !          1473:     int i;
        !          1474: 
        !          1475:     assert(nkr < MAXKR);
        !          1476:     if (keyring == NULL)
        !          1477:        keyring = globalPubringName;
        !          1478:     for (i = 0; i < nkr; ++i)
        !          1479:        if (strcmp(keyring, krnames[i]) == 0)
        !          1480:            return 0;           /* duplicate name */
        !          1481:     krnames[nkr++] = store_str(keyring);
        !          1482:     return 0;
        !          1483: }                              /* setkrent */
        !          1484: 
        !          1485: void endkrent(void)
        !          1486: {
        !          1487:     hashleft = strleft = 0;
        !          1488:     hashtbl = NULL;
        !          1489:     nkr = 0;
        !          1490:     freebufpool();
        !          1491: }                              /* endkrent */
        !          1492: 
        !          1493: /*
        !          1494:  * create userid hash table, read all files set with setkrent()
        !          1495:  */
        !          1496: int init_userhash(void)
        !          1497: {
        !          1498:     FILE *f;
        !          1499:     int status, i;
        !          1500:     byte keyID[KEYFRAGSIZE];
        !          1501:     char userid[256];
        !          1502:     byte ctb;
        !          1503:     int keyflag;
        !          1504: 
        !          1505:     if (!hashtbl) {
        !          1506:        hashtbl = allocbuf(PK_HASHSIZE * sizeof(struct hashent *));
        !          1507:        memset(hashtbl, 0, PK_HASHSIZE * sizeof(struct hashent *));
        !          1508:     }
        !          1509:     for (i = 0; i < nkr; ++i) {
        !          1510:        if ((f = fopen(krnames[i], FOPRBIN)) == NULL)
        !          1511:            continue;
        !          1512:        keyflag = 0;
        !          1513:        while ((status = readkpacket(f, &ctb, userid, keyID, NULL)) != -1) {
        !          1514:            if (is_key_ctb(ctb) && user_from_keyID(keyID) == NULL)
        !          1515:                keyflag = 1;
        !          1516:            if (keyflag && ctb == CTB_USERID) {
        !          1517:                if (!hashleft) {
        !          1518:                    hashptr = allocbuf(HASH_ALLOC * sizeof(struct hashent));
        !          1519:                    hashleft = HASH_ALLOC;
        !          1520:                }
        !          1521:                memcpy(hashptr->keyID, keyID, KEYFRAGSIZE);
        !          1522:                hashptr->userid = store_str(userid);
        !          1523:                hashptr->next = hashtbl[PK_HASH(keyID)];
        !          1524:                hashtbl[PK_HASH(keyID)] = hashptr;
        !          1525:                ++hashptr;
        !          1526:                --hashleft;
        !          1527:                keyflag = 0;
        !          1528:            }
        !          1529:        }
        !          1530:        fclose(f);
        !          1531:     }
        !          1532:     return 0;
        !          1533: }                              /* init_userhash */
        !          1534: 
        !          1535: /*
        !          1536:  * memory management routines
        !          1537:  */
        !          1538: 
        !          1539: static void maint_init_mem(void)
        !          1540: {
        !          1541:     pkhash = allocbuf(PK_HASHSIZE * sizeof(struct pubkey *));
        !          1542:     memset(pkhash, 0, PK_HASHSIZE * sizeof(struct pubkey *));
        !          1543: }
        !          1544: 
        !          1545: static void maint_release_mem(void)
        !          1546: {
        !          1547:     nleft = 0;
        !          1548:     strleft = 0;
        !          1549:     pkhash = NULL;
        !          1550:     freebufpool();
        !          1551: }
        !          1552: 
        !          1553: /*
        !          1554:  * allocn() does the same as malloc().  Memory is allocated in chunks
        !          1555:  * of ALLOC_UNIT bytes, all memory can be freed by calling freebufpool().
        !          1556:  */
        !          1557: static VOID *
        !          1558:  allocn(int size)
        !          1559: {
        !          1560:     static char *ptr;
        !          1561: #ifndef MSDOS                  /* don't align on MSDOS to save memory */
        !          1562:     size = (size + 3) & ~3;
        !          1563: #endif
        !          1564:     assert(size < ALLOC_UNIT);
        !          1565:     if (size > nleft) {
        !          1566:        ptr = allocbuf(ALLOC_UNIT);
        !          1567:        nleft = ALLOC_UNIT;
        !          1568:     }
        !          1569:     nleft -= size;
        !          1570:     ptr += size;
        !          1571:     return ptr - size;
        !          1572: }                              /* allocn */
        !          1573: 
        !          1574: /*
        !          1575:  * store_str does the same as strdup(), but allocates memory with allocbuf()
        !          1576:  */
        !          1577: static char *
        !          1578:  store_str(char *str)
        !          1579: {
        !          1580:     int size = strlen(str) + 1;
        !          1581:     if (size > ALLOC_UNIT) {
        !          1582:        fprintf(stderr, "store_str: string too long\n");
        !          1583:        return NULL;
        !          1584:     }
        !          1585:     if (size > strleft) {
        !          1586:        strptr = allocbuf(ALLOC_UNIT);
        !          1587:        strleft = ALLOC_UNIT;
        !          1588:     }
        !          1589:     strcpy(strptr, str);
        !          1590:     strptr += size;
        !          1591:     strleft -= size;
        !          1592:     return strptr - size;
        !          1593: }                              /* store_str */
        !          1594: 
        !          1595: 
        !          1596: static struct bufpool {
        !          1597:     struct bufpool *next;
        !          1598:     char buf[1];               /* variable size */
        !          1599: } *bufpool = NULL;
        !          1600: 
        !          1601: long totalsize = 0;
        !          1602: 
        !          1603: /*
        !          1604:  * allocate buffer, all buffers allocated with this function can be
        !          1605:  * freed with one call to freebufpool()
        !          1606:  */
        !          1607: static VOID *
        !          1608:  allocbuf(int size)
        !          1609: {
        !          1610:     struct bufpool *p;
        !          1611: 
        !          1612:     p = xmalloc(size + sizeof(struct bufpool *));
        !          1613:     totalsize += size;
        !          1614:     p->next = bufpool;
        !          1615:     bufpool = p;
        !          1616:     return p->buf;
        !          1617: }                              /* allocbuf */
        !          1618: 
        !          1619: /*
        !          1620:  * free all memory obtained with allocbuf()
        !          1621:  */
        !          1622: static void freebufpool(void)
        !          1623: {
        !          1624:     struct bufpool *p;
        !          1625: 
        !          1626:     if (verbose)
        !          1627:        fprintf(pgpout, "\nMemory used: %ldk\n", totalsize / 1024);
        !          1628:     totalsize = 0;
        !          1629:     while (bufpool) {
        !          1630:        p = bufpool;
        !          1631:        bufpool = bufpool->next;
        !          1632:        free(p);
        !          1633:     }
        !          1634:     nleft = strleft = hashleft = 0;
        !          1635: }                              /* freebufpool */
        !          1636: 
        !          1637: #ifdef MACTC5
        !          1638: void ReInitKeyMaint(void);
        !          1639: 
        !          1640: void ReInitKeyMaint(void) {
        !          1641:        trustlst_len = 9;
        !          1642:        legitlst_len = 9;
        !          1643:        strcpy(floppyring,"");
        !          1644:        check_only = FALSE;
        !          1645:        floppy_fp = NULL;
        !          1646:        pkhash = NULL;
        !          1647:        pklist = NULL;
        !          1648:        hashtbl = NULL;
        !          1649:        totalsize = 0;
        !          1650: }
        !          1651: #endif

unix.superglobalmegacorp.com

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