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

📄 pgpdecode.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if( IsPGPError( err = pgpFindOptionArgs( optionList,
						 kPGPOptionType_PassThroughKeys, FALSE,
						 "%d", &fPassKeys ) ) )
		goto error;
	if( IsPGPError( err = pgpFindOptionArgs( optionList,
						 kPGPOptionType_RecursivelyDecode, FALSE,
						 "%d", &fRecurse ) ) )
		goto error;
	*recurse = (PGPBoolean)fRecurse;

	fPassClear |= fRecurse;		/* Recurse needs passthroughclearsigned */

	if( fPassClear || fPassKeys ) {
		*fifo = pgpFifoCreate( context, &pgpByteFifoDesc );
		if (*fifo == NULL) {
			err = kPGPError_OutOfMemory;
			goto error;
		}
	}
	
	if( fPassClear ) {
		pipeHead->annotate( pipeHead, NULL, PGPANN_PASSTHROUGH_CLEARSIGN,
							&boolFlag, 1 );
	}

	if( fPassKeys ) {
		pipeHead->annotate( pipeHead, NULL, PGPANN_PASSTHROUGH_KEYS,
							&boolFlag, 1 );
	}

	return kPGPError_NoErr;

error:
	if( IsntNull( *fifo ) ) {
		pgpFifoDestroy( &pgpByteFifoDesc, *fifo );
		*fifo = NULL;
	}
	return err;
}


/* Burn a passphrase from the job state structure, if any */
	static void
pgpBurnDecodePassphrase ( PGPDecodeJob *s )
{
	if( IsntNull( s->passPhrase ) ) {
		pgpClearMemory( s->passPhrase, s->passLength );
		PGPFreeData( s->passPhrase );
		s->passPhrase = NULL;
		s->passLength = 0;
	}
}


/*********************** Subroutines for callbacks *************************/


/* Close an existing output pipeline and do appropriate cleanup */

	static PGPError
pgpCloseOutput(
	PGPDecodeJob		 *s,
	PGPPipeline			**output
	)
{
	PGPError			  err;

	if( IsntNull( *output ) ) {
		(*output)->sizeAdvise (*output, 0);
		if( IsntNull( s->outPipe ) ) {
			/* Return buffer sizes to user */
			if( IsntNull( s->outBufPtrPtr ) ) {
				/* Dynamically allocated buffer - tell user size & position */
				if( IsPGPError( err = pgpGetVariableMemOutput( s->outPipe,
								s->outBufMaxLength, s->outBufPtrPtr,
								s->outBufUsedLength ) ) )
					goto error;
			} else {
				/* Fixed size buffer - tell user actual size used */
				pgpAssert( IsntNull( s->outBufPtr ) );
				if( IsPGPError( err = pgpGetMemOutput( s->outPipe,
							s->outBufMaxLength, s->outBufUsedLength ) ) )
					goto error;
			}
			s->outPipe = NULL;
		}
		(*output)->teardown (*output);
		*output = NULL;
		if( s->pfout ) {
			pgpFileClose( s->pfout );
			s->pfout = NULL;
		}
	}
	return kPGPError_NoErr;
error:
	return err;
}


/* Close an existing buffer saving a key and do appropriate cleanup */

	static PGPError
pgpCloseKeyOutput(
	PGPDecodeJob		*s
	)
{
	PGPOption			 op;			/* Selected option from list */
	PGPByte				*bufPtr;		/* Buffer pointer for key data */
	PGPSize				 bufLength;		/* Length of key buffer */
	PGPKeySet			*keySet;		/* Keyset for key data */
	PGPKeySet			*importKeySet;	/* Keyset we are adding to for user */
	PGPError			 err;			/* Error code */
	PGPContextRef		cdkContext;

	pgpAssertAddrValid( s, PGPDecodeJob );
	cdkContext	= s->context;

	keySet = NULL;
	importKeySet = NULL;
	bufPtr = NULL;

	/* Get buffer and length where key data is */
	pgpAssert( IsntNull( s->outKey ) );
	if( IsPGPError( err = pgpGetVariableMemOutput( s->outKey,
					(PGPSize)~0, &bufPtr, &bufLength ) ) )
		goto error;

	/* Close down output portion of pipeline */
	s->outKey = NULL;
	pgpAssert( s->fPrevOutput );
	pgpAssert( IsntNull( s->prevOutput ) );
	pgpAssert( IsNull( s->outPipe ) );
	if( IsPGPError( err = pgpCloseOutput(s,  s->prevOutput ) ) )
		goto error;

	/* Translate into a keyset holding any imported key(s) */
	if( IsPGPError( err = pgpImportKeyBinary( s->context,
											  bufPtr, bufLength, &keySet ) ) )
		goto error;
	PGPFreeData( bufPtr );
	bufPtr = NULL;

	/* See if there is a keyset specified for adding keys to */
	if( IsPGPError( err = pgpSearchOptionSingle( s->optionList,
							 kPGPOptionType_ImportKeysTo, &op ) ) )
		goto error;
	if( IsOp( op ) ) {
		/* Add keys to user-specified keyset */
		if( IsPGPError( err = pgpOptionPtr( &op, (void **)&importKeySet ) ) )
			goto error;
		pgpa(pgpaPGPKeySetValid(importKeySet));
		if( !pgpKeySetIsValid(importKeySet) ) {
			pgpDebugMsg( "Error: invalid ImportKeysTo keyset" );
			err = kPGPError_BadParams;
			goto error;
		}
		if( IsPGPError( err = PGPAddKeys( keySet, importKeySet) ) )
			goto error;
		if( IsPGPError( err = PGPCommitKeyRingChanges( importKeySet ) ) )
			goto error;
		PGPFreeKeySet( keySet );
		keySet = NULL;
	} else {
		/* Else see if we should ask user what to do with keys */
		PGPUInt32 fKeyEvents;
		if( IsPGPError( err = pgpFindOptionArgs( s->optionList,
							 kPGPOptionType_SendEventIfKeyFound, FALSE,
							 "%d", &fKeyEvents ) ) )
			goto error;
		if( fKeyEvents ) {
			err = pgpEventKeyFound( s->context, &s->newOptionList,
						s->func, s->userValue, keySet );
			pgpCleanupOptionList( &s->newOptionList );
			if( IsPGPError( err ) )
				goto error;
		}
		/* User has dealt with it if he wants, now we can delete data */
		PGPFreeKeySet( keySet );
		keySet = NULL;
	}
	return kPGPError_NoErr;
error:
	if( IsntNull( bufPtr ) )
		PGPFreeData( bufPtr );
	if( IsntNull( keySet ) )
		PGPFreeKeySet( keySet );
	return err;
}	


/* 
 * Use when we first open output in passthrough mode.  We drain the
 * contents of the passthrough fifo (which holds header data and such
 * which we read before we got the begin annotation).
 */
static void
sDrainPassThroughFifo( PGPDecodeJob *s )
{
	PGPByte const *	ptr;
	PGPSize			length;
	PGPError		err;

	pgpAssert( IsntNull( s->prevStarOutput ) );
	pgpAssert( IsntNull( s->passThroughFifo ) );

	ptr = pgpFifoPeek(&pgpByteFifoDesc, s->passThroughFifo, &length);
	while (length != 0) {
		s->prevStarOutput->write( s->prevStarOutput, ptr, length, &err );
		pgpFifoSeek(&pgpByteFifoDesc, s->passThroughFifo, length);
		ptr = pgpFifoPeek(&pgpByteFifoDesc, s->passThroughFifo, &length);
	}
}


/*
 * Output state diversion.  We sometimes want to suspend output to the
 * current pipeline temporarily while we deal with a key or non-pgp data.
 * We save the current state in the "prev" class of variables, and later
 * restore them.
 */

static void
sRestoreOutputState( PGPDecodeJob *s, PGPPipeline **output )
{
	/*
	 * In order for our cleanup in pgpDecodeInternal to work, the output
	 * tail pointer from the module which calls us must always be the same.
	 * The following assertion helps test for that.  (During pgpDecodeInternal
	 * we have no access to the output tail pointer, so we will assume that
	 * the prevOutput value matches what is needed.)
	 */
	pgpAssert( s->prevOutput == output );
	*output = s->prevStarOutput;
	s->outPipe = s->prevOutPipe;
	s->pfout = s->prevPFout;
	s->prevStarOutput = NULL;
	s->prevOutPipe = NULL;
	s->prevPFout = NULL;
	s->fPrevOutput = FALSE;
}

static void
sSaveOutputState( PGPDecodeJob *s, PGPPipeline **output )
{
	pgpAssert( s->prevOutput == output );
	s->prevStarOutput = *output;
	s->prevOutPipe = s->outPipe;
	s->prevPFout = s->pfout;
	s->fPrevOutput = TRUE;
	s->outPipe = NULL;
	s->pfout = NULL;
	*output = NULL;
}





/***************** Callback functions from Aurora library *******************/

static PGPError pgpDecodeDoCommit(void *arg, PGPInt32 scope);


/*
 * The low-level Aurora library calls our analyze and commit functions
 * for each recursive level of handling of a given message segment.
 * We only want to give one of these to the user.  Accordingly we have
 * three states as far as getting segment-type information:
 *
 *	- Waiting for segment type info
 *	- Got segment type info, waiting to give to user
 * 	- Gave segment info to user, waiting for end of segment
 *
 * We give segment info to the user from the commit call, because that
 * is our opportunity to skip a section, which the user is allowed to do
 * on the analyze call.
 */
	static PGPError
pgpDecodeHandleAnnotation(
	void				*arg,
	PGPPipeline			*origin,
	PGPInt32			 type,
	PGPByte const		*string,
	PGPSize				 size
	)
{
	PGPDecodeJob		*s;				/* Parameters for callbacks */
	PGPUInt32			 passThroughNonPGP;
	PGPError			 err = kPGPError_NoErr;

	s = (PGPDecodeJob *) arg;
	(void) origin;
	(void) string;
	(void) size;

	/* Keep track of our nesting status */
	PGP_SCOPE_DEPTH_UPDATE(s->scopeLevel, type);

	/* Handle passthrough data */
	if (type == PGPANN_CLEARDATA) {
		/* Passthrough data gets buffered or handed to suspended output */
		s->passThrough = TRUE;
		if( IsntNull( s->prevStarOutput ) ) {
			s->prevStarOutput->write( s->prevStarOutput,
									  string, size, &err );
		} else {
			/* We get a few lines of header before the data starts,
			 * so we buffer that here and will drain it in
			 * NewOutput.
			 */
			pgpAssert( IsntNull( s->passThroughFifo ) );
			pgpFifoWrite(&pgpByteFifoDesc, s->passThroughFifo,
						 string, size);
		}
	} else if( type == PGPANN_LITERAL_TYPE ) {
		/* Remember type in case we want to recurse into it */
		pgpAssert (size == 1);
		s->literalType = *(PGPByte *)string;
	} else if( s->analyzeState == kAnalyzeWaiting ) {
		/* If looking for the start of a segment, figure out the type */
		switch (type) {
		case PGPANN_ARMOR_BEGIN:
			/* Just get the section offset for later callback */
			if( size == sizeof(s->sectOffset) )
				s->sectOffset = *(PGPSize *)string;
			break;
		case PGPANN_PGPKEY_BEGIN:
			s->analyzeType = kPGPAnalyze_Key;
			s->analyzeState = kAnalyzeGotType;
			s->scopeSegment = s->scopeLevel;
			break;
		case PGPANN_CIPHER_BEGIN:
			s->analyzeType = kPGPAnalyze_Encrypted;
			s->analyzeState = kAnalyzeGotType;
			s->scopeSegment = s->scopeLevel;
			break;
		case PGPANN_COMPRESSED_BEGIN:
		/* Signed may be a detached or a regular sig, need another anno */
		/*		case PGPANN_SIGNED_BEGIN: */
		case PGPANN_SIGNED_SIG:
		case PGPANN_SIGNED_SIG2:
			s->analyzeType = kPGPAnalyze_Signed;
			s->analyzeState = kAnalyzeGotType;
			s->scopeSegment = s->scopeLevel;
			break;
		case PGPANN_SIGNED_SEP:
			s->analyzeType = kPGPAnalyze_DetachedSignature;
			s->analyzeState = kAnalyzeGotType;
			s->scopeSegment = s->scopeLevel;
			break;
		case PGPANN_CLEARSIG_BEGIN:
			/*
			 * Clearsig doesn't go through binary parser, so we do some
			 * shortcuts here.  Call commit directly.  We can't currently
			 * skip clearsigned messages though.  Note commit changes
			 * analyzeState.
			 */
			s->analyzeType = kPGPAnalyze_Signed;
			s->analyzeState = kAnalyzeGotType;
			s->scopeSegment = s->scopeLevel;
			if( size == sizeof(s->sectOffset) )
				s->sectOffset = *(PGPSize *)string;
			err = pgpDecodeDoCommit(arg, type);
			if (err == PGPANN_PARSER_EATIT || err == PGPANN_PARSER_RECURSE)
				err = kPGPError_NoErr;
			break;
		case PGPANN_NONPGP_BEGIN:
			/*
			 * Non-PGP data is handled differently.  Call commit directly.
			 * (Skip not supported though.)  Note commit changes
			 * analyzeState.
			 */
			if( IsPGPError( pgpFindOptionArgs( s->optionList,
							kPGPOptionType_PassThroughIfUnrecognized, FALSE,
							"%d", &passThroughNonPGP ) ) )
				goto error;
			if( passThroughNonPGP ) {
				s->analyzeType = kPGPAnalyze_Unknown;
				s->analyzeState = kAnalyzeGotType;
				s->scopeSegment = s->scopeLevel;
				if( size == sizeof(s->sectOffset) )
					s->sectOffset = *(PGPSize *)string;
				err = pgpDecodeDoCommit(arg, type);
				if (err == PGPANN_PARSER_EATIT || err == PGPANN_PARSER_RECURSE)
					err = kPGPError_NoErr;
			}
			break;
		}
	} else if( s->analyzeState == kAnalyzeSegmentEndWait ) {
		/*
		 * Handle end of segment.
		 * Special treatment for clearsig: it goes CLEARSIG_BEGIN,
		 * CLEARSIG_END, ARMOR_BEGIN, ARMOR_END.  We skip the CLEARSIG_END
		 * so we terminate the scope at the ARMOR_END.
		 */
		if( type == PGPANN_PGPKEY_END ) {
			/* On close of PGPkey segment, deal with key data */
			/* May be nested within an encrypted segment so check here */
			if( IsPGPError( err = pgpCloseKeyOutput( s ) ) )
				goto error;
			pgpAssert( s->fPrevOutput );
			sRestoreOutputState( s, s->prevOutput );
		}
		if( s->scopeLevel < s->scopeSegment && type != PGPANN_CLEARSIG_END) {
			/* Close any open output so client can see his data */
			if( !s->fixedOutput && IsntNull( s->prevOutput ) ) {
				/* If finished with a segment, close it */
				if( IsPGPError( err = pgpCloseOutput(s,  s->prevOutput )))
					goto error;
			}
			s->passThrough = FALSE;		/* End of segment */
			err = pgpEventEndLex( s->context, &s->newOptionList,
								  s->func, s->userValue, s->sectionNumber++ );
			pgpCleanupOptionList( &s->newOptionList );
			s->analyzeState = kAnalyzeWaiting;
			if( IsPGPError( err ) )
				goto error;
			/* Handle one-section mode */
			if( s->sectionNumber == 1 ) {
				PGPUInt32 fOnlyOne;
				if( IsPGPError( err = pgpFindOptionArgs( s->optionList,
									kPGPOptionType_DecodeOnlyOne, FALSE,
									"%d", &fOnlyOne ) ) )
					goto error;
				if( fOnlyOne ) {
					err = kPGPError_Interrupted;
				}
			}

⌨️ 快捷键说明

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