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

📄 dbxodbc.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
	{
	RETCODE retCode;
	SWORD bufLen;
	char *keywordPtr, buffer[ 128 ];

	assert( command != NULL );
	strcpy( query, command );

	/* If it's a CREATE TABLE command, rewrite the blob and date types to
	   the appropriate values for the database backend */
	if( !strncmp( command, "CREATE TABLE", 12 ) )
		{
		char *placeholderPtr;

		if( ( placeholderPtr = strstr( query, " BLOB" ) ) != NULL )
			{
			const int nameLen = strlen( dbmsInfo->blobName );

			/* Open up a gap and replace the blob name placeholder with the
			   actual blob name */
			memmove( placeholderPtr + 1 + nameLen, placeholderPtr + 5,
					 strlen( placeholderPtr + 5 ) + 1 );
			memcpy( placeholderPtr + 1, dbmsInfo->blobName, nameLen );
			}
		if( ( placeholderPtr = strstr( query, " DATETIME" ) ) != NULL )
			{
			const int nameLen = strlen( dbmsInfo->dateTimeName );

			/* Open up a gap and replace the date name placeholder with the
			   actual date name */
			memmove( placeholderPtr + 1 + nameLen, placeholderPtr + 9,
					 strlen( placeholderPtr + 9 ) + 1 );
			memcpy( placeholderPtr + 1, dbmsInfo->dateTimeName, nameLen );
			}
		}

	/* If it's not a CREATE TABLE command with a primary key or a
	   SELECT/DELETE with wildcards used, there's nothing to do */
	if( ( strncmp( query, "CREATE TABLE", 12 ) || \
		  ( keywordPtr = strstr( query, " PRIMARY KEY" ) ) == NULL ) && \
		( ( strncmp( query, "SELECT", 6 ) && strncmp( query, "DELETE", 6 ) ) || \
		  strstr( query, " LIKE " ) == NULL ) )
		return;

	/* It's a potential problem command, check for the presence of Access or
	   SQL Server */
	retCode = pSQLGetInfo( dbmsInfo->hDbc, SQL_DBMS_NAME, buffer,
						   sizeof( buffer ), &bufLen );
	if( ( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO ) && \
		strnicmp( buffer, "Access", 6 ) && \
		strnicmp( buffer, "SQL Server", 10 ) )
		return;
	if( query[ 0 ] == 'C' )
		{
#if 0
		/* Rewrite the PRIMARY KEY qualifier as a constraint on the column.
		   We use the name 'PrimaryKey' since this is what Access uses by
		   default */
		memmove( keywordPtr + 33, keywordPtr + 12,
				 ( strlen( keywordPtr ) - 12 ) + 1 );
		memcpy( keywordPtr, "CONSTRAINT PrimaryKey PRIMARY KEY", 33 );
#else
		/* Remove the PRIMARY KEY qualifier (the constraint mechanism is too
		   awkward to handle cleanly) */
		memmove( keywordPtr, keywordPtr + 12, strlen( keywordPtr + 12 ) + 1 );
#endif /* 0 */
		}
	else
		{
		/* Unlike everything else in the known universe, Access uses * and ?
		   instead of the standard SQL wildcards so if we find a LIKE ... %
		   we rewrite the % as a * */
		if( buffer[ 0 ] == 'A' && \
			( keywordPtr = strstr( query, " LIKE " ) ) != NULL )
			{
			int i;

			/* Search up to 5 characters ahead for a wildcard and replace it
			   with the one needed by Access if we find it */
			for( i = 7; i < 11 && keywordPtr[ i ]; i++ )
				if( keywordPtr[ i ] == '%' )
					keywordPtr[ i ] = '*';
			}
		}
	}

/* Get the name of the blob and date data type for this data source */

static int getDatatypeInfo( DBMS_STATE_INFO *dbmsInfo )
	{
	RETCODE retCode;
	SDWORD length;
	SWORD bufLen;
	char buffer[ 8 ];
	long count;

	pSQLAllocStmt( dbmsInfo->hDbc, &dbmsInfo->hStmt );

	/* First we see whether the database supports long binary strings (most
	   of the newer ones which are likely to be used do) */
	retCode = pSQLGetTypeInfo( dbmsInfo->hStmt, SQL_LONGVARBINARY );
	if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
		{
		/* Get the results of the transaction.  If the database doesn't
		   support this, we'll get SQL_NO_DATA_FOUND (status 100) returned */
		retCode = pSQLFetch( dbmsInfo->hStmt );
		if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
			{
			/* Get the type name and maximum possible field length (we only
			   check the second return code since they both apply to the same
			   row) */
			pSQLGetData( dbmsInfo->hStmt, 1, SQL_C_CHAR,
						 dbmsInfo->blobName, 64, &length );
			retCode = pSQLGetData( dbmsInfo->hStmt, 3, SQL_C_LONG,
								   &count, sizeof( long ), &length );
			if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
				{
				dbmsInfo->hasBinaryBlobs = TRUE;
				dbmsInfo->blobType = SQL_LONGVARBINARY;
				}
			}
		else
			{
			/* Get the name of the long char type for this data source */
			pSQLFreeStmt( dbmsInfo->hStmt, SQL_CLOSE );
			retCode = pSQLGetTypeInfo( dbmsInfo->hStmt, SQL_LONGVARCHAR );
			if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
				{
				/* Get the results of the transaction */
				retCode = pSQLFetch( dbmsInfo->hStmt );
				if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
					{
					/* Get the type name and maximum possible field length
					   (we only check the second return code since they both
					   apply to the same row) */
					pSQLGetData( dbmsInfo->hStmt, 1, SQL_C_CHAR,
								 dbmsInfo->blobName, 64, &length );
					retCode = pSQLGetData( dbmsInfo->hStmt, 3, SQL_C_LONG,
										   &count, sizeof( long ), &length );
					dbmsInfo->blobType = SQL_LONGVARCHAR;
					}
				}
			}
		}

	/* If we couldn't get a blob type or the type is too short to use,
	   report it back as a database open failure */
	if( ( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO ) || \
		count < 4096 )
		{
		if( count >= 4096 )
			/* There was a problem, get more details */
			getErrorInfo( dbmsInfo, SQL_ERRLVL_0, CRYPT_ERROR_OPEN );
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		return( CRYPT_ERROR_OPEN );
		}

	/* Now do the same thing for the date+time data type.  This changed from
	   SQL_TIMESTAMP in ODBC 2.x to SQL_TYPE_TIMESTAMP in ODBC 3.x, since 3.x
	   will be more common we try the 3.x version first and if that fails
	   fall back to 2.x */
	pSQLFreeStmt( dbmsInfo->hStmt, SQL_CLOSE );
	retCode = pSQLGetTypeInfo( dbmsInfo->hStmt, SQL_TYPE_TIMESTAMP );
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		retCode = pSQLGetTypeInfo( dbmsInfo->hStmt, SQL_TIMESTAMP );
	if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
		{
		/* Fetch the results of the transaction and get the type name */
		retCode = pSQLFetch( dbmsInfo->hStmt );
		if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO )
			retCode = pSQLGetData( dbmsInfo->hStmt, 1, SQL_C_CHAR,
								   dbmsInfo->dateTimeName, 64, &length );
		}
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		{
		getErrorInfo( dbmsInfo, SQL_ERRLVL_0, CRYPT_ERROR_OPEN );
		pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
		return( CRYPT_ERROR_OPEN );
		}

#if 0	/* Not needed since we always supply the length */
	retCode = pSQLGetInfo( dbmsInfo->hDbc, SQL_NEED_LONG_DATA_LEN,
						   buffer, sizeof( buffer ), &bufLen );
	if( retCode != SQL_SUCCESS )
		dbmsInfo->needLongLength = TRUE;	/* Make a paranoid guess */
	else
		dbmsInfo->needLongLength = ( *buffer == 'Y' ) ? TRUE : FALSE;
#endif /* 0 */


	/* Finally, determine the escape char being used.  This is usually '\',
	   but it may have been changed for some reason */
	retCode = pSQLGetInfo( dbmsInfo->hDbc, SQL_SEARCH_PATTERN_ESCAPE,
						   buffer, sizeof( buffer ), &bufLen );
	dbmsInfo->escapeChar = ( retCode == SQL_SUCCESS ) ? buffer[ 0 ] : '\\';

	pSQLFreeStmt( dbmsInfo->hStmt, SQL_DROP );
	dbmsInfo->hStmt = NULL;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						 	Database Open/Close Routines					*
*																			*
****************************************************************************/

/* Close a previously-opened ODBC connection.  We have to have this before
   openDatabase() since it may be called by openDatabase() if the open
   process fails.  This is necessary because the complex ODBC open may
   require a fairly extensive cleanup afterwards */

static void closeDatabase( DBMS_STATE_INFO *dbmsInfo )
	{
	/* Commit the transaction (the default transaction mode for drivers which
	   support SQLSetConnectOption() is auto-commit so the SQLTransact() call
	   isn't strictly necessary, but we play it safe anyway) */
	if( dbmsInfo->needsUpdate )
		{
		pSQLTransact( dbmsInfo->hEnv, dbmsInfo->hDbc, SQL_COMMIT );
		dbmsInfo->needsUpdate = FALSE;
		}

	/* Clean up */
	pSQLDisconnect( dbmsInfo->hDbc );
	pSQLFreeConnect( dbmsInfo->hDbc );
	pSQLFreeEnv( dbmsInfo->hEnv );
	dbmsInfo->hStmt = 0;
	dbmsInfo->hDbc = 0;
	dbmsInfo->hEnv = 0;
	}

/* Open a connection to a data source using ODBC.  We don't check the return
   codes for many of the functions since the worst that can happen if they
   fail is that performance will be somewhat suboptimal.  In addition we
   don't allocate statement handles at this point since these are handled in
   various strange and peculiar ways by different ODBC drivers.  The main
   problem is that some drivers don't support mode than one hstmt per hdbc,
   some support only one active hstmt (an hstmt with results pending) per
   hdbc, and some support multiple active hstmt's per hdbc.  For this reason
   we use a strategy of allocating an hstmt, performing a transaction, and
   then immediately freeing it again afterwards */

static int openDatabase( DBMS_STATE_INFO *dbmsInfo, const char *name,
						 const char *server, const char *user,
						 const char *password, const int options,
						 int *featureFlags )
	{
	RETCODE retCode;
	SWORD userLen = ( user == NULL ) ? 0 : SQL_NTS;
	SWORD passwordLen = ( password == NULL ) ? 0 : SQL_NTS;
	int status;

	/* Make sure the driver is bound in */
	if( hODBC == NULL_HINSTANCE )
		return( CRYPT_ERROR_OPEN );

	UNUSED( server );

	/* Allocate environment and connection handles */
	pSQLAllocEnv( &dbmsInfo->hEnv );
	pSQLAllocConnect( dbmsInfo->hEnv, &dbmsInfo->hDbc );

	/* Set the access mode to readonly if we can.  The default is R/W, but
	   setting it to readonly optimises transaction management */
	if( options == CRYPT_KEYOPT_READONLY )
		pSQLSetConnectOption( dbmsInfo->hDbc, SQL_ACCESS_MODE,
							  SQL_MODE_READ_ONLY );

	/* Set the cursor type to forward-only (which should be the default).
	   Note that we're passing an SQLSetStmtOption() arg.to
	   SQLSetConnectOption() which causes all stmt's allocated for this
	   connection to have the specified behaviour */
	pSQLSetConnectOption( dbmsInfo->hDbc, SQL_CURSOR_TYPE,
						  SQL_CURSOR_FORWARD_ONLY );

	/* Turn off scanning for escape clauses in the SQL strings, which lets
	   the driver pass the string directly to the data source.  See the
	   comment for the previous call about the arg.being passed */
	pSQLSetConnectOption( dbmsInfo->hDbc, SQL_NOSCAN, SQL_NOSCAN_ON );

	/* Once everything is set up the way we want it, try to connect to a data
	   source and allocate a statement handle */
	retCode = pSQLConnect( dbmsInfo->hDbc, ( char * ) name, SQL_NTS,
						   ( char * ) user, userLen,
						   ( char * ) password, passwordLen );
	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO )
		{
		getErrorInfo( dbmsInfo, SQL_ERRLVL_0, CRYPT_ERROR_OPEN );
		pSQLFreeConnect( dbmsInfo->hDbc );
		pSQLFreeEnv( dbmsInfo->hEnv );
		return( CRYPT_ERROR_OPEN );
		}

	/* Get various driver and source-specific information which we may need
	   later on */
	status = getDatatypeInfo( dbmsInfo );
	if( cryptStatusError( status ) )
		{
		closeDatabase( dbmsInfo );
		return( status );
		}
	*featureFlags = dbmsInfo->hasBinaryBlobs ? \

⌨️ 快捷键说明

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