📄 pgpk.c
字号:
/*
* pgpk.c -- PGP Key Management Main Routine!
*
* Copyright (C) 1996,1997 Pretty Good Privacy, Inc. All rights reserved.
*
* Written by: Derek Atkins <warlord@MIT.EDU>
* Mark H. Weaver <mhw@netris.org>
* Chris Harman <charman@pgp.com>
*
* $Id: pgpk.c,v 1.1.2.5 1997/06/07 09:49:18 mhw Exp $
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for sbrk() */
#endif
#ifdef UNIX
#include <sys/stat.h> /* for umask() */
#endif
#include "pgpDebug.h"
#include "pgpArmor.h"
#include "pgpFileMod.h"
#include "pgpFIFO.h"
#include "pgpKeySpec.h"
#include "pgpMem.h"
#include "pgpPassCach.h"
#include "pgpConf.h"
#include "pgpEnv.h"
#include "pgpErr.h"
#include "pgpFile.h"
#include "pgpUI.h"
#include "pgpPipeline.h"
#include "pgpPubKey.h"
#include "pgpRndom.h"
#include "pgpRndPool.h"
#include "pgpRngPub.h"
#include "pgpRngRead.h"
#include "pgpUserIO.h"
#include "pgpUsuals.h"
#include "pgpRingUI.h"
#include "pgpRngMnt.h"
#include "pgpSigSpec.h"
#include "pgpTrust.h"
#include "pgpTrstPkt.h"
#include "pgpExit.h"
#include "pgpAppFile.h"
#include "pgpKeyRings.h"
#include "pgpInitApp.h"
#include "pgpOpt.h"
#define MAXARGS 2
struct Flags {
char args[MAXARGS];
int argc;
char const *outfile;
char opt;
byte doarmor;
};
static struct PgpPassCache *passcache = NULL;
static struct RingPool *ringpool = NULL;
static struct RingSet *allkeys = NULL;
static struct PgpRandomContext *rng = NULL;
#define PASSLEN 256
static void
setOptArgs (char const *args, struct PgpOptContext *opt, struct Flags *flags)
{
while (*opt->optarg && strchr (args, *opt->optarg))
flags->args[flags->argc++] = *(opt->optarg++);
}
static void
setOpt (int opt, struct PgpOptContext *optp, struct Flags *flags)
{
if (!flags->opt) {
flags->opt = opt;
if (optp->state == 1 && optp->optarg)
switch (opt) {
case 'k':
setOptArgs ("s", optp, flags);
break;
case 'l':
setOptArgs ("l", optp, flags);
break;
case 'r':
setOptArgs ("su", optp, flags);
break;
case 'x':
setOptArgs ("a", optp, flags);
break;
}
return;
}
exitArgError ("Cannot use -%c and -%c together\n", flags->opt, opt);
}
static void
mainParseArgs (struct PgpUICb *ui, void *ui_arg, struct PgpEnv *env,
int *argcp, char *argv[], struct Flags *flags)
{
struct PgpOptContext opt;
int c, argc = *argcp;
pgpOptStart (&opt, argc, argv);
argc = 0;
while ((c = pgpOptNext (&opt)) != EOF) {
switch (c) {
case 0:
if (opt.optarg[0] != '+' || opt.optarg[1] == '\0')
argv[argc++] = opt.optarg;
else if (pgpConfigLineProcess (ui, ui_arg, env,
opt.optarg + 1,
PGPENV_PRI_CMDLINE))
exitArgError ("Unrecognized option %s",
opt.optarg);
break;
case '-':
/* This accepts --foo */
/* -- is special-cased, so "-- foo" won't do. */
if (pgpConfigLineProcess(ui, ui_arg, env, opt.optarg,
PGPENV_PRI_CMDLINE))
exitArgError (
"Unrecognized option -%s",
opt.optarg - 1);
opt.optarg = NULL;
break;
case 'a': /* Add */
case 'c': /* Check */
case 'd': /* Disable */
case 'e': /* Edit */
case 'g': /* Generate */
case 'k': /* Revo(k)e */
case 'l': /* List */
case 'r': /* Remove */
case 's': /* Sign */
case 'x': /* eXtract */
setOpt (c, &opt, flags);
break;
case 'h': /* Help */
exitUsage (PGPEXIT_OK);
/*NOTREACHED*/
case 'o': /* Output */
/* XXX check for duplicate args */
if (!opt.optarg)
exitArgError (
"-o option requires a userid argument");
flags->outfile = opt.optarg;
opt.optarg = 0;
break;
case 'u': /* Username (myname) */
/* XXX Check for duplicate args */
if (!opt.optarg)
exitArgError (
"-u option requires a userid argument");
pgpenvSetString (env, PGPENV_MYNAME, opt.optarg,
PGPENV_PRI_CMDLINE);
opt.optarg = 0;
break;
case 'v': /* Verbose */
pgpenvSetInt(env, PGPENV_VERBOSE, 1+
pgpenvGetInt(env, PGPENV_VERBOSE,
NULL, NULL), PGPENV_PRI_CMDLINE);
break;
default:
exitArgError ("Unrecognized option -%c", c);
}
}
*argcp = argc;
return;
}
/* Two functions to write out extracted key files */
static int
mainWriteSet (FILE *fp, int flags, struct RingSet const *set)
{
struct PgpFile *pfp = pgpFileWriteOpen (fp, NULL);
int rslt = ringSetWrite (set, pfp, NULL, PGPVERSION_3,
flags);
pgpFileClose(pfp);
return rslt;
}
/* Like mainWriteSet, but for armored files */
static int
mainWriteArmoredSet (FILE *fp, int flags, struct RingSet const *set,
struct PgpEnv *env)
{
struct PgpFile *pfp;
struct PgpPipeline *ppl = NULL;
int rslt;
pfp = pgpFileWriteOpen(fp, NULL);
if (!pfp) {
fclose(fp);
return PGPERR_NOMEM;
}
if (!pgpFileWriteCreate (&ppl, pfp, 1)) {
pgpFileClose(pfp);
return PGPERR_NOMEM;
}
if (!rng)
rng = pgpRandomCreate ();
if (!pgpArmorWriteCreate(&ppl, env, &pgpByteFifoDesc,
rng, PGPVERSION_2_6, PGP_ARMOR_NORMAL)) {
ppl->teardown(ppl);
return PGPERR_NOMEM;
}
pfp = pgpFilePipelineOpen(ppl);
if (!pfp) {
ppl->teardown(ppl);
return PGPERR_NOMEM;
}
rslt = ringSetWrite (set, pfp, NULL, PGPVERSION_2_6, flags);
pgpFileClose(pfp);
return rslt;
}
#if 0
/* Unused at present. fp must be a seekable stream. */
static struct RingSet const *
mainOpenKeyring (FILE *fp, int trusted)
{
struct RingFile *ring;
struct PgpFile *pfp;
int error = 0;
pfp = pgpFileReadOpen (fp, NULL, NULL);
ring = ringFileOpen (ringpool, pfp, trusted, &error);
if (error)
fprintf (stderr, "ringFileOpen returned %d: %s\n",
error, pgperrString (error));
if (ring)
return ringFileSet (ring);
return NULL;
}
#endif
static int
setPassword (struct PgpEnv *env, struct PgpSecKey *seckey, void *ui_arg)
{
char pass[PASSLEN];
char pass2[PASSLEN];
int error;
pgpAssert (! pgpSecKeyIslocked (seckey));
do {
memset (pass, 0, sizeof (pass));
memset (pass2, 0, sizeof (pass2));
pgpTtyGetPass (ui_arg, pass, sizeof(pass));
fputs ("Enter same pass phrase again\n", stderr);
pgpTtyGetPass (ui_arg, pass2, sizeof(pass2));
if (!strcmp (pass, pass2))
break;
fprintf (stderr,
"Error: Pass phrases were different. Try again.\n");
} while (1);
if (!strlen (pass))
return 0;
memset (pass2, 0, sizeof (pass2));
error = pgpSecKeyChangeLock (seckey, env, rng, pass, strlen (pass));
memset (pass, 0, sizeof (pass));
return error;
}
/* Perform the maintenance pass and get trust info for interesting
keys. */
static const char checking[] = "Checking %d signatures...\n";
static int
doKeyEditTrust(union RingObject *obj, struct RingSet *set, int firsttime,
FILE *log); /* forward ref */
/*
* Callback function for displaying sig progress. We just show a count on
* every 10th sig check
*/
static void
mainShowSigCheckProgress(void *arg, struct RingIterator *iter, int checkok)
{
int sigcheckcount = *(int *)arg;
(void)iter;
(void)checkok;
++sigcheckcount;
*(int *)arg = sigcheckcount;
if (sigcheckcount % 10 == 0)
fprintf (stderr, "%6d \r", sigcheckcount);
}
static int
mainDoMaint (void *ui_arg, struct RingSet *keys, int sigcheck,
struct RingSet *sigs)
{
FILE *fp = ((struct PgpTtyUI *) ui_arg)->fp;
int numsigs;
struct RingSet *dest;
unsigned count = 0;
int err;
int sigcheckcount;
#if 0
union RingObject *key, *name;
size_t len;
struct RingIterator *iter;
int rc;
char const *namestring;
#endif
int trust_changed = 0;
/* Check sigs as required */
switch (sigcheck) {
case 1:
/* Only check signatures in sigs that are not
marked as having been checked. */
numsigs = ringPoolCheckCount (sigs, keys, 0);
if (numsigs > 0)
fprintf (fp, checking, numsigs);
sigcheckcount = 0;
if ((err = ringPoolCheck (sigs, keys, 0, mainShowSigCheckProgress,
(void *) &sigcheckcount)) != 0)
fprintf (stderr, "Error %d checking signatures\n", err);
if (sigcheckcount > 0)
fprintf (stderr, "\n");
break;
case 2:
/* Check all signatures as part of a full maintenance
pass */
numsigs = ringPoolCheckCount (keys, keys, 1);
if (numsigs > 0)
fprintf (fp, checking, numsigs);
sigcheckcount = 0;
if ((err = ringPoolCheck (keys, keys, 1, mainShowSigCheckProgress,
(void *) &sigcheckcount)) != 0)
fprintf (stderr, "Error %d checking signatures\n", err);
if (sigcheckcount > 0)
fprintf (stderr, "\n");
break;
default:
fprintf (fp, "No signatures to check...\n");
/* Don't check any sigs */
}
/* Loop around performing maintenance passes until no more
interesting keys are returned. */
do {
dest = ringSetCreate (ringpool);
if (!dest)
return ringPoolError(ringpool)->error;
fprintf (fp, "Computing validity of name/key bindings...\n");
ringMnt (keys, dest, time ((time_t *) NULL));
#if 0
ringSetFreeze (dest);
if (pgpenvGetInt (((struct PgpTtyUI *) ui_arg)->env, PGPENV_BATCHMODE,
NULL, NULL))
count = 0; /* ignore interesting keys in batchmode */
else
ringSetCount (dest, &count, 1);
if (count > 0) {
iter = ringIterCreate (dest);
if (!iter) {
ringSetDestroy (dest);
return ringPoolError(ringpool)->error;
}
/* Ask the user to define the trust for each key returned in dest.
For the new trust model, we must locate the names with undefined
trust.
@@@ May want indication of why key is interesting in future,
and switch based on the reason. */
while (ringIterNextObject (iter, 1) > 0) {
PgpTrustModel pgptrustmodel = pgpTrustModel(ringpool);
key = ringIterCurrentObject (iter, 1);
pgpAssert (key && ringObjectType (key) == RINGTYPE_KEY);
if (pgptrustmodel == PGPTRUST0) {
fprintf (fp, "Trust in the following key is undefined:\n");
ringTtyShowKey (ui_arg, key, keys, 0);
if (doKeyEditTrust (key, keys, 1, fp))
trust_changed = 1;
else
/* So we don't ask again */
ringKeySetTrust (keys, key, PGP_KEYTRUST_UNKNOWN);
} else { /* new trust model */
ringTtyShowKey (ui_arg, key, keys, 0);
while ((rc = ringIterNextObject (iter, 2)) > 0) {
name = ringIterCurrentObject (iter, 2);
if (name && ringObjectType (name) == RINGTYPE_NAME) {
if (ringNameConfidenceUndefined (keys, name)) {
fprintf (fp,
"\nConfidence in the following name is undefined:\n");
namestring = ringNameName (keys, name, &len);
ringTtyPutString (namestring, len, len+2, fp, '"',
'"');
putc ('\n', fp);
if (doKeyEditTrust (name, keys, 1, fp)) {
trust_changed = 1;
} else {
/*
* This is required to force 'undefined trust' to
* 'no trust', so we don't ask again.
*/
ringNameSetConfidence (keys, name, 0);
}
}
}
}
}
ringIterDestroy (iter);
}
#endif
ringSetDestroy (dest);
} while (count > 0 && trust_changed);
return 0;
}
/*
* Makes sure that the global <allkeys> is loaded,
* and returns an error code or 0 if successful.
* If <canFail> is 0, then an error will cause it to exit.
*/
static int
loadAllKeys(struct PgpEnv *env, int canFail, int trusted_only)
{
if (!allkeys) {
int error = mainOpenKeyrings(env, ringpool, trusted_only,
&allkeys);
if (error) {
fprintf(stderr,
"mainOpenKeyrings failed (%d): %s\n",
error, pgperrString (error));
if (canFail)
return error;
else
exitUsage(error);
}
}
return 0;
}
/*
* Interface to loadAllKeys which makes sure <allkeys> will be reloaded.
* Sometimes we want to load only untrusted keyrings but <allkeys> may
* hold trusted ones.
*/
static int
reloadAllKeys(struct PgpEnv *env, int canFail, int trusted_only)
{
if (allkeys) {
ringSetDestroy(allkeys);
allkeys = 0;
}
return loadAllKeys(env, canFail, trusted_only);
}
/*
* Open key rings and return sets for pubring and secring.
*/
static void
mainOpenPubSec(struct PgpEnv *env, char const **pub,
struct RingSet **pubring, char const **sec,
struct RingSet **secring, FILE *log)
{
if (pub && pubring) {
*pub = pgpenvGetString (env, PGPENV_PUBRING, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -