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

📄 dbxodbc.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
					DBMS_FLAG_BINARYBLOBS : DBMS_FLAG_NONE;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						 	Database Access Routines						*
*																			*
****************************************************************************/

/* Perform a transaction which updates the database without returning any
   data */

static int performUpdate( DBMS_STATE_INFO *dbmsInfo, const char *command,
						  const void *boundData, const int boundDataLength,
						  const time_t boundDate,
						  const DBMS_UPDATE_TYPE updateType )
	{
	TIMESTAMP_STRUCT timestampInfo;
	UWORD paramNo = 1;
	RETCODE retCode;
	int status = CRYPT_OK;

	/* If we're aborting a transaction, roll it back, re-eanble autocommit,
	   and clean up */
	if( updateType == DBMS_UPDATE_ABORT )
		{
		pSQLTransact( dbmsInfo->hEnv, dbmsInfo->hDbc, SQL_ROLLBACK );
		pSQLSetConnectOption( dbmsInfo->hDbc, SQL_AUTOCOMMIT, 1 );
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		dbmsInfo->hStmt = NULL;
		return( CRYPT_OK );
		}

	/* If it's the start of a transaction, turn autocommit off */
	if( updateType == DBMS_UPDATE_BEGIN )
		pSQLSetConnectOption( dbmsInfo->hDbc, SQL_AUTOCOMMIT, 0 );

	/* Allocate an hstmt unless we're in the middle of a transaction */
	if( updateType != DBMS_UPDATE_CONTINUE && \
		updateType != DBMS_UPDATE_COMMIT )
		pSQLAllocStmt( dbmsInfo->hDbc, &dbmsInfo->hStmt );

	/* Bind in any necessary parameters to the hstmt.  This is unlike the
	   behaviour mentioned in the ODBC documentation, which claims that
	   SQLExecDirect() will return SQL_NEED_DATA if it finds a parameter
	   marker.  Instead, we have to bind the parameters before calling
	   SQLExecDirect() and it reads them from the bound location as required.
	   In addition an older version of the ODBC spec required that the
	   cbColDef value never exceed SQL_MAX_MESSAGE_LENGTH, however this is
	   defined to be 512 bytes which means we can't add most certs of any
	   real complexity or with keys > 1K bits, so we pass in the actual data
	   length here instead.  This works for all ODBC drivers tested */
	if( boundDate != 0 )
		{
		struct tm *timeInfo = gmtime( &boundDate );

		memset( &timestampInfo, 0, sizeof( TIMESTAMP_STRUCT ) );
		timestampInfo.year = timeInfo->tm_year + 1900;
		timestampInfo.month = timeInfo->tm_mon + 1;
		timestampInfo.day = timeInfo->tm_mday;
		timestampInfo.hour = timeInfo->tm_hour;
		timestampInfo.minute = timeInfo->tm_min;
		timestampInfo.second = timeInfo->tm_sec;
		pSQLBindParameter( dbmsInfo->hStmt, paramNo++, SQL_PARAM_INPUT,
						   SQL_C_TIMESTAMP, SQL_TIMESTAMP, 0, 0,
						   &timestampInfo, 0, NULL );
		}
	if( boundData != NULL )
		{
		dbmsInfo->cbBlobLength = SQL_LEN_DATA_AT_EXEC( boundDataLength );
		pSQLBindParameter( dbmsInfo->hStmt, paramNo++, SQL_PARAM_INPUT,
						   SQL_C_BINARY, dbmsInfo->blobType, boundDataLength, 0,
						   ( PTR ) 6, 0, &dbmsInfo->cbBlobLength );
		}

	/* Execute the command/hStmt as appropriate */
	if( command == NULL )
		retCode = pSQLExecute( dbmsInfo->hStmt );
	else
		{
		char query[ MAX_SQL_QUERY_SIZE ];

		convertQuery( dbmsInfo, query, command );
		retCode = pSQLExecDirect( dbmsInfo->hStmt, query, SQL_NTS );
		}
	if( retCode == SQL_NEED_DATA )
		{
		PTR pToken;

		/* Add the key data and perform a dummy SQLParamData() call to tell
		   the ODBC driver that we've finished with the operation */
		pSQLParamData( dbmsInfo->hStmt, &pToken );
		retCode = pSQLPutData( dbmsInfo->hStmt, ( PTR ) boundData,
							   boundDataLength );
		if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
			retCode = pSQLParamData( dbmsInfo->hStmt, &pToken );
		}
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		{
		/* If we hit an error at this point we can only exit if we're not
		   finishing a transaction.  If we are, the commit turns into an
		   abort further down */
		status = getErrorInfo( dbmsInfo, SQL_ERRLVL_2, CRYPT_ERROR_WRITE );
		if( updateType != DBMS_UPDATE_COMMIT )
			return( status );
		}
	else
		/* If we're performing a delete, the operation will succeed even
		   though nothing was found to delete so we make sure we actually
		   changed something */
		if( command != NULL && !strnicmp( command, "DELETE", 6 ) )
			{
			SDWORD rowCount;

			pSQLRowCount( dbmsInfo->hStmt, &rowCount );
			if( rowCount <= 0 )
				status = CRYPT_ERROR_NOTFOUND;
			}

	/* If it's the end of a transaction, commit the transaction and turn
	   autocommit on again */
	if( updateType == DBMS_UPDATE_COMMIT )
		{
		RETCODE retCode;

		/* If we've had a failure before this point, abort, otherwise
		   commit */
		retCode = pSQLTransact( dbmsInfo->hEnv, dbmsInfo->hDbc,	/* VC++ braindamage */
						( UWORD ) ( cryptStatusError( status ) ? \
									SQL_ROLLBACK : SQL_COMMIT ) );
		pSQLSetConnectOption( dbmsInfo->hDbc, SQL_AUTOCOMMIT, 1 );
		if( cryptStatusOK( status ) && \
			( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO ) )
			status = getErrorInfo( dbmsInfo, SQL_ERRLVL_2, CRYPT_ERROR_WRITE );
		}

	/* Clean up, unless we're in the middle of a transaction */
	if( updateType != DBMS_UPDATE_BEGIN && \
		updateType != DBMS_UPDATE_CONTINUE )
		{
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		dbmsInfo->hStmt = NULL;
		}

	return( status );
	}

/* Perform a transaction which returns information */

static RETCODE fetchData( DBMS_STATE_INFO *dbmsInfo, char *data,
						  int *dataLength, const int maxLength,
						  const DBMS_QUERY_TYPE queryType )
	{
	const SWORD dataType = ( dbmsInfo->hasBinaryBlobs ) ? \
						   SQL_C_BINARY : SQL_C_CHAR;
	RETCODE retCode;
	SDWORD length;

	/* Get the results of the transaction */
	retCode = pSQLFetch( dbmsInfo->hStmt );
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		return( retCode );

	/* If we're just doing a presence check, we don't bother fetching data */
	if( queryType == DBMS_QUERY_CHECK )
		return( SQL_SUCCESS );

	/* Read the data */
	retCode = pSQLGetData( dbmsInfo->hStmt, 1, dataType, data,
						   maxLength, &length );
	*dataLength = ( int ) length;

	return( retCode );
	}

static int performQuery( DBMS_STATE_INFO *dbmsInfo, const char *command,
						 char *data, int *dataLength, time_t boundDate,
						 const DBMS_QUERY_TYPE queryType )
	{
	/* We have to explicitly set the maximum length indicator because some
	   sources will helpfully zero-pad the data to the maximum indicated size,
	   which is smaller for the non-ASCII-encoded buffer */
	const int maxLength = dbmsInfo->hasBinaryBlobs ? \
						  MAX_CERT_SIZE : MAX_QUERY_RESULT_SIZE;
	const BOOLEAN isQuery = ( data == NULL ) ? TRUE : FALSE;
	char query[ MAX_SQL_QUERY_SIZE ];
	TIMESTAMP_STRUCT timestampInfo;
	RETCODE retCode;

	/* Clear return value */
	*dataLength = 0;

	/* If we're cancelling a continuing query, clean up and exit */
	if( queryType == DBMS_QUERY_CANCEL )
		{
		/* Cancel any outstanding requests and free the statement handle.
		   The cancel isn't strictly necessary, but it means the
		   SQLFreeStmt() doesn't return an error code to tell is something
		   was still happening */
		pSQLCancel( dbmsInfo->hStmt );
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		dbmsInfo->hStmt = NULL;
		return( CRYPT_OK );
		}

	/* If we're in the middle of a continuing query, fetch the next set of
	   results */
	if( queryType == DBMS_QUERY_CONTINUE )
		{
		retCode = fetchData( dbmsInfo, data, dataLength, maxLength,
							 DBMS_QUERY_CONTINUE );
		if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
			{
			int status;

			status = getErrorInfo( dbmsInfo, SQL_ERRLVL_2, CRYPT_ERROR_READ );
			pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
			dbmsInfo->hStmt = NULL;

			/* If we ran out of results we explicitly signal to the caller
			   that the query has completed */
			return( ( status == CRYPT_ERROR_NOTFOUND ) ? \
					CRYPT_ERROR_COMPLETE : CRYPT_ERROR_READ );
			}

		return( CRYPT_OK );
		}

	/* Allocate an hstmt and set the cursor concurrency to read-only */
	pSQLAllocStmt( dbmsInfo->hDbc, &dbmsInfo->hStmt );
	if( queryType != DBMS_QUERY_START )
		/* Only return a maximum of a single row in response to a point
		   query.  This is a simple optimisation to ensure the database
		   doesn't start sucking across huge amounts of data when it's
		   not necessary */
		pSQLSetConnectOption( dbmsInfo->hStmt, SQL_MAX_ROWS, 1 );
	pSQLSetStmtOption( dbmsInfo->hStmt, SQL_CONCURRENCY,
					   SQL_CONCUR_READ_ONLY );

	/* Bind in any necessary parameters to the hstmt */
	if( boundDate != 0 )
		{
		struct tm *timeInfo = gmtime( &boundDate );

		memset( &timestampInfo, 0, sizeof( TIMESTAMP_STRUCT ) );
		timestampInfo.year = timeInfo->tm_year + 1900;
		timestampInfo.month = timeInfo->tm_mon + 1;
		timestampInfo.day = timeInfo->tm_mday;
		timestampInfo.hour = timeInfo->tm_hour;
		timestampInfo.minute = timeInfo->tm_min;
		timestampInfo.second = timeInfo->tm_sec;
		pSQLBindParameter( dbmsInfo->hStmt, 1, SQL_PARAM_INPUT,
						   SQL_C_TIMESTAMP, SQL_TIMESTAMP, 0, 0,
						   &timestampInfo, 0, NULL );
		}

	/* Execute the SQL statement */
	convertQuery( dbmsInfo, query, command );
	retCode = pSQLExecDirect( dbmsInfo->hStmt, query, SQL_NTS );
	if( queryType != DBMS_QUERY_START && \
		( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO ) )
		retCode = fetchData( dbmsInfo, data, dataLength, maxLength,
							 queryType );

	/* Handle any errors */
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		{
		int status;

		status = getErrorInfo( dbmsInfo, SQL_ERRLVL_2, CRYPT_ERROR_READ );
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		dbmsInfo->hStmt = NULL;
		return( status );
		}
	if( queryType != DBMS_QUERY_START )
		{
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		dbmsInfo->hStmt = NULL;
		}

	return( CRYPT_OK );
	}

/* Fetch extended error information from the database state info */

static void performErrorQuery( DBMS_STATE_INFO *dbmsInfo, int *errorCode,
							   char *errorMessage )
	{
	*errorCode = dbmsInfo->errorCode;
	strcpy( errorMessage, dbmsInfo->errorMessage );
	}

/* Pull in the shared database RPC routines, renaming the generic dispatch
   function to the ODBC-specific one which is called directly by the
   marshalling code */

#define processCommand( stateInfo, buffer ) \
		odbcProcessCommand( stateInfo, buffer )

#include "dbx_rpc.c"

⌨️ 快捷键说明

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