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

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

unix.superglobalmegacorp.com

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