⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgprngread.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			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(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(RingFile *file, union RingObject const *obj,
	int pkttype, PGPUInt32 max)
{
	RingPool *pool = file->set.pool;
	FilePos const *pos;
	PGPByte *p;
	PGPFile *f;
	PGPSize len, len1;
	int i;
	PGPByte c;
	int magic;

	pos = ringFilePos(obj, file);

	/* Memory file, special case for comparison */
	if (pgpVirtMaskIsEqual (&file->set.mask, &pool->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 = (PGPByte *)pos->ptr.buf;
		magic = 0;
		if (p[0] != ((PGPByte *)pool->pktbuf)[0]) {
			if ((p[0] ^ ((PGPByte *)pool->pktbuf)[0]) != 1
			    || (p[0] & ((PGPByte *)pool->pktbuf)[0]) != 2)
		{
			return 1;	/* First char different */
		}
			magic = ((PGPByte *)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, kPGPError_FileOpFailed);
		return kPGPError_FileOpFailed;
	}
	i = pktByteGet(f, &len, &len1, (PGPSize *)NULL);
	if (i < 0) {
		ringErr(file, pos->fpos, (PGPError)i);
		return i;
	}
	if (PKTBYTE_TYPE(i) != pkttype) {
		ringErr(file, pos->fpos, kPGPError_BadPacket);
		return kPGPError_BadPacket;
	}
	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 */
	if (pgpFileRead(&c, 1, f) != 1)  {
		i = pgpFileError(f) ? kPGPError_ReadFailed : kPGPError_EOF;
		ringErr(file, pos->fpos, (PGPError)i);
		return i;
	}
	i = c & 255;
	magic = 0;	/* First char the same */
	if (i != ((PGPByte *)pool->pktbuf)[0]) {
		if ((i ^ ((PGPByte *)pool->pktbuf)[0]) != 1
			|| (i & ((PGPByte *)pool->pktbuf)[0]) != 2)
			return 1;
		magic = ((PGPByte *)pool->pktbuf)[0]; /* First char magic */
	}
	i = fileUnequalBuf(f, pool->pktbuf+1, len-1, len1-1);
	if (i < 0)
		ringErr(file, pos->fpos, (PGPError)i);

	return i ? i : magic;
}

/*
 * Return 1 if the key in the ring's pktbuf differs from the
 * key in its other homes, 0 if it is the same, and <0 if there
 * is some sort of error.
 * Does *not* alter file1's read position unless there is an error.
 * (I.e. if it needs to seek file1, it saves and restores the file
 * position.  It doesn't bother for other files.  Use the MEMRING file
 * if you don't need this feature.)
 *
 * SPECIAL CASE:
 * Returns >1 if the version byte bug was detected.  This is the case
 * wherein version 2.6 would write out an edited secret key with a
 * version byte of 3 even if it was originally 2.
 * This function returns the current pktbuf's version byte (2 or 3)
 * if the keys are identical except that the version byte differs
 * from something read previously.
 * The caller must decide what sort of trouble to log.
 */
int
keysdiffer(RingFile *file1, union RingObject const *key, int pktbyte)
{
	RingPool *pool = file1->set.pool;
	RingFile *file2;
	size_t savelen, publen;
	PGPVirtMask secmask;
	PGPUInt32 max;
	int i, type;
	long retpos=0;

	pgpVirtMaskInit (pool, &secmask);

	pgpAssert(OBJISKEY(key));
	pgpAssert(file1->f ||
			  pgpVirtMaskIsEqual(&file1->set.mask, &pool->memringmask));


	/*
	 * If this is a secret key, find the prefix which is a public key,
	 * and limit it to that if reasonable.
	 */
	savelen = pool->pktbuflen;
	if ((PKTBYTE_TYPE(pktbyte) == PKTBYTE_SECKEY ||
		 PKTBYTE_TYPE(pktbyte) == PKTBYTE_SECSUBKEY)
	    && !(key->g.flags & KEYF_ERROR))
	{
		publen = ringKeyParsePublicPrefix((PGPByte const *)pool->pktbuf,
		                                  pool->pktbuflen);
		if (publen)
			pool->pktbuflen = publen;
	}

	/* Find a file containing the key - try for public first */
	ringKeySecMask(pool, key, &secmask);

	file2 = ringBestFile(pool, key, &secmask);
	if (file2) {
		max = (PGPUInt32)-1;
		type = OBJISTOPKEY(key) ? PKTBYTE_PUBKEY : PKTBYTE_PUBSUBKEY;
	} else {
		file2 = ringBestFile(pool, key, 0);
		pgpAssert(file2);
		max = (PGPUInt32)pool->pktbuflen;
		type = OBJISTOPKEY(key) ? PKTBYTE_SECKEY : PKTBYTE_SECSUBKEY;
	}

	if (file2 == file1 && file1->f && (retpos=pgpFileTell(file1->f)) < 0) {
		ringErr(file1, pgpFileTell(file1->f), kPGPError_FileOpFailed);
		pgpVirtMaskCleanup (pool, &secmask);
		return kPGPError_FileOpFailed;
	}
		
	/* Note that we don't need to seek file2 here, ringPacketDiffers does */
	i = ringPacketDiffers(file2, key, type, max);

	/*
	 * If we compared against a secret key, and encountered the version
	 * bug, and the version bug has already been noted, ignore the
	 * difference.
	 */
	if (i == PGPVERSION_2
            && type == PKTBYTE_SECKEY
	    && key->g.flags & SECF_VERSION_BUG)
		i = 0;

	if (file2 == file1 && file1->f &&
			pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
		ringErr(file1, pgpFileTell(file1->f), kPGPError_FileOpFailed);
		pgpVirtMaskCleanup (pool, &secmask);
		return kPGPError_FileOpFailed;
	}
	
	/* Restore pktbuflen, may have been changed above */
	pool->pktbuflen = savelen;

	pgpVirtMaskCleanup (pool, &secmask);
	return i;
}

/*
 * Return 1 if the secret in the ring's pktbuf differs from the
 * key in its other homes, 0 if it is the same, and <0 if there
 * is some sort of error.
 * Does *not* alter file1's read position unless there is an error.
 *
 * SPECIAL CASE:
 * Returns >1 if the version byte bug was detected.  This is the case
 * wherein version 2.6 would write out an edited secret key with a
 * version byte of 3 even if it was originally 2.
 * This function returns the current pktbuf's version byte (2 or 3)
 * if the keys are identical except that the version byte differs
 * from something read previously.
 * The caller must decide what sort of trouble to log.
 */
/*
 * Return 1 if the signature in the ring's pktbuf differs from the
 * sig in its various homes, 0 if it is the same, and <0 if there
 * is some sort of error.
 * Does *not* alter file1's read position unless there is an error.
 * (I.e. if it needs to seek file1, it saves and restores the file
 * position.  It doesn't bother for other files.  Use the MEMRING file
 * if you don't need this feature.)
 */
static int
secsdiffer(RingFile *file1, union RingObject const *sec)
{
	RingPool *pool = file1->set.pool;
	RingFile *file2;
	long retpos=0;
	PGPByte pktbyte;
	int i;

	pgpAssert(OBJISSEC(sec));

	/* Find a matching signature */
	file2 = ringBestFile(pool, sec, 0);
	pgpAssert (file2);
	pgpAssert (file2->f ||
			   pgpVirtMaskIsEqual (&file2->set.mask, &pool->memringmask));
	if (file2 == file1 && file1->f && (retpos=pgpFileTell(file1->f)) < 0) {
		ringErr(file1, pgpFileTell(file1->f), kPGPError_FileOpFailed);
		return kPGPError_FileOpFailed;
	}

	pktbyte = OBJISTOPKEY(sec->g.up) ? PKTBYTE_SECKEY :
	          PKTBYTE_SECSUBKEY;

	/* Note that we don't need to seek file2 here, ringPacketDiffers does */
	i = ringPacketDiffers(file2, sec, pktbyte, (PGPUInt32)-1);
	if (i < 0)
		return i;

	if (file2 == file1 && file1->f &&
			pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
		ringErr(file1, sec->g.pos.fpos, kPGPError_FileOpFailed);
		return kPGPError_FileOpFailed;
	}
	return i;
}

static union RingObject *
ringFindSec(RingFile *file, union RingObject *parent)
{
	RingPool *pool = file->set.pool;
	union RingObject *sec, **secp;
	int i;

	/* Properties of the secret */
	PGPUInt32 hash;

	hash = ringHashBuf((PGPByte const *)pool->pktbuf, pool->pktbuflen);
	
	/* Search for matching sigs */
	for (secp=&parent->g.down; (sec=*secp) != NULL; secp=&sec->g.next) {
		if (OBJISSEC(sec)
		    && sec->c.hash == hash
		    && (i = secsdiffer(file, sec)) <= 0)
			return i<0 ? NULL : sec;
	}

	/* Not found - allocate a new secret */
	sec = ringNewSec(pool);
	if (sec) {
		/*
		 * Make secret object the first thing.  This is assumed by
		 * ringFindSig which tries to keep sigs together just past
		 * the sec obj.  Especially important with subkeys where it's
		 * hard to tell which sigs go with which keys as we read.
		 */
		sec->g.next = parent->g.down;
		parent->g.down = sec;
		sec->g.up = parent;
		sec->c.hash = hash;
	}
	return sec;
}

/*
 * Return 1 if the name in the ring's pktbuf differs from the
 * name in its various homes, 0 if it is the same, and <0 if there
 * is some sort of error.
 * Does *not* alter file1's read position unless there is an error.
 * (I.e. if it needs to seek file1, it saves and restores the file
 * position.  It doesn't bother for other files.  Use the MEMRING file
 * if you don't need this feature.)
 */
int
namesdiffer(RingFile *file1, union RingObject const *name,
			PGPBoolean fAttribute)
{
	RingPool *pool = file1->set.pool;
	RingFile *file2;
	long retpos=0;
	int i;

	/* Find a matching name */
	file2 = ringBestFile(pool, name, 0);
	pgpAssert (file2);
	pgpAssert (file2->f ||
			   pgpVirtMaskIsEqual (&file2->set.mask, &pool->memringmask));
	if (file2 == file1 && file1->f && (retpos=pgpFileTell(file1->f)) < 0) {
		ringErr(file1, pgpFileTell(file1->f), kPGPError_FileOpFailed);
		return kPGPError_FileOpFailed;
	}

	/* Note that we don't need to seek file2 here, ringPacketDiffers does */
	i = ringPacketDiffers(file2, name,
			(fAttribute?PKTBYTE_ATTRIBUTE:PKTBYTE_NAME), (PGPUInt32)-1);

	if (file2 == file1 && file1->f &&
			pgpFileSeek(file1->f, retpos, SEEK_SET) != 0) {
		ringErr(file1, name->g.pos.fpos, kPGPError_FileOpFailed);
		return kPGPError_FileOpFailed;
	}
	return i;
}

/*
 * Exported variant of namesdiffer.  This has a similar function, but
 * a very different interface - it does not assume that the name has been
 * fetched into the pktbuf.
 * Returns 1 if the two names differ, 0 if the same, < 0 on error.
 */
int
ringNamesDiffer (RingSet const *set, union RingObject *name1,
	union RingObject *name2)
{
	char const *buf1, *buf2;	/* Pointers to the names */
	PGPSize len, tlen;
	PGPUInt32 hash1, hash2;		/* HAshes of the two names */
	
	pgpAssert (OBJISNAME(name1));
	pgpAssert (OBJISNAME(name2));
	pgpAssert (pgpIsRingSetMember(set, name1));
	pgpAssert (pgpIsRingSetMember(set, name2));

	/* Quick test of lengths */
	len = name1->n.len;
	if (len != name2->n.len)
		return 1;

	/* Trivial case: both names are in memory */
	if (NAMEISCACHED(&name1->n) && NAMEISCACHED(&name2->n))
		return memcmp(name1->n.name.ptr, name2->n.name.ptr, len) != 0;

	/* First, compare hashes to see what's what */
	hash1 = NAMEISCACHED(&name1->n) 
		? ringHashBuf((const unsigned char *) name1->n.name.ptr, len)
		: name1->n.name.hash;
	hash2 = NAMEISCACHED(&name2->n) 
		? ringHashBuf((const unsigned char *) name2->n.name.ptr, len)
		: name2->n.name.hash;
	if (hash1 != hash2)
		return 1;
	/*
	 * At this point, we're 99% sure the names are the same, but
	 * we need to confirm...
	 * Load the first name.  This may go into a cache, or the pktbuf.
	 */
	buf1 = ringPoolGetName(ringSetPool(set), &name1->n, &tlen);
	if (!buf1)
		return ringSetError(set)->error;
	pgpAssert(tlen == len);
	/* If name2 is available without using the pktbuf, great. */
	if (NAMEISCACHED(&name2->n)) {
		buf2 = name2->n.name.ptr;
		return memcmp(buf1, buf2, len) != 0;
	}
	/*
	 * Otherwise, if name1 isn't in the pktbuf, we can fetch name2
	 *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -