pgprngread.c
来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 2,259 行 · 第 1/5 页
C
2,259 行
name->flags &= ~NAMEF_FILEMASK;
name->flags |= MEMRINGBIT;
return name->name.ptr = (char *)pos->ptr.buf;
}
/* Allocate cache space for it */
/* Dummy loop to break out of */
do {
/* Try the preferred cache */
file2 = file;
cut = file2->strings; /* Remember cutback position */
str = (char *)memPoolAlloc(&file2->strings, name->len, 1);
if (str)
break;
/* Try the pktbuf */
str = ringReserve(pool, name->len);
if (str) {
file2 = NULL;
pool->pktbuflen = name->len;
break;
}
/* Okay, desperation time - look for any cache */
mask = name->mask & pool->filemask & ~MEMRINGMASK;
pos = &name->pos;
for (;;) {
i = ringLsBitFind(mask);
pgpAssert(i >= 0);
pgpAssert (i < MEMRINGBIT);
pgpAssert(pool->files[i].f);
file2 = &pool->files[i];
cut = file2->strings;
str = (char *)memPoolAlloc(&file2->strings,
name->len, 1);
if (str)
break;
if (!(mask &= mask-1)) {
ringAllocErr(pool);
return NULL;
}
pos = pos->ptr.next;
}
} while (0); /* Dummy loop to break out of */
/* Okay, we got buffer space... get the packet */
if (pgpFileSeek(file->f, pos->fpos, SEEK_SET) != 0) {
i = PGPERR_KEYIO_SEEKING;
goto error;
}
i = pktByteGet(file->f, &len, (word32 *)NULL);
if (i < 0)
goto error;
if (PKTBYTE_TYPE(i) != PKTBYTE_NAME || len != name->len)
goto badpkt;
i = pgpFileRead(str, (size_t)len, file->f);
if ((size_t)i != (size_t)len) {
i = pgpFileError(file->f) ? PGPERR_KEYIO_READING :
PGPERR_KEYIO_EOF;
goto error;
}
/* Double-check that we got the right thing. */
if (ringHashBuf((byte *)str, len) != name->name.hash)
goto badpkt;
/* Success at last! */
if (file2) {
/* It's cached in file2 - set flags appropriately */
NAMESETCACHED(name);
name->flags &= ~NAMEF_FILEMASK;
name->flags |= ringLsBitFind(file2->set.mask);
name->name.ptr = str;
}
return str;
badpkt:
i = PGPERR_KEYIO_BADPKT;
error:
if (file2)
memPoolCutBack(&file2->strings, &cut);
ringErr(file, pos->fpos, i);
return NULL;
}
void const *
ringFetchObject(struct RingSet const *set, union RingObject *obj, size_t *lenp)
{
byte const *buf = NULL;
ringmask secmask, bestfile; /* Needed in RINGTYPE_KEY */
struct RingPool *pool = set->pool;
byte pktbyte;
pgpAssert(obj->g.mask & set->mask);
pgpAssert(obj->g.mask & pool->filemask);
switch (ringObjectType(obj)) {
case RINGTYPE_NAME:
buf = (byte const *)ringPoolGetName(pool, &obj->n, lenp);
break;
case RINGTYPE_SIG:
buf = (byte const *)ringFetchPacket(pool, obj, 0, PKTBYTE_SIG,
RINGSIG_MAXLEN, lenp, ringSigVerify);
break;
case RINGTYPE_UNK:
buf = (byte const *)ringFetchPacket(pool, obj, 0,
PKTBYTE_TYPE(obj->u.pktbyte),
RINGUNK_MAXLEN, lenp, ringUnkVerify);
break;
case RINGTYPE_SEC:
pktbyte = OBJISTOPKEY(obj->g.up) ? PKTBYTE_SECKEY :
PKTBYTE_SECSUBKEY;
buf = (byte const *)ringFetchPacket(pool, obj, 0,
pktbyte, RINGSEC_MAXLEN,
lenp, ringSecVerify);
/* Compensate for version bug */
if (buf
&& *lenp > 0
&& obj->g.flags & SECF_VERSION_BUG
&& buf[0] == PGPVERSION_2_6)
((byte *)buf)[0] = PGPVERSION_2;
break;
case RINGTYPE_KEY:
/* File we'd like to fetch from */
bestfile = ringBestFile(pool, obj, 0)->set.mask;
/* Where secrets are located */
secmask = ringKeySecMask(obj);
/* Is where we want to fetch from secret? */
if (bestfile & secmask) {
pktbyte = OBJISTOPKEY(obj) ? PKTBYTE_SECKEY :
PKTBYTE_SECSUBKEY;
/* Have to fetch the secret key and extract. */
obj = obj->g.down;
while (!(obj->g.mask & bestfile) || !OBJISSEC(obj)) {
obj = obj->g.next;
pgpAssert(obj);
}
buf = (byte const *)ringFetchPacket(pool, obj,
~secmask, pktbyte, RINGSEC_MAXLEN,
lenp, ringSecVerify);
if (buf) {
size_t len;
/* Compensate for version bug */
if (*lenp > 0
&& obj->g.flags & SECF_VERSION_BUG
&& buf[0] == PGPVERSION_2_6)
((byte *)buf)[0] = PGPVERSION_2;
len = ringKeyParsePublicPrefix(buf, *lenp);
/* If unparseable, take the whole thing. */
if (len)
*lenp = len;
}
} else {
pktbyte = OBJISTOPKEY(obj) ? PKTBYTE_PUBKEY :
PKTBYTE_PUBSUBKEY;
/* Fetch public components */
buf = (byte const *)ringFetchPacket(pool, obj, secmask,
pktbyte, RINGKEY_MAXLEN,
lenp, ringKeyVerify);
}
break;
default:
pgpAssert(0);
break;
}
return buf;
}
/*** Various bookkeeping helper functions ***/
/*
* Sort all the keys in a pool into keyID order. This uses 8 passes
* of a byte-wise radix sort. Each pass is stable, so sorting on the
* least significant byte, proceeding to the most will result in a
* completely sorted list.
*
* Actually, it's sorted with the *visible* part (the low 32 bits) of the
* keyID more significant than the invisible part. This makes the ordering
* more sensible to a human watching what's going on.
*
* There are 256 lists, with a head and a tail pointer. The tail
* pointer is a pointer to a pointer, namely the slot the pointer to
* the next entry to be added to the list goes in. It is initialized
* to point to the head pointer. So adding an element to the list
* consists of setting *tail = object; and then tail = &object->next;
*
* After each pass, concatenate the lists, starting at the end.
* Begin with an empty list and keep appending the current list to
* the tail of the one before it, grabbing the head as the new
* current list.
*/
#if 0
static int
ringKeyIDcmp(byte const id1[8], byte const id2[8])
{
int i;
i = memcmp(id1+4, id2+4, 4);
return i ? i : memcmp(id1, id2, 4);
}
#endif
static void
ringSortKeys(struct RingPool *pool)
{
#if 1
/*
* Disable sort, users who switch back to old versions of
* PGP are unhappy to see their keyring reordered. The reason
* for the sort was to hide the order with which keys had been
* added to the keyring, and to make merges more efficient.
* For now neither of those is compelling enough to keep.
*/
(void)pool;
#else
int i, j;
int pass;
int lastpass;
union RingObject *list = pool->keys;
union RingObject *head[256];
union RingObject **tail[256];
for (pass=0; pass<9; ++pass) {
/* XXX Experimental backwards compat code - put DSA keys at end */
/* On last pass we sort by pkalg */
lastpass = (pass==8);
i = (pass < 4) ? (3-pass) : (11-pass); /* 3,2,1,0,7,6,5,4 */
/* Clear the table for the next distribution pass */
for (j = 0; j < 256; j++)
tail[j] = head+j;
/* Distribute the list elements among the sublists */
while (list) {
if (lastpass)
j = list->k.pkalg;
else
j = list->k.keyID[i];
*tail[j] = list;
tail[j] = &list->k.next;
list = list->k.next;
}
j = 256;
/* list is already 0 from the previous loop */
/* Gather the sublists back into one big list */
while (j--) {
*tail[j] = list;
list = head[j];
}
}
pool->keys = list;
#endif
}
static void
ringPoolLinkKey(struct RingPool *pool, union RingObject *parent,
union RingObject *key, byte pkalg, byte const keyID[8])
{
union RingObject **ptr;
pgpAssert(OBJISKEY(key));
memcpy(key->k.keyID, keyID, 8);
key->k.pkalg = pkalg;
if (parent) {
key->g.up = parent;
ptr = &parent->g.down;
while (*ptr)
ptr = &(*ptr)->g.next;
} else {
ptr = &pool->keys;
}
key->g.next = *ptr;
*ptr = key;
RINGPOOLHASHKEY(pool, key);
}
/* Remove specified key from the top-level keys list */
static void
ringPoolUnlinkKey(struct RingPool *pool, union RingObject *key)
{
union RingObject *obj, **objp;
pgpAssert(pool && key);
objp = &pool->keys;
while ((obj = *objp) != NULL && obj != key) {
objp = &obj->g.next;
}
pgpAssert(obj == key);
*objp = key->g.next;
key->g.next = NULL;
return;
}
/*
* Same as ringPoolFindKey, but creates a dummy key with the given parent
* if one is not found.
* Note that a dummy key is a RingObject with its mask set to 0.
*/
static union RingObject *
ringPoolFindDummyKey(struct RingPool *pool, union RingObject *parent,
byte pkalg, byte const keyID[8])
{
union RingObject *key = ringPoolFindKey(pool, pkalg, keyID);
if (!key) {
key = ringNewKey(pool);
if (key) {
if (parent)
key->k.flags |= RINGOBJF_SUBKEY;
ringPoolLinkKey(pool, parent, key, pkalg, keyID);
}
}
return key;
}
/*
* Free an entire tree of objects.
* This does not do anything with the FilePos chain, but since the
* first entry is preallocated, if the object has at most one FilePos,
* (as is the case in newly created objects), no memory is leaked.
*/
static void
ringFreeTree(struct RingPool *pool, union RingObject *obj)
{
union RingObject *down;
if (!OBJISBOT(obj)) {
while ((down = obj->g.down) != NULL) {
obj->g.down = down->g.next;
ringFreeTree(pool, down);
}
}
ringFreeObject(pool, obj);
}
/*
* Free up a newly created dummy key.
* Unlink it from the pool and free it and all descendents.
*/
static void
ringFreeDummyKey(struct RingPool *pool, union RingObject *key)
{
union RingObject **objp;
pgpAssert(OBJISKEY(key));
/* Find head of list this object is on */
if (OBJISTOP(key))
objp = &pool->keys;
else
objp = &key->g.up->g.down;
while (*objp != key) {
pgpAssert(*objp);
objp = &(*objp)->g.next;
}
*objp = key->g.next;
ringFreeTree(pool, key);
}
/*
* Return 0 if the packet in the pktbuf is the same as the packet in
* the given file at the given offset, and the file packet is of type
* pkttype. Returns 1 if they differ, and -1 (and sets the ring's error
* status) if there is an error, including an unexpected packet byte.
* Compare at most max bytes.
*
* This does NOT examine any more of the object than its filepos
* chain; in particular, it does NOT examine the object's type.
* Thus, it is possible to have a key object and use it to
* fetch a secret-key packet.
*
* Special case: returns pktbuf[0] if pktbuf[0] is 2 or 3 and the file's
* packet begins with 5-pktbuf[0]. This is used by the key difference
* code to detect the version byte bug. The other things can ignore it,
* and just treat all positive return values as "different".
*/
static int
ringPacketDiffers(struct RingFile *file, union RingObject const *obj,
int pkttype, word32 max)
{
struct RingPool *pool = file->set.pool;
struct FilePos const *pos;
byte *p;
struct PgpFile *f;
word32 len;
int i;
byte c;
int magic;
pos = ringFilePos(obj, file);
/* Memory file, special case for comparison */
if (file->set.mask == MEMRINGMASK) {
len = pos->fpos;
if (len > max)
len = max;
if (max > pool->pktbuflen)
max = pool->pktbuflen;
if (len != max)
return 1; /* Different */
if (!len)
return 0;
/* Check first character specially */
p = (byte *)pos->ptr.buf;
magic = 0;
if (p[0] != ((byte *)pool->pktbuf)[0]) {
if ((p[0] ^ ((byte *)pool->pktbuf)[0]) != 1
|| (p[0] & ((byte *)pool->pktbuf)[0]) != 2)
return 1; /* First char different */
magic = ((byte *)pool->pktbuf)[0]; /* First char magic */
}
return memcmp(p+1, pool->pktbuf+1, (size_t)len-1) ? 1 : magic;
}
/* Usual case - external file */
f = file->f;
pgpAssert(f);
i = pgpFileSeek(f, pos->fpos, SEEK_SET);
if (i != 0) {
ringErr(file, pos->fpos, PGPERR_KEYIO_SEEKING);
return PGPERR_KEYIO_SEEKING;
}
i = pktByteGet(f, &len, (word32 *)NULL);
if (i < 0) {
ringErr(file, pos->fpos, i);
return i;
}
if (PKTBYTE_TYPE(i) != pkttype) {
ringErr(file, pos->fpos, PGPERR_KEYIO_BADPKT);
return PGPERR_KEYIO_BADPKT;
}
if (len > max)
len = max;
if (max > pool->pktbuflen)
max = pool->pktbuflen;
if (len != max)
return 1; /* Different */
if (!len)
return 0;
/* Check first character specially */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?