📄 pgpk.c
字号:
if (!*pub) {
if (log)
fprintf (log,
"Unknown pubring file, assuming \"pubring.pkr\"\n");
*pub = "pubring.pkr";
}
*pubring = mainOpenRingfile (env, ringpool, *pub, "public",1);
}
if (sec && secring) {
*sec = pgpenvGetString (env, PGPENV_SECRING, NULL, NULL);
if (!*sec) {
if (log)
fprintf (log,
"Unknown secring file, assuming \"secring.skr\"\n");
*sec = "secring.skr";
}
*secring = mainOpenRingfile (env, ringpool, *sec, "private",0);
}
}
/*
* Searches <ring> for keys matching the substrings on the
* command line. <ring> must be immutable.
* If <argc>==0 and <defAll>, uses the entire <ring>.
* In either case, the *set returned is a valid, newly created, immutable
* set.
*
* Returns 1 if any keys were selected, else 0.
*/
static int
selectKeyArgs(struct PgpEnv *env, int argc, char *argv[],
char const *ringName, struct RingSet const *ring,
struct RingSet **set, int defAll)
{
int anykeys = 0, i, result;
(void)env; /* Avoid warning */
if (argc <= 0 && defAll) {
*set = ringSetCopy(ring);
if (!*set)
exitUsage(ringPoolError(ringpool)->error);
anykeys = 1; /* XXX: Not necessarily, ring might be empty */
} else {
*set = ringSetCreate(ringpool);
if (!*set)
exitUsage(ringPoolError(ringpool)->error);
for (i = 0; i < argc; i++) {
result = ringSetFilterSpec(ring, *set, argv[i], 0);
if (result < 0)
exitUsage(result);
else if (result > 0)
anykeys = 1;
else
fprintf(stderr,
"No key named \"%s\" in keyring \"%s\"\n",
argv[i], ringName);
}
}
return anykeys;
}
/*
* This selects one RingObject from the given immutable <set> for which
* (*filt)(env, obj, arg) returns non-zero. (*print)(env, file, obj, arg)
* should print a label for the appropriate object to file (with newline),
* suitable for a menu. If there is more than one candidate, and <print>
* is non-null, the user is presented with a menu to choose from. If
* there's more than one candidate and <print> is null, or if there are no
* candidates, 1 is returned. The object is returned in <obj>, or NULL if
* there was an error. Returns < 0 for a library error, 1 for other error,
* or 0 on success.
*
* The <print> function may assume that the global <allkeys> will be
* set correctly by the time it is called. This routine makes sure of
* that, the caller doesn't have to.
*/
static int
selectOneRingObj(struct PgpEnv *env, struct RingSet *set, int level,
union RingObject **obj1, FILE *out, char const *header,
void *arg,
int (*filt)(struct PgpEnv *env, union RingObject const *obj,
void *arg),
void (*print)(struct PgpEnv *env, union RingObject *obj,
FILE *file, void *arg))
{
struct RingIterator *iter;
union RingObject *obj, *objList[50];
int maxObjs = sizeof(objList) / sizeof(objList[0]);
int numObjs = 0;
int notFirst = 0;
int result;
long choice;
char *endNum, buf[32];
int i;
*obj1 = NULL;
iter = ringIterCreate(set);
if (!iter)
return ringSetError(set)->error;
/* Advance iter state */
for (i=1; i<level; ++i)
if ((result = ringIterNextObject(iter, i)) < 0)
return result;
for (;;) {
result = ringIterNextObject(iter, level);
if (result < 0)
goto destroyAndExit;
else if (result == 0)
break;
if (numObjs >= maxObjs) {
fprintf(stderr, "Too many matches; aborting!\n");
goto destroyAndError;
}
obj = ringIterCurrentObject(iter, level);
pgpAssert(obj);
if (filt(env, obj, arg)) {
objList[numObjs++] = obj;
if (notFirst) {
if (!print || !out)
goto destroyAndError;
loadAllKeys(env, 0, 0);
if (numObjs == 2) {
fprintf(out, "%s\n 1) ", header);
print(env, objList[0], out, arg);
}
fprintf(out, "%2d) ", numObjs);
print(env, obj, out, arg);
}
else
notFirst = 1;
}
}
ringIterDestroy(iter);
if (numObjs < 1)
return 1;
else if (numObjs == 1) {
*obj1 = objList[0];
return 0;
}
pgpAssert(out);
fprintf(out, "Choose one of the above: ");
pgpTtyGetString(buf, sizeof(buf), out);
choice = strtol(buf, &endNum, 10);
while (isspace(*endNum))
endNum++;
if (*endNum || choice < 1 || choice > numObjs) {
fprintf(stderr, "Invalid choice\n");
return 1;
}
*obj1 = objList[choice - 1];
return 0;
destroyAndError:
result = 1;
destroyAndExit:
ringIterDestroy(iter);
return result;
}
/* A filter for selectOneRingObj (above), which selects all keys */
static
int keyFilt(struct PgpEnv *env, union RingObject const *obj, void *arg)
{
(void)env; /* Avoid warnings */
(void)arg;
return ringObjectType(obj) == RINGTYPE_KEY;
}
/* A filter to select the specified type */
static
int typeFilt(struct PgpEnv *env, union RingObject const *obj, void *arg)
{
byte mtype = *(byte *)arg;
(void)env; /* Avoid warnings */
return ringObjectType(obj) == mtype;
}
/*
* A filter for signatures that won't show revocations. We don't print
* those out explicitly so it is better not to try to choose them.
*/
static
int sigFilt(struct PgpEnv *env, union RingObject const *obj, void *arg)
{
(void)env;
(void)arg;
if (ringObjectType(obj) == RINGTYPE_SIG) {
int type = ringSigType(allkeys, (union RingObject *) obj);
if (type != PGP_SIGTYPE_KEY_COMPROMISE &&
type != PGP_SIGTYPE_KEY_UID_REVOKE)
return 1; /* accept */
}
return 0; /* reject */
}
/*
* A key printer for selectOneRingObj (above),
* which prints keys for a menu.
*/
static void
keyPrint(struct PgpEnv *env, union RingObject *obj,
FILE *file, void *arg)
{
struct PgpTtyUI ui;
(void)env; /* Avoid warnings */
(void)arg;
ui.fp = file;
fputc('\n', file);
pgpAssert(allkeys);
ringTtyShowKey((void *) &ui, obj, allkeys, 0);
}
/*
* A name printer for selectOneRingObj (above),
* which prints keys for a menu.
*/
static void
namePrint(struct PgpEnv *env, union RingObject *obj,
FILE *file, void *arg)
{
char const *namestring;
size_t len;
struct PgpTtyUI ui;
(void)env; /* Avoid warnings */
(void)arg;
ui.fp = file;
fputc('\n', file);
pgpAssert(allkeys);
namestring = ringNameName (allkeys, obj, &len);
ringTtyPutString (namestring, len, (unsigned) len, file, 0, 0);
fputs("\n", file);
ringTtyShowSigs ((void *) &ui, obj, allkeys, 2);
}
/*
* A sig printer for selectOneRingObj (above),
* which prints keys for a menu.
*/
static void
sigPrint(struct PgpEnv *env, union RingObject *obj,
FILE *file, void *arg)
{
(void)env; /* Avoid warnings */
(void)arg;
pgpAssert(allkeys);
fputc('\n', file);
ringTtyShowSig(obj, allkeys, file, 1);
}
static void
objPrint(struct PgpEnv *env, union RingObject *obj,
FILE *file, void *arg)
{
switch (ringObjectType(obj)) {
case RINGTYPE_KEY:
keyPrint(env, obj, file, arg);
break;
case RINGTYPE_NAME:
namePrint(env, obj, file, arg);
break;
case RINGTYPE_SIG:
sigPrint(env, obj, file, arg);
break;
}
}
/*
* Add an object with all its children to the dest key set.
* The src key set, which controls which children are taken, must be
* immutable. dest must be mutable.
* Return number of objects added, or negative on error.
*/
static int
ringSetAddHierarchy(struct RingSet *dest, struct RingSet const *src,
union RingObject *obj)
{
struct RingIterator *iter;
int level, initlevel;
int nobjs;
int err;
/* First add the object */
if ((err=ringSetAddObject(dest, obj)) < 0)
return err;
iter = ringIterCreate(src);
if (!iter)
return ringSetError(src)->error;
nobjs = 1;
initlevel=ringIterSeekTo(iter, obj);
if (initlevel < 0)
return initlevel;
level = initlevel + 1;
while (level > initlevel) {
union RingObject *child;
err = ringIterNextObject(iter, level);
if (err < 0) {
ringIterDestroy(iter);
return err;
}
if (err > 0) {
child = ringIterCurrentObject(iter, level);
if (!child)
return ringSetError(src)->error;
if ((err=ringSetAddObject(dest, child)) < 0)
return err;
++nobjs;
++level;
} else {
--level;
}
}
ringIterDestroy(iter);
return nobjs;
}
/*
* Service routine for selectRingObject, below. This one selects a user ID
* and optionally a signature from a RingSet composed of a single key
* and its descendants. See the comments for selectRingObject for more
* info on the parameters.
*/
static int
selectChildObject(struct PgpEnv *env, struct RingSet *to_select,
int selecttype, char const *prep, FILE *log,
union RingObject **pobj)
{
struct RingSet *to_select2;
int err;
byte type;
char header[256];
unsigned counts[RINGTYPE_MAX];
pgpAssert (selecttype==RINGTYPE_NAME || selecttype==RINGTYPE_SIG);
ringSetCountTypes(to_select, counts, RINGTYPE_MAX);
if (selecttype == RINGTYPE_NAME)
sprintf (header,
"Please select a user ID %s:", prep);
else
sprintf (header,
"Please select a user ID with a signature %s:", prep);
type = RINGTYPE_NAME;
err = selectOneRingObj(env, to_select, 2, pobj, log,
header, &type, typeFilt, namePrint);
if (err) {
if (log)
fprintf (log,
"No user ID's selected %s.\n", prep);
ringSetDestroy(to_select);
return 0;
}
/* Keep name and all its children */
if (!(to_select2 = ringSetCreate(ringpool))) {
ringSetDestroy(to_select);
return ringPoolError(ringpool)->error;
}
ringSetAddHierarchy(to_select2, to_select, *pobj);
ringSetFreeze(to_select2);
if (selecttype == RINGTYPE_SIG) {
ringSetCountTypes(to_select2, counts, RINGTYPE_MAX);
pgpAssert(counts[RINGTYPE_KEY-1] == 1);
pgpAssert(counts[RINGTYPE_NAME-1] == 1);
sprintf (header,
"Please select a signature %s:", prep);
err = selectOneRingObj(env, to_select2, 3, pobj, log,
header, &type, sigFilt, sigPrint);
if (err) {
if (log)
fprintf (log,
"No signatures selected %s.\n", prep);
ringSetDestroy(to_select2);
return 0;
}
}
ringSetDestroy(to_select2);
pgpAssert(counts[selecttype-1] >= 1);
return counts[selecttype-1]; /* success */
}
/*
* Selection routine.
* Selects a key, userid or
* signature depending on the selecttype parameter, a RINGTYPE_ value.
* Returns pointer to the object in *pobj. Prep is a prepositional
* clause like "to be removed". Returns 0 if no keys selected, negative
* on error. If objects are selected returns the number of objects at
* that level, e.g. if a user ID is selected it returns the number of
* user ID's on that key; if a signature is selected it returns the
* number of sigs on that user ID. This will always be at least 1.
*/
static int
selectRingObject(struct PgpEnv *env, int argc, char **argv, char const *pub,
struct RingSet const *pubring, int selecttype,
char const *prep, FILE *log, union RingObject **pobj)
{
struct RingSet *to_select = NULL, *to_select2 = NULL;
char namebuf[256];
char header[256];
size_t namelen;
int anykeys = 0;
int err;
unsigned counts[RINGTYPE_MAX];
/*
* Protect header[] from being overfilled by the sprintf's to it.
* prep is only set within the program to small strings, so this
* should never happen.
*/
pgpAssert (strlen(prep) < 100);
if (argc == 0) {
pgpAssert(log);
fprintf (log,
"A user ID is required to select the key you want %s.\n\
Enter the key's user ID: ", prep);
namelen = pgpTtyGetString (namebuf, sizeof (namebuf), log);
argv = (char **)pgpMemAlloc(sizeof(char *));
argv[0] = namebuf;
argc = 1;
}
/* Set up for return */
ringSetCountTypes(pubring, counts, RINGTYPE_MAX);
anykeys = selectKeyArgs (env, argc, argv, pub, pubring, &to_select, 0);
if (anykeys) {
ringSetFreeze(to_select);
if (selecttype == RINGTYPE_NAME)
sprintf (header,
"Please select a key with a user ID %s:", prep);
else if (selecttype == RINGTYPE_SIG)
sprintf (header,
"Please select a key with a signature %s:", prep);
else
sprintf (header,
"Please select a key %s:", prep);
anykeys = !selectOneRingObj (env, to_select, 1, pobj, log,
header, NULL, keyFilt, keyPrint);
}
if (!anykeys) {
if (log)
fprintf (log,
"No keys selected %s.\n", prep);
ringSetDestroy(to_select);
return 0;
}
/* Add key and all its children to a new ringset called to_select */
to_select2 = ringSetCreate(ringpool);
if (!to_select2) {
ringSetDestroy(to_select);
return ringPoolError(ringpool)->error;
}
ringSetAddHierarchy(to_select2, to_select, *pobj);
ringSetDestroy(to_select);
to_select = to_select2;
ringSetFreeze(to_select);
/* Handle signature and user ID selection */
if (selecttype != RINGTYPE_KEY) {
err = selectChildObject(env, to_select, selecttype,
prep, log, pobj);
ringSetDestroy(to_select);
return err;
}
ringSetDestroy(to_select);
pgpAssert(counts[selecttype-1] >= 1);
return counts[selecttype-1]; /* success */
}
static int
doKeyAdd (struct PgpEnv *env, int argc, char *argv[], struct PgpTtyUI *ui_arg)
{
struct RingSet *pubring = NULL, *secring = NULL;
struct RingSet *newpub = NULL, *newsec = NULL;
struct RingSet *tmpring, *keyfile = NULL;
struct RingIterator *iter;
char const *pub, *sec;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -