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

📄 dbxodbc.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*						 cryptlib ODBC Mapping Routines						*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <stdio.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "keyset.h"
  #include "dbxdbx.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "keyset.h"
  #include "dbxdbx.h"
#else
  #include "crypt.h"
  #include "keysets/keyset.h"
  #include "keyset/dbxdbx.h"
#endif /* Compiler-specific includes */

/* SQLError() returns error information at various levels and is rather
   unstable in its handling of input parameters, for example with some Win16 
   drivers if you pass it a valid hstmt then it may GPF after some calls so 
   you need to force a NULL hstmt.  The following values define the levels 
   of handle that we pass in in order for SQLError() to work as advertised */

#define SQL_ERRLVL_0	0
#define SQL_ERRLVL_1	1
#define SQL_ERRLVL_2	2

#ifdef USE_ODBC

/****************************************************************************
*																			*
*						 		Init/Shutdown Routines						*
*																			*
****************************************************************************/

#ifdef DYNAMIC_LOAD

/* Global function pointers.  These are necessary because the functions need
   to be dynamically linked since not all systems contain the necessary
   DLL's.  Explicitly linking to them will make cryptlib unloadable on some
   systems.

   MSDN updates from late 2000 defined SQLROWCOUNT themselves (which could be
   fixed by undefining it), however after late 2002 the value was typedef'd,
   requring all sorts of extra trickery to handle the different cases.  
   Because of this this particular function is typedef'd with a _FN suffix 
   to reduce problems */

#define NULL_HINSTANCE	( HINSTANCE ) NULL

static HINSTANCE hODBC = NULL_HINSTANCE;

typedef RETCODE ( SQL_API *SQLALLOCENV )( HENV FAR *phenv );
typedef RETCODE ( SQL_API *SQLALLOCCONNECT )( HENV henv, HDBC FAR *phdbc );
typedef RETCODE ( SQL_API *SQLALLOCSTMT )( HDBC hdbc, HSTMT FAR *phstmt );
typedef RETCODE ( SQL_API *SQLBINDPARAMETER )( HSTMT hstmt, UWORD ipar,
				  SWORD fParamType, SWORD fCType, SWORD fSqlType,
				  UDWORD cbColDef, SWORD ibScale, PTR rgbValue,
				  SDWORD cbValueMax, SDWORD FAR *pcbValue );
typedef RETCODE ( SQL_API *SQLCANCEL )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLCONNECT )( HDBC hdbc, UCHAR FAR *szDSN,
				  SWORD cdDSN, UCHAR FAR *szUID, SWORD cbUID,
				  UCHAR FAR *szAuthStr, SWORD cbAuthStr );
typedef RETCODE ( SQL_API *SQLDISCONNECT )( HDBC hdbc );
typedef RETCODE ( SQL_API *SQLERROR )( HENV henv, HDBC hdbc, HSTMT hstmt,
				  UCHAR FAR *szSqlState, SDWORD FAR *pfNativeError,
				  UCHAR FAR *szErrorMsg, SWORD cbErrorMsgMax,
				  SWORD FAR *pcbErrorMsg );
typedef RETCODE ( SQL_API *SQLEXECDIRECT )( HSTMT hstmt, UCHAR FAR *szSqlStr,
				  SDWORD cbSqlStr );
typedef RETCODE ( SQL_API *SQLEXECUTE )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLFETCH )( HSTMT hstmt );
typedef RETCODE ( SQL_API *SQLFREECONNECT )( HDBC hdbc );
typedef RETCODE ( SQL_API *SQLFREEENV )( HENV henv );
typedef RETCODE ( SQL_API *SQLFREESTMT )( HSTMT hstmt, UWORD fOption );
typedef RETCODE ( SQL_API *SQLGETDATA )( HSTMT hstmt, UWORD icol,
				  SWORD fCType, PTR rgbValue, SDWORD cbValueMax,
				  SDWORD FAR *pcbValue );
typedef RETCODE ( SQL_API *SQLGETINFO )( HDBC hdbc, UWORD fInfoType,
				  PTR rgbInfoValue, SWORD cbInfoValueMax,
				  SWORD FAR *pcbInfoValue );
typedef RETCODE ( SQL_API *SQLGETTYPEINFO )( HSTMT hstmt, SWORD fSqlType );
typedef RETCODE ( SQL_API *SQLPARAMDATA )( HSTMT hstmt, PTR FAR *prgbValue );
typedef RETCODE ( SQL_API *SQLPREPARE )( HSTMT hstmt, UCHAR FAR *szSqlStr,
				  SDWORD cbSqlStr );
typedef RETCODE ( SQL_API *SQLPUTDATA )( HSTMT hstmt, PTR rgbValue,
				  SDWORD cbValue );
typedef RETCODE ( SQL_API *SQLROWCOUNT_FN )( HSTMT hstmt, SDWORD *cbRowCount );
typedef RETCODE ( SQL_API *SQLSETCONNECTOPTION )( HDBC hdbc, UWORD fOption,
				  UDWORD vParam );
typedef RETCODE ( SQL_API *SQLSETSTMTOPTION )( HSTMT hstmt, UWORD fOption,
				  UDWORD vParam );
typedef RETCODE ( SQL_API *SQLTRANSACT )( HENV henv, HDBC hdbc, UWORD fType );
static SQLALLOCCONNECT pSQLAllocConnect = NULL;
static SQLALLOCENV pSQLAllocEnv = NULL;
static SQLALLOCSTMT pSQLAllocStmt = NULL;
static SQLBINDPARAMETER pSQLBindParameter = NULL;
static SQLCANCEL pSQLCancel = NULL;
static SQLCONNECT pSQLConnect = NULL;
static SQLDISCONNECT pSQLDisconnect = NULL;
static SQLERROR pSQLError = NULL;
static SQLEXECDIRECT pSQLExecDirect = NULL;
static SQLEXECUTE pSQLExecute = NULL;
static SQLFETCH pSQLFetch = NULL;
static SQLFREECONNECT pSQLFreeConnect = NULL;
static SQLFREEENV pSQLFreeEnv = NULL;
static SQLFREESTMT pSQLFreeStmt = NULL;
static SQLGETDATA pSQLGetData = NULL;
static SQLGETINFO pSQLGetInfo = NULL;
static SQLGETTYPEINFO pSQLGetTypeInfo = NULL;
static SQLPARAMDATA pSQLParamData = NULL;
static SQLPREPARE pSQLPrepare = NULL;
static SQLPUTDATA pSQLPutData = NULL;
static SQLROWCOUNT_FN pSQLRowCount = NULL;
static SQLSETCONNECTOPTION pSQLSetConnectOption = NULL;
static SQLSETSTMTOPTION pSQLSetStmtOption = NULL;
static SQLTRANSACT pSQLTransact = NULL;

/* The use of dynamically bound function pointers vs statically linked
   functions requires a bit of sleight of hand since we can't give the
   pointers the same names as prototyped functions.  To get around this we
   redefine the actual function names to the names of the pointers */

#define SQLAllocConnect			pSQLAllocConnect
#define SQLAllocEnv				pSQLAllocEnv
#define SQLAllocStmt			pSQLAllocStmt
#define SQLBindParameter		pSQLBindParameter
#define SQLCancel				pSQLCancel
#define SQLConnect				pSQLConnect
#define SQLDisconnect			pSQLDisconnect
#define SQLError				pSQLError
#define SQLExecDirect			pSQLExecDirect
#define SQLExecute				pSQLExecute
#define SQLFetch				pSQLFetch
#define SQLFreeConnect			pSQLFreeConnect
#define SQLFreeEnv				pSQLFreeEnv
#define SQLFreeStmt				pSQLFreeStmt
#define SQLGetData				pSQLGetData
#define SQLGetInfo				pSQLGetInfo
#define SQLGetTypeInfo			pSQLGetTypeInfo
#define SQLParamData			pSQLParamData
#define SQLPrepare				pSQLPrepare
#define SQLPutData				pSQLPutData
#define SQLRowCount				pSQLRowCount
#define SQLSetConnectOption		pSQLSetConnectOption
#define SQLSetStmtOption		pSQLSetStmtOption
#define SQLTransact				pSQLTransact

/* Depending on whether we're running under Win16 or Win32 we load the ODBC
   driver under a different name */

#ifdef __WIN16__
  #define ODBC_LIBNAME	"ODBC.DLL"
#else
  #define ODBC_LIBNAME	"ODBC32.DLL"
#endif /* __WIN16__ */

/* Dynamically load and unload any necessary DBMS libraries */

int dbxInitODBC( void )
	{
#ifdef __WIN16__
	UINT errorMode;
#endif /* __WIN16__ */

	/* If the ODBC module is already linked in, don't do anything */
	if( hODBC != NULL_HINSTANCE )
		return( CRYPT_OK );

	/* Obtain a handle to the module containing the ODBC functions */
#ifdef __WIN16__
	errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
	hODBC = LoadLibrary( ODBC_LIBNAME );
	SetErrorMode( errorMode );
	if( hODBC < HINSTANCE_ERROR )
		{
		hODBC = NULL_HINSTANCE;
		return( CRYPT_ERROR );
		}
#else
	if( ( hODBC = LoadLibrary( ODBC_LIBNAME ) ) == NULL_HINSTANCE )
		return( CRYPT_ERROR );
#endif /* __WIN32__ */

	/* Now get pointers to the functions */
	pSQLAllocConnect = ( SQLALLOCCONNECT ) GetProcAddress( hODBC, "SQLAllocConnect" );
	pSQLAllocEnv = ( SQLALLOCENV ) GetProcAddress( hODBC, "SQLAllocEnv" );
	pSQLAllocStmt = ( SQLALLOCSTMT ) GetProcAddress( hODBC, "SQLAllocStmt" );
	pSQLBindParameter = ( SQLBINDPARAMETER ) GetProcAddress( hODBC, "SQLBindParameter" );
	pSQLCancel = ( SQLCANCEL ) GetProcAddress( hODBC, "SQLCancel" );
	pSQLConnect = ( SQLCONNECT ) GetProcAddress( hODBC, "SQLConnect" );
	pSQLDisconnect = ( SQLDISCONNECT ) GetProcAddress( hODBC, "SQLDisconnect" );
	pSQLError = ( SQLERROR ) GetProcAddress( hODBC, "SQLError" );
	pSQLExecDirect = ( SQLEXECDIRECT ) GetProcAddress( hODBC, "SQLExecDirect" );
	pSQLExecute = ( SQLEXECUTE ) GetProcAddress( hODBC, "SQLExecute" );
	pSQLFetch = ( SQLFETCH ) GetProcAddress( hODBC, "SQLFetch" );
	pSQLFreeConnect = ( SQLFREECONNECT ) GetProcAddress( hODBC, "SQLFreeConnect" );
	pSQLFreeEnv = ( SQLFREEENV ) GetProcAddress( hODBC, "SQLFreeEnv" );
	pSQLFreeStmt = ( SQLFREESTMT ) GetProcAddress( hODBC, "SQLFreeStmt" );
	pSQLGetData = ( SQLGETDATA ) GetProcAddress( hODBC, "SQLGetData" );
	pSQLGetInfo = ( SQLGETINFO ) GetProcAddress( hODBC, "SQLGetInfo" );
	pSQLGetTypeInfo = ( SQLGETTYPEINFO ) GetProcAddress( hODBC, "SQLGetTypeInfo" );
	pSQLParamData = ( SQLPARAMDATA ) GetProcAddress( hODBC, "SQLParamData" );
	pSQLPrepare = ( SQLPREPARE ) GetProcAddress( hODBC, "SQLPrepare" );
	pSQLPutData = ( SQLPUTDATA ) GetProcAddress( hODBC, "SQLPutData" );
	pSQLRowCount = ( SQLROWCOUNT_FN ) GetProcAddress( hODBC, "SQLRowCount" );
	pSQLSetConnectOption = ( SQLSETCONNECTOPTION ) GetProcAddress( hODBC, "SQLSetConnectOption" );
	pSQLSetStmtOption = ( SQLSETSTMTOPTION ) GetProcAddress( hODBC, "SQLSetStmtOption" );
	pSQLTransact = ( SQLTRANSACT ) GetProcAddress( hODBC, "SQLTransact" );

	/* Make sure that we got valid pointers for every ODBC function */
	if( pSQLAllocConnect == NULL || pSQLAllocEnv == NULL ||
		pSQLAllocStmt == NULL || pSQLBindParameter == NULL ||
		pSQLCancel == NULL || pSQLConnect == NULL ||
		pSQLDisconnect == NULL || pSQLError == NULL ||
		pSQLExecDirect == NULL || pSQLExecute == NULL ||
		pSQLFetch == NULL || pSQLFreeConnect == NULL ||
		pSQLFreeEnv == NULL || pSQLFreeStmt == NULL ||
		pSQLGetData == NULL || pSQLGetInfo == NULL ||
		pSQLGetTypeInfo == NULL || pSQLParamData == NULL ||
		pSQLPrepare == NULL || pSQLPutData == NULL ||
		pSQLSetConnectOption == NULL || pSQLSetStmtOption == NULL ||
		pSQLTransact == NULL )
		{
		/* Free the library reference and reset the handle */
		FreeLibrary( hODBC );
		hODBC = NULL_HINSTANCE;
		return( CRYPT_ERROR );
		}

	return( CRYPT_OK );
	}

void dbxEndODBC( void )
	{
	if( hODBC != NULL_HINSTANCE )
		FreeLibrary( hODBC );
	hODBC = NULL_HINSTANCE;
	}
#else

int dbxInitODBC( void )
	{
	return( CRYPT_OK );
	}

void dbxEndODBC( void )
	{
	}
#endif /* DYNAMIC_LOAD */

/****************************************************************************
*																			*
*						 		Utility Routines							*
*																			*
****************************************************************************/

/* Get information on an ODBC error */

static int getErrorInfo( DBMS_STATE_INFO *dbmsInfo, const int errorLevel,
						 const int defaultStatus )
	{
	HDBC hdbc = ( errorLevel < 1 ) ? SQL_NULL_HDBC : dbmsInfo->hDbc;
	HDBC hstmt = ( errorLevel < 2 ) ? SQL_NULL_HSTMT : dbmsInfo->hStmt;
	char altErrorMessage[ MAX_ERRMSG_SIZE ];
	char szSqlState[ SQL_SQLSTATE_SIZE ], szAltSqlState[ SQL_SQLSTATE_SIZE ];
	SDWORD dwNativeError = 0, dwAltNativeError = 0;
	SWORD dummy;
	RETCODE retCode;

	/* Get the initial ODBC error info.  We pre-set the native error codes
	   to set because they sometimes aren't set by SQLError() */
	retCode = SQLError( dbmsInfo->hEnv, hdbc, hstmt, szSqlState,
						&dwNativeError, dbmsInfo->errorMessage,
						MAX_ERRMSG_SIZE - 1, &dummy );
	dbmsInfo->errorCode = ( int ) dwNativeError;	/* Usually 0 */

	/* Work around a bug in ODBC 2.0 drivers (still present on older NT 4
	   machines) in which the primary error is some bizarre nonsense value
	   and the actual error is present at the second level */
	retCode = SQLError( dbmsInfo->hEnv, hdbc, hstmt, szAltSqlState,
						&dwAltNativeError, altErrorMessage,
						MAX_ERRMSG_SIZE - 1, &dummy );
	if( !strncmp( szSqlState, "01004", 5 ) )
		{
		memcpy( szSqlState, szAltSqlState, SQL_SQLSTATE_SIZE );
		strcpy( dbmsInfo->errorMessage, altErrorMessage );
		}

	/* Some of the information returned by SQLError() is pretty odd.  It
	   usually returns an ANSI SQL2 error state in SQLSTATE, but also returns
	   a native error code in NativeError.  However the NativeError codes
	   aren't documented anywhere, so we rely on SQLSTATE having a useful
	   value.  	We can also get SQL_NO_DATA_FOUND with SQLSTATE set to
	   "00000" and the error message string empty */
	if( !strncmp( szSqlState, "S0002", 5 ) ||	/* ODBC 2.x */
		!strncmp( szSqlState, "42S02", 5 ) ||	/* ODBC 3.x */
		( !strncmp( szSqlState, "00000", 5 ) && retCode == SQL_NO_DATA_FOUND ) )
		{
		/* Make sure that the caller gets a sensible error message if they
		   try to examine the extended error information */
		if( !*dbmsInfo->errorMessage )
			strcpy( dbmsInfo->errorMessage, "No data found." );
		return( CRYPT_ERROR_NOTFOUND );
		}

	/* When we're trying to create a new keyset, there may already be one
	   present giving an S0001 (table already exists) or S0011 (index
	   already exists) error .  We could check for the table by doing a
	   dummy read, but it's easier to just try the update anyway and convert
	   the error code to the correct value here if there's a problem */
	if( !strncmp( szSqlState, "S0001", 5 ) ||
		!strncmp( szSqlState, "S0011", 5 ) ||	/* ODBC 2.x */
		!strncmp( szSqlState, "42S01", 5 ) ||
		!strncmp( szSqlState, "42S11", 5 ) )	/* ODBX 3.x */
		return( CRYPT_ERROR_DUPLICATE );

	/* This one is a bit odd: An integrity constraint violation occurred,
	   which means (among other things) that an attempt was made to write a
	   duplicate value to a column constrained to contain unique values.  It
	   can also include things like writing a NULL value to a column
	   constrained to be NOT NULL, but this wouldn't normally happen so we
	   can convert this one to a duplicate data error */
	if( !strncmp( szSqlState, "23000", 5 ) )
		return( CRYPT_ERROR_DUPLICATE );

	return( defaultStatus );
	}

⌨️ 快捷键说明

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