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 + -
显示快捷键?