1 /****************************************************************************
2 *																			*
3 *						 cryptlib ODBC Mapping Routines						*
4 *						Copyright Peter Gutmann 1996-2012					*
5 *																			*
6 ****************************************************************************/
7 
8 #include <stdio.h>		/* For sprintf() */
9 #if defined( INC_ALL )
10   #include "crypt.h"
11   #include "dbms.h"
12   #include "keyset.h"
13 #else
14   #include "crypt.h"
15   #include "keyset/dbms.h"
16   #include "keyset/keyset.h"
17 #endif /* Compiler-specific includes */
18 
19 /* ODBC functions can return either SQL_SUCCESS or SQL_SUCCESS_WITH_INFO to
20    indicate successful completion, to make them easier to work with we use
21    a general status-check macro along the lines of cryptStatusOK() */
22 
23 #define sqlStatusOK( status ) \
24 		( ( status ) == SQL_SUCCESS || ( status ) == SQL_SUCCESS_WITH_INFO )
25 
26 /* DBMS back-ends that require special handling */
27 
28 enum { DBMS_NONE, DBMS_ACCESS, DBMS_INTERBASE, DBMS_MYSQL, DBMS_POSTGRES };
29 
30 /* The level at which we want SQLDiagRec() to return error information to
31    us */
32 
33 typedef enum { SQL_ERRLVL_NONE, SQL_ERRLVL_STMT, SQL_ERRLVL_DBC,
34 			   SQL_ERRLVL_ENV, SQL_ERRLVL_LAST } SQL_ERRLVL_TYPE;
35 
36 /* When rewriting an SQL query we have to provide a slightly larger buffer
37    to allow for possible expansion of some SQL strings */
38 
39 #define SQL_QUERY_BUFSIZE	( MAX_SQL_QUERY_SIZE + 64 )
40 
41 /* Some ODBC functions take either pointers or small integer values cast to
42    pointers to indicate certain magic values.  This causes problems in
43    64-bit environments because the LLP64 model means that pointers are 64
44    bits while ints and longs are 32 bits.  To deal with this we define the
45    following data-conversion macros for 32- and 64-bit environments */
46 
47 #ifdef __WIN64__
48   #define VALUE_TO_PTR	ULongToPtr
49 #else
50   #define VALUE_TO_PTR	( SQLPOINTER )
51 #endif /* 32- vs. 64-bit environment */
52 
53 #ifdef USE_ODBC
54 
55 /* When processing bound data we need to store the state information used by
56    SQLBindParameter() until the SQL operation completes.  The following
57    structure provides the necessary state storage */
58 
59 typedef struct {
60 	SQLINTEGER lengthStorage[ BOUND_DATA_MAXITEMS + 8 ];
61 	SQL_TIMESTAMP_STRUCT timestampStorage;
62 	} BOUND_DATA_STATE;
63 
64 /****************************************************************************
65 *																			*
66 *						 		Init/Shutdown Routines						*
67 *																			*
68 ****************************************************************************/
69 
70 #ifdef DYNAMIC_LOAD
71 
72 /* Global function pointers.  These are necessary because the functions need
73    to be dynamically linked since not all systems contain the necessary
74    shared libraries.  Explicitly linking to them will make cryptlib
75    unloadable on some systems.
76 
77    MSDN updates from late 2000 defined SQLROWCOUNT themselves (which could be
78    fixed by undefining it), however after late 2002 the value was typedef'd,
79    requring all sorts of extra trickery to handle the different cases.
80    Because of this issue, this particular function is typedef'd with a _FN
81    suffix.
82 
83    Several of the ODBC functions allow such a mess of parameters, with
84    options for pointers to be cast to integers indexing a table of data
85    values hidden under someone's bed and other peculiarities, that several
86    of the following markups are only approximations for the way the
87    functions are used here.  If markups are absent entirely (e.g. for the
88    SQLSetXXXAttr() functions) it's because the polymorphism of parameters
89    doesn't allow any coherent annotation to be given */
90 
91 static INSTANCE_HANDLE hODBC = NULL_INSTANCE;
92 
93 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLALLOCHANDLE ) \
94 					( SQLSMALLINT HandleType, IN_OPT SQLHANDLE InputHandle,
95 					OUT_PTR SQLHANDLE *OutputHandlePtr );
96 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLBINDPARAMETER ) \
97 					( IN SQLHSTMT StatementHandle,
98 					SQLUSMALLINT ParameterNumber, SQLSMALLINT InputOutputType,
99 					SQLSMALLINT ValueType, SQLSMALLINT ParameterType,
100 					SQLUINTEGER ColumnSize, SQLSMALLINT DecimalDigits,
101 					IN_BUFFER_OPT( BufferLength ) SQLPOINTER ParameterValuePtr,
102 					SQLINTEGER BufferLength,
103 					INOUT_OPT SQLINTEGER *StrLen_or_IndPtr );
104 typedef SQLRETURN ( SQL_API *SQLCLOSECURSOR )( IN SQLHSTMT StatementHandle );
105 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLCONNECT ) \
106 					( IN SQLHDBC ConnectionHandle,
107 					IN_BUFFER( NameLength1 ) SQLCHAR *ServerName,
108 					SQLSMALLINT NameLength1,
109 					IN_BUFFER( NameLength2 ) SQLCHAR *UserName,
110 					SQLSMALLINT NameLength2,
111 					IN_BUFFER( NameLength3 ) SQLCHAR *Authentication,
112 					SQLSMALLINT NameLength3 );
113 typedef SQLRETURN ( SQL_API *SQLDISCONNECT )( IN SQLHDBC ConnectionHandle );
114 typedef SQLRETURN ( SQL_API *SQLENDTRAN )( SQLSMALLINT HandleType,
115 					IN SQLHANDLE Handle, SQLSMALLINT CompletionType );
116 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLEXECDIRECT ) \
117 					( SQLHSTMT StatementHandle,
118 					IN_BUFFER( TextLength ) SQLCHAR *StatementText,
119 					SQLINTEGER TextLength );
120 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLEXECUTE ) \
121 					( IN SQLHSTMT StatementHandle );
122 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLFETCH ) \
123 					( IN SQLHSTMT StatementHandle );
124 typedef SQLRETURN ( SQL_API *SQLFREEHANDLE )( SQLSMALLINT HandleType,
125 					IN SQLHANDLE Handle );
126 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETDATA ) \
127 					( SQLHSTMT StatementHandle, SQLUSMALLINT ColumnNumber,
128 					SQLSMALLINT TargetType,
129 					OUT_BUFFER( BufferLength, *StrLen_or_IndPtr ) \
130 						SQLPOINTER TargetValuePtr,
131 					SQLINTEGER BufferLength, SQLINTEGER *StrLen_or_IndPtr );
132 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETDIAGREC ) \
133 					( SQLSMALLINT HandleType,
134 					IN SQLHANDLE Handle, SQLSMALLINT RecNumber,
135 					OUT_BUFFER_FIXED( SQL_SQLSTATE_SIZE ) SQLCHAR *Sqlstate,
136 					OUT SQLINTEGER *NativeErrorPtr,
137 					OUT_BUFFER( BufferLength, *TextLengthPtr ) \
138 						SQLCHAR *MessageText,
139 					SQLSMALLINT BufferLength, SQLSMALLINT *TextLengthPtr );
140 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETINFO ) \
141 					( IN SQLHDBC ConnectionHandle,
142 					SQLUSMALLINT InfoType,
143 					OUT_BUFFER( BufferLength, *StringLengthPtr ) \
144 						SQLPOINTER InfoValuePtr,
145 					SQLSMALLINT BufferLength, SQLSMALLINT *StringLengthPtr );
146 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETSTMTATTR ) \
147 					( IN SQLHSTMT StatementHandle,
148 					SQLINTEGER Attribute, OUT SQLPOINTER ValuePtr,
149 					SQLINTEGER BufferLength,
150 					STDC_UNUSED SQLINTEGER *StringLengthPtr );
151 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLGETTYPEINFO ) \
152 					( IN SQLHSTMT StatementHandle,
153 					SQLSMALLINT DataType );
154 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLPREPARE ) \
155 					( IN SQLHSTMT StatementHandle,
156 					IN_BUFFER( TextLength ) SQLCHAR *StatementText,
157 					SQLINTEGER TextLength );
158 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLROWCOUNT_FN ) \
159 					( IN SQLHSTMT StatementHandle,
160 					OUT SQLINTEGER *RowCountPtr );
161 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETCONNECTATTR ) \
162 					( IN SQLHDBC ConnectionHandle,
163 					SQLINTEGER Attribute, SQLPOINTER ValuePtr,
164 					SQLINTEGER StringLength );
165 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETENVATTR ) \
166 					( IN SQLHENV EnvironmentHandle,
167 					SQLINTEGER Attribute, SQLPOINTER ValuePtr,
168 					SQLINTEGER StringLength );
169 typedef CHECK_RETVAL SQLRETURN ( SQL_API *SQLSETSTMTATTR ) \
170 					( IN SQLHSTMT StatementHandle,
171 					SQLINTEGER Attribute, SQLPOINTER ValuePtr,
172 					SQLINTEGER StringLength );
173 
174 static SQLALLOCHANDLE pSQLAllocHandle = NULL;
175 static SQLBINDPARAMETER pSQLBindParameter = NULL;
176 static SQLCLOSECURSOR pSQLCloseCursor = NULL;
177 static SQLCONNECT pSQLConnect = NULL;
178 static SQLDISCONNECT pSQLDisconnect = NULL;
179 static SQLENDTRAN pSQLEndTran = NULL;
180 static SQLEXECDIRECT pSQLExecDirect = NULL;
181 static SQLEXECUTE pSQLExecute = NULL;
182 static SQLFETCH pSQLFetch = NULL;
183 static SQLFREEHANDLE pSQLFreeHandle = NULL;
184 static SQLGETDATA pSQLGetData = NULL;
185 static SQLGETDIAGREC pSQLGetDiagRec = NULL;
186 static SQLGETINFO pSQLGetInfo = NULL;
187 static SQLGETSTMTATTR pSQLGetStmtAttr = NULL;
188 static SQLGETTYPEINFO pSQLGetTypeInfo = NULL;
189 static SQLPREPARE pSQLPrepare = NULL;
190 static SQLROWCOUNT_FN pSQLRowCount = NULL;
191 static SQLSETCONNECTATTR pSQLSetConnectAttr = NULL;
192 static SQLSETENVATTR pSQLSetEnvAttr = NULL;
193 static SQLSETSTMTATTR pSQLSetStmtAttr = NULL;
194 
195 /* The use of dynamically bound function pointers vs. statically linked
196    functions requires a bit of sleight of hand since we can't give the
197    pointers the same names as prototyped functions.  To get around this we
198    redefine the actual function names to the names of the pointers */
199 
200 #define SQLAllocHandle			pSQLAllocHandle
201 #define SQLBindParameter		pSQLBindParameter
202 #define SQLCloseCursor			pSQLCloseCursor
203 #define SQLConnect				pSQLConnect
204 #define SQLDisconnect			pSQLDisconnect
205 #define SQLEndTran				pSQLEndTran
206 #define SQLExecDirect			pSQLExecDirect
207 #define SQLExecute				pSQLExecute
208 #define SQLFetch				pSQLFetch
209 #define SQLFreeHandle			pSQLFreeHandle
210 #define SQLGetData				pSQLGetData
211 #define SQLGetDiagRec			pSQLGetDiagRec
212 #define SQLGetInfo				pSQLGetInfo
213 #define SQLGetStmtAttr			pSQLGetStmtAttr
214 #define SQLGetTypeInfo			pSQLGetTypeInfo
215 #define SQLPrepare				pSQLPrepare
216 #define SQLRowCount				pSQLRowCount
217 #define SQLSetConnectAttr		pSQLSetConnectAttr
218 #define SQLSetEnvAttr			pSQLSetEnvAttr
219 #define SQLSetStmtAttr			pSQLSetStmtAttr
220 
221 /* Depending on whether we're running under Win16, Win32, or Unix we load the
222    ODBC driver under a different name */
223 
224 #if defined( __WIN16__ )
225   #define ODBC_LIBNAME			"ODBC.DLL"
226 #elif defined( __WIN32__ )
227   #define ODBC_LIBNAME			"ODBC32.DLL"
228 #elif defined( __UNIX__ )
229   #if defined( __APPLE__ )
230 	/* OS X has built-in ODBC support via iODBC */
231 	#define ODBC_LIBNAME		"libiodbc.dylib"
232   #else
233 	/* Currently we default to UnixODBC, which uses libodbc.so.  If this
234 	   fails, we fall back to the next-most-common one, iODBC.  If you're
235 	   using something else, you'll need to change the entry below to
236 	   specify your library name */
237 	#define ODBC_LIBNAME		"libodbc.so"
238 	#define ODBC_ALT_LIBNAME	"libiodbc.so"
239   #endif /* Mac OS X vs. other Unixen */
240 #endif /* System-specific ODBC library names */
241 
242 /* Dynamically load and unload any necessary DBMS libraries */
243 
244 CHECK_RETVAL \
dbxInitODBC(void)245 int dbxInitODBC( void )
246 	{
247 #ifdef __WIN16__
248 	UINT errorMode;
249 #endif /* __WIN16__ */
250 
251 	/* If the ODBC module is already linked in, don't do anything */
252 	if( hODBC != NULL_INSTANCE )
253 		return( CRYPT_OK );
254 
255 	/* Obtain a handle to the module containing the ODBC functions */
256 #if defined( __WIN16__ )
257 	errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
258 	hODBC = LoadLibrary( ODBC_LIBNAME );
259 	SetErrorMode( errorMode );
260 	if( hODBC < HINSTANCE_ERROR )
261 		{
262 		hODBC = NULL_INSTANCE;
263 		return( CRYPT_ERROR_NOTAVAIL );
264 		}
265 #elif defined( __UNIX__ ) && !defined( __APPLE__ )
266 	if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE && \
267 		( hODBC = DynamicLoad( ODBC_ALT_LIBNAME ) ) == NULL_INSTANCE )
268 		return( CRYPT_ERROR_NOTAVAIL );
269 #else
270 	if( ( hODBC = DynamicLoad( ODBC_LIBNAME ) ) == NULL_INSTANCE )
271 		return( CRYPT_ERROR_NOTAVAIL );
272 #endif /* __WIN32__ */
273 
274 	/* Now get pointers to the functions */
275 	pSQLAllocHandle = ( SQLALLOCHANDLE ) DynamicBind( hODBC, "SQLAllocHandle" );
276 	pSQLBindParameter = ( SQLBINDPARAMETER ) DynamicBind( hODBC, "SQLBindParameter" );
277 	pSQLCloseCursor = ( SQLCLOSECURSOR ) DynamicBind( hODBC, "SQLCloseCursor" );
278 	pSQLConnect = ( SQLCONNECT ) DynamicBind( hODBC, "SQLConnect" );
279 	pSQLDisconnect = ( SQLDISCONNECT ) DynamicBind( hODBC, "SQLDisconnect" );
280 	pSQLEndTran = ( SQLENDTRAN ) DynamicBind( hODBC, "SQLEndTran" );
281 	pSQLExecDirect = ( SQLEXECDIRECT ) DynamicBind( hODBC, "SQLExecDirect" );
282 	pSQLExecute = ( SQLEXECUTE ) DynamicBind( hODBC, "SQLExecute" );
283 	pSQLFetch = ( SQLFETCH ) DynamicBind( hODBC, "SQLFetch" );
284 	pSQLFreeHandle = ( SQLFREEHANDLE ) DynamicBind( hODBC, "SQLFreeHandle" );
285 	pSQLGetData = ( SQLGETDATA ) DynamicBind( hODBC, "SQLGetData" );
286 	pSQLGetDiagRec = ( SQLGETDIAGREC ) DynamicBind( hODBC, "SQLGetDiagRec" );
287 	pSQLGetInfo = ( SQLGETINFO ) DynamicBind( hODBC, "SQLGetInfo" );
288 	pSQLGetStmtAttr = ( SQLGETSTMTATTR ) DynamicBind( hODBC, "SQLGetStmtAttr" );
289 	pSQLGetTypeInfo = ( SQLGETTYPEINFO ) DynamicBind( hODBC, "SQLGetTypeInfo" );
290 	pSQLPrepare = ( SQLPREPARE ) DynamicBind( hODBC, "SQLPrepare" );
291 	pSQLRowCount = ( SQLROWCOUNT_FN ) DynamicBind( hODBC, "SQLRowCount" );
292 	pSQLSetConnectAttr = ( SQLSETCONNECTATTR ) DynamicBind( hODBC, "SQLSetConnectAttr" );
293 	pSQLSetEnvAttr = ( SQLSETENVATTR ) DynamicBind( hODBC, "SQLSetEnvAttr" );
294 	pSQLSetStmtAttr = ( SQLSETSTMTATTR ) DynamicBind( hODBC, "SQLSetStmtAttr" );
295 
296 	/* Make sure that we got valid pointers for every ODBC function */
297 	if( pSQLAllocHandle == NULL || pSQLBindParameter == NULL ||
298 		pSQLCloseCursor == NULL || pSQLConnect == NULL ||
299 		pSQLDisconnect == NULL || pSQLEndTran == NULL ||
300 		pSQLExecDirect == NULL || pSQLExecute == NULL ||
301 		pSQLFetch == NULL || pSQLFreeHandle == NULL ||
302 		pSQLGetData == NULL || pSQLGetDiagRec == NULL ||
303 		pSQLGetInfo == NULL || pSQLGetStmtAttr == NULL ||
304 		pSQLGetTypeInfo == NULL || pSQLPrepare == NULL ||
305 		pSQLSetConnectAttr == NULL || pSQLSetEnvAttr == NULL ||
306 		pSQLSetStmtAttr == NULL )
307 		{
308 		/* Free the library reference and reset the handle */
309 		DynamicUnload( hODBC );
310 		hODBC = NULL_INSTANCE;
311 		return( CRYPT_ERROR_NOTAVAIL );
312 		}
313 
314 	return( CRYPT_OK );
315 	}
316 
dbxEndODBC(void)317 void dbxEndODBC( void )
318 	{
319 	if( hODBC != NULL_INSTANCE )
320 		DynamicUnload( hODBC );
321 	hODBC = NULL_INSTANCE;
322 	}
323 #else
324 
325 CHECK_RETVAL \
dbxInitODBC(void)326 int dbxInitODBC( void )
327 	{
328 	return( CRYPT_OK );
329 	}
330 
dbxEndODBC(void)331 void dbxEndODBC( void )
332 	{
333 	}
334 #endif /* DYNAMIC_LOAD */
335 
336 /****************************************************************************
337 *																			*
338 *						 		Utility Routines							*
339 *																			*
340 ****************************************************************************/
341 
342 /* Get information on an ODBC error.  The statement handle is specified as a
343    distinct parameter because it may be an ephemeral handle not part of the
344    state information data */
345 
346 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getErrorInfo(INOUT DBMS_STATE_INFO * dbmsInfo,IN_ENUM (SQL_ERRLVL)const SQL_ERRLVL_TYPE errorLevel,const SQLHSTMT hStmt,IN_ERROR const int defaultStatus)347 static int getErrorInfo( INOUT DBMS_STATE_INFO *dbmsInfo,
348 						 IN_ENUM( SQL_ERRLVL ) const SQL_ERRLVL_TYPE errorLevel,
349 						 const SQLHSTMT hStmt,
350 						 IN_ERROR const int defaultStatus )
351 	{
352 #ifdef USE_ERRMSGS
353 	ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
354 #endif /* USE_ERRMSGS */
355 	SQLCHAR szSqlState[ SQL_SQLSTATE_SIZE + 8 ];
356 	SQLCHAR errorString[ MAX_ERRMSG_SIZE + 1 + 8 ];
357 	SQLHANDLE handle;
358 	SQLINTEGER dwNativeError = 0;
359 	SQLSMALLINT handleType, errorStringLength;
360 	SQLRETURN sqlStatus;
361 
362 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
363 
364 	REQUIRES( errorLevel == SQL_ERRLVL_STMT || \
365 			  errorLevel == SQL_ERRLVL_DBC || \
366 			  errorLevel == SQL_ERRLVL_ENV );
367 	REQUIRES( ( errorLevel == SQL_ERRLVL_STMT && \
368 				hStmt != SQL_NULL_HSTMT ) || \
369 			  ( errorLevel != SQL_ERRLVL_STMT && \
370 				hStmt == SQL_NULL_HSTMT ) );
371 	REQUIRES( cryptStatusError( defaultStatus ) );
372 
373 	/* Set up the handle information for the diagnostic information that we
374 	   want to retrieve */
375 	switch( errorLevel )
376 		{
377 		case SQL_ERRLVL_STMT:
378 			handleType = SQL_HANDLE_STMT;
379 			handle = hStmt;
380 			break;
381 
382 		case SQL_ERRLVL_DBC:
383 			handleType = SQL_HANDLE_DBC;
384 			handle = dbmsInfo->hDbc;
385 			break;
386 
387 		case SQL_ERRLVL_ENV:
388 			handleType = SQL_HANDLE_ENV;
389 			handle = dbmsInfo->hEnv;
390 			break;
391 
392 		default:
393 			retIntError();
394 		}
395 
396 	/* Get the ODBC error information at the most detailed level that we can
397 	   manage */
398 	sqlStatus = SQLGetDiagRec( handleType, handle, 1, szSqlState,
399 							   &dwNativeError, errorString, MAX_ERRMSG_SIZE,
400 							   &errorStringLength );
401 	if( !sqlStatusOK( sqlStatus ) && errorLevel == SQL_ERRLVL_STMT )
402 		{
403 		/* If we couldn't get information at the statement-handle level, try
404 		   again at the connection handle level */
405 		sqlStatus = SQLGetDiagRec( SQL_HANDLE_DBC, dbmsInfo->hDbc, 1,
406 								   szSqlState, &dwNativeError,
407 								   errorString, MAX_ERRMSG_SIZE,
408 								   &errorStringLength );
409 		}
410 	if( !sqlStatusOK( sqlStatus ) )
411 		{
412 		DEBUG_DIAG(( "Couldn't read error information from database "
413 					 "backend" ));
414 		assert( DEBUG_WARN );	/* Catch this if it ever occurs */
415 		setErrorString( errorInfo,
416 						"Couldn't get error information from database "
417 						"backend", 52 );
418 		return( CRYPT_ERROR_READ );
419 		}
420 
421 	/* In some (rare) cases SQLGetDiagRec() can return an empty error string
422 	   with only szSqlState set, in which case we clear the error string */
423 	if( errorStringLength > 0 )
424 		{
425 		/* Since the error string has come from the database source we
426 		   sanitise it before returning it to the caller.  The +1 is for
427 		   the '\0' that sanitiseString() adds to the string */
428 		sanitiseString( errorString, errorStringLength + 1,
429 						errorStringLength );
430 		setErrorString( errorInfo, errorString, errorStringLength );
431 		}
432 	else
433 		clearErrorString( errorInfo );
434 
435 	/* Check for a not-found error status.  We can also get an sqlStatus of
436 	   SQL_NO_DATA with SQLSTATE set to "00000" and the error message string
437 	   empty in some cases, in which case we provide our own error string */
438 	if( !memcmp( szSqlState, "S0002", 5 ) ||	/* ODBC 2.x */
439 		!memcmp( szSqlState, "42S02", 5 ) ||	/* ODBC 3.x */
440 		( !memcmp( szSqlState, "00000", 5 ) && \
441 		  sqlStatus == SQL_NO_DATA ) )
442 		{
443 		/* Make sure that the caller gets a sensible error message if they
444 		   try to examine the extended error information */
445 		if( errorStringLength <= 0 )
446 			setErrorString( errorInfo, "No data found", 13 );
447 
448 		return( CRYPT_ERROR_NOTFOUND );
449 		}
450 
451 	/* When we're trying to create a new keyset, there may already be one
452 	   present giving an S0001/42S01 (table already exists) or S0011/42S11
453 	   (index already exists) error .  We could check for the table by doing
454 	   a dummy read, but it's easier to just try the update anyway and
455 	   convert the error code to the correct value here if there's a
456 	   problem */
457 	if( !memcmp( szSqlState, "S0001", 5 ) ||
458 		!memcmp( szSqlState, "S0011", 5 ) ||	/* ODBC 2.x */
459 		!memcmp( szSqlState, "42S01", 5 ) ||
460 		!memcmp( szSqlState, "42S11", 5 ) )		/* ODBX 3.x */
461 		return( CRYPT_ERROR_DUPLICATE );
462 
463 	/* This one is a bit odd: An integrity constraint violation occurred,
464 	   which means (among other things) that an attempt was made to write a
465 	   duplicate value to a column constrained to contain unique values.  It
466 	   can also include things like writing a NULL value to a column
467 	   constrained to be NOT NULL, but this wouldn't normally happen so we
468 	   can convert this one to a duplicate data error */
469 	if( !memcmp( szSqlState, "23000", 5 ) )
470 		return( CRYPT_ERROR_DUPLICATE );
471 
472 	return( defaultStatus );
473 	}
474 
475 /* Dump debugging information on an ODBC error to the error log.  This is
476    used to record oddball errors during debugging that don't necessarily
477    affect overall operation but that should be fixed anyway */
478 
479 #if !defined( NDEBUG ) && defined( DEBUG_DIAGNOSTIC_ENABLE )
480 
481 #define DUMP_ODBCERROR	debugDiagOdbcError
482 
483 STDC_NONNULL_ARG( ( 1, 2 ) ) \
debugDiagOdbcError(IN_STRING const char * functionName,INOUT DBMS_STATE_INFO * dbmsInfo,IN_ENUM (SQL_ERRLVL)const SQL_ERRLVL_TYPE errorLevel,const SQLHSTMT hStmt)484 void debugDiagOdbcError( IN_STRING const char *functionName,
485 						 INOUT DBMS_STATE_INFO *dbmsInfo,
486 						 IN_ENUM( SQL_ERRLVL ) const SQL_ERRLVL_TYPE errorLevel,
487 						 const SQLHSTMT hStmt )
488 	{
489 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
490 	assert( isReadPtr( functionName, 8 ) );
491 	assert( errorLevel == SQL_ERRLVL_STMT || \
492 			errorLevel == SQL_ERRLVL_DBC || \
493 			errorLevel == SQL_ERRLVL_ENV );
494 	assert( ( errorLevel == SQL_ERRLVL_STMT && \
495 			hStmt != SQL_NULL_HSTMT ) || \
496 		  ( errorLevel != SQL_ERRLVL_STMT && \
497 			hStmt == SQL_NULL_HSTMT ) );
498 
499 	( void ) getErrorInfo( dbmsInfo, errorLevel, hStmt,
500 						   CRYPT_ERROR_INTERNAL );
501 	DEBUG_DIAG(( "%s reports: %s.\n", functionName,
502 				 getErrorInfoString( &dbmsInfo->errorInfo ) ));
503 	}
504 #else
505   #define DUMP_ODBCERROR( dbmsInfo, functionName, errorLevel, hStmt );
506 #endif /* !NDEBUG */
507 
508 /* Rewrite the SQL query to handle the back-end specific blob and date type,
509    and to work around problems with some back-end types (and we're
510    specifically talking Access here) */
511 
512 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 6 ) ) \
rewriteString(INOUT_BUFFER (stringMaxLength,* stringLength)char * string,IN_LENGTH_SHORT const int stringMaxLength,OUT_LENGTH_BOUNDED_Z (stringMaxLength)int * stringLength,IN_LENGTH_SHORT const int subStringLength,IN_LENGTH_SHORT const int origStringLength,IN_BUFFER (newSubStringLength)const char * newSubString,IN_LENGTH_SHORT const int newSubStringLength)513 static int rewriteString( INOUT_BUFFER( stringMaxLength, \
514 										*stringLength ) char *string,
515 						  IN_LENGTH_SHORT const int stringMaxLength,
516 						  OUT_LENGTH_BOUNDED_Z( stringMaxLength ) \
517 								int *stringLength,
518 						  IN_LENGTH_SHORT const int subStringLength,
519 						  IN_LENGTH_SHORT const int origStringLength,
520 						  IN_BUFFER( newSubStringLength ) \
521 								const char *newSubString,
522 						  IN_LENGTH_SHORT const int newSubStringLength )
523 	{
524 	const int remainder = origStringLength - subStringLength;
525 	const int newStringLength = newSubStringLength + remainder;
526 
527 	assert( isWritePtr( string, stringMaxLength ) );
528 	assert( isReadPtr( newSubString, newSubStringLength ) );
529 
530 	REQUIRES( stringMaxLength > 0 && stringMaxLength < MAX_INTLENGTH_SHORT );
531 	REQUIRES( subStringLength > 0 && \
532 			  subStringLength < origStringLength && \
533 			  subStringLength < MAX_INTLENGTH_SHORT );
534 	REQUIRES( origStringLength > 0 && \
535 			  origStringLength <= stringMaxLength && \
536 			  origStringLength < MAX_INTLENGTH_SHORT );
537 	REQUIRES( newSubStringLength > 0 && \
538 			  newSubStringLength < MAX_INTLENGTH_SHORT );
539 
540 	/* Clear return value */
541 	*stringLength = 0;
542 
543 	/* Make sure that the parameters are in order and there's room to
544 	   rewrite the string */
545 	ENSURES( remainder > 0 && newStringLength > 0 && \
546 			 newStringLength < stringMaxLength );
547 
548 	/* Open/close up a gap and replace the existing substring with the new
549 	   one:
550 
551 									origStringLength
552 		|<----------- string -------------->|
553 		+---------------+-------------------+-----------+
554 		|///////////////|...................|			|
555 		+---------------+-------------------+-----------+
556 		|<- subString ->|								|
557 												stringMaxLength */
558 	REQUIRES( rangeCheck( newSubStringLength, remainder, stringMaxLength ) );
559 	memmove( string + newSubStringLength, string + subStringLength,
560 			 remainder );
561 	memcpy( string, newSubString, newSubStringLength );
562 	*stringLength = newSubStringLength - subStringLength;
563 
564 	return( CRYPT_OK );
565 	}
566 
567 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
568 static int convertQuery( INOUT DBMS_STATE_INFO *dbmsInfo,
569 						 OUT_BUFFER( queryMaxLen, *queryLength ) char *query,
570 						 IN_LENGTH_SHORT_MIN( 16 ) const int queryMaxLen,
571 						 OUT_LENGTH_BOUNDED_Z( queryMaxLen ) \
572 								int *queryLength,
573 						 IN_BUFFER( commandLength ) const char *command,
574 						 IN_LENGTH_SHORT const int commandLength )
575 	{
576 	int currentLength = commandLength;
577 	int offset, length, status;
578 
579 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
580 	assert( isWritePtr( query, queryMaxLen ) );
581 	assert( isReadPtr( command, commandLength ) );
582 
583 	REQUIRES( queryMaxLen >= 16 && queryMaxLen < MAX_INTLENGTH_SHORT );
584 	REQUIRES( commandLength > 0 && commandLength < queryMaxLen && \
585 			  commandLength < MAX_INTLENGTH_SHORT );
586 
587 	/* Clear return value */
588 	*queryLength = 0;
589 
590 	/* Copy the SQL command across to the query buffer */
591 	memcpy( query, command, commandLength );
592 
593 	/* If it's a CREATE TABLE command rewrite the blob and date types to the
594 	   appropriate values for the database back-end */
595 	if( !strCompare( command, "CREATE TABLE", 12 ) )
596 		{
597 		offset = strFindStr( query, currentLength, " BLOB", 5 );
598 		if( offset > 0 )
599 			{
600 			offset++;	/* Skip space before blob name */
601 
602 			status = rewriteString( query + offset, queryMaxLen - offset,
603 									&length, 4, currentLength - offset,
604 									dbmsInfo->blobName,
605 									dbmsInfo->blobNameLength );
606 			if( cryptStatusError( status ) )
607 				return( status );
608 			currentLength += length;
609 			}
610 		offset = strFindStr( query, currentLength, " DATETIME", 9 );
611 		if( offset > 0 && \
612 			!( dbmsInfo->dateTimeNameLength == 8 && \
613 			   !strCompare( dbmsInfo->dateTimeName, "DATETIME", 8 ) ) )
614 			{
615 			offset++;	/* Skip space before date/time name */
616 			status = rewriteString( query + offset, queryMaxLen - offset,
617 									&length, 8, currentLength - offset,
618 									dbmsInfo->dateTimeName,
619 									dbmsInfo->dateTimeNameLength );
620 			if( cryptStatusError( status ) )
621 				return( status );
622 			currentLength += length;
623 			}
624 		}
625 
626 	/* If it's not one of the back-ends that require special-case handling,
627 	   we're done */
628 	switch( dbmsInfo->backendType )
629 		{
630 		case DBMS_ACCESS:
631 			/* If it's not a SELECT/DELETE with wildcards used, there's
632 			   nothing to do */
633 			if( ( strCompare( query, "SELECT", 6 ) && \
634 				  strCompare( query, "DELETE", 6 ) ) || \
635 				  strFindStr( query, currentLength, " LIKE ", 6 ) <= 7 )
636 				{
637 				*queryLength = currentLength;
638 				return( CRYPT_OK );
639 				}
640 			break;
641 
642 		case DBMS_INTERBASE:
643 			/* If it's not a CREATE TABLE/INSERT/DELETE/SELECT with the
644 			   'type' column involved, there's nothing to do */
645 			if( strCompare( query, "CREATE TABLE", 12 ) && \
646 				strCompare( query, "SELECT", 6 ) && \
647 				strCompare( query, "DELETE", 6 ) && \
648 				strCompare( query, "INSERT", 6 ) )
649 				{
650 				*queryLength = currentLength;
651 				return( CRYPT_OK );
652 				}
653 			if( strFindStr( query, currentLength, " type ", 6 ) <= 7 )
654 				{
655 				*queryLength = currentLength;
656 				return( CRYPT_OK );
657 				}
658 			break;
659 
660 		default:
661 			/* Currently no other back-ends need special handling */
662 			*queryLength = currentLength;
663 			return( CRYPT_OK );
664 		}
665 
666 	/* Unlike everything else in the known universe Access uses * and ?
667 	   instead of the standard SQL wildcards so if we find a LIKE ... %
668 	   we rewrite the % as a * */
669 	if( ( dbmsInfo->backendType == DBMS_ACCESS ) && \
670 		( offset = strFindStr( query, currentLength, " LIKE ", 6 ) ) > 0 )
671 		{
672 		int i;
673 
674 		/* Search up to 6 characters ahead for a wildcard and replace it
675 		   with the one needed by Access if we find it.  We search 6 chars
676 		   ahead because the higher-level SQL code uses expressions like
677 		   "SELECT .... WHERE foo LIKE '--%'", which is 5 chars plus one as
678 		   a safety margin */
679 		for( i = offset + 7; i < offset + 11 && i < currentLength; i++ )
680 			{
681 			if( query[ i ] == '%' )
682 				query[ i ] = '*';
683 			}
684 		}
685 
686 	/* Interbase treats TYPE as a reserved word so we can't use 'type' for a
687 	   column name */
688 	if( ( dbmsInfo->backendType == DBMS_INTERBASE ) && \
689 		( offset = strFindStr( query, currentLength, " type ", 6 ) ) > 0 )
690 		{
691 		offset++;	/* Skip space before type name */
692 		status = rewriteString( query + offset, queryMaxLen - offset,
693 								&length, 4, currentLength - offset,
694 								"ctype", 5 );
695 		if( cryptStatusError( status ) )
696 			return( status );
697 		currentLength += length;
698 		}
699 
700 	*queryLength = currentLength;
701 	return( CRYPT_OK );
702 	}
703 
704 /* Bind parameters for a query/update.  The caller has to supply the bound
705    data storage since it still has to exist later on when the query is
706    executed */
707 
708 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3, 4 ) ) \
bindParameters(const SQLHSTMT hStmt,IN_ARRAY_C (BOUND_DATA_MAXITEMS)const BOUND_DATA * boundData,OUT BOUND_DATA_STATE * boundDataState,INOUT DBMS_STATE_INFO * dbmsInfo)709 static int bindParameters( const SQLHSTMT hStmt,
710 						   IN_ARRAY_C( BOUND_DATA_MAXITEMS ) \
711 							const BOUND_DATA *boundData,
712 						   OUT BOUND_DATA_STATE *boundDataState,
713 						   INOUT DBMS_STATE_INFO *dbmsInfo )
714 	{
715 	SQLUSMALLINT paramNo = 1;
716 	int i;
717 
718 	assert( isReadPtr( boundData, \
719 					   sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS ) );
720 	assert( isWritePtr( boundDataState, sizeof( BOUND_DATA_STATE ) ) );
721 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
722 
723 	memset( boundDataState, 0, sizeof( BOUND_DATA_STATE ) );
724 
725 	/* Bind in any necessary parameters to the hStmt */
726 	for( i = 0; i < BOUND_DATA_MAXITEMS && \
727 				boundData[ i ].type != BOUND_DATA_NONE; i++ )
728 		{
729 		const BOUND_DATA *boundDataPtr = &boundData[ i ];
730 		SQLSMALLINT valueType, parameterType;
731 		SQLRETURN sqlStatus;
732 
733 		if( boundDataPtr->type == BOUND_DATA_TIME )
734 			{
735 			SQL_TIMESTAMP_STRUCT *timestampStorage = \
736 								 &boundDataState->timestampStorage;
737 			struct tm timeInfo, *timeInfoPtr = &timeInfo;
738 
739 			REQUIRES( boundDataPtr->dataLength == sizeof( time_t ) );
740 
741 			/* Sanity check the input parameters */
742 			timeInfoPtr = gmTime_s( boundDataPtr->data, timeInfoPtr );
743 			if( timeInfoPtr == NULL )
744 				return( CRYPT_ERROR_BADDATA );
745 
746 			/* Bind in the date.  The handling of the ColumnSize parameter
747 			   is ugly, this value should be implicit in the underlying data
748 			   type but a small number of back-ends (e.g. ones derived from
749 			   the Sybase 4.2 code line, which includes the current Sybase
750 			   and SQL Server) may support multiple time representations and
751 			   require an explicit length indicator to decide which one they
752 			   should use.  This means that we have to provide an explicit
753 			   length value as a hint to the driver, see the comment in
754 			   getDatatypeInfo() for how this is obtained */
755 			memset( timestampStorage, 0, sizeof( SQL_TIMESTAMP_STRUCT ) );
756 			timestampStorage->year = ( SQLSMALLINT ) ( timeInfoPtr->tm_year + 1900 );
757 			timestampStorage->month = ( SQLUSMALLINT ) ( timeInfoPtr->tm_mon + 1 );
758 			timestampStorage->day = ( SQLUSMALLINT ) timeInfoPtr->tm_mday;
759 			timestampStorage->hour = ( SQLUSMALLINT ) timeInfoPtr->tm_hour;
760 			timestampStorage->minute = ( SQLUSMALLINT ) timeInfoPtr->tm_min;
761 			timestampStorage->second = ( SQLUSMALLINT ) timeInfoPtr->tm_sec;
762 			sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
763 										  SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP,
764 										  dbmsInfo->dateTimeNameColSize, 0,
765 										  timestampStorage, 0, NULL );
766 			if( !sqlStatusOK( sqlStatus ) )
767 				return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
768 									  CRYPT_ERROR_BADDATA ) );
769 			continue;
770 			}
771 
772 		assert( ( boundDataPtr->dataLength == 0 ) || \
773 				isReadPtr( boundDataPtr->data, boundDataPtr->dataLength ) );
774 
775 		REQUIRES( boundDataPtr != NULL );
776 		REQUIRES( boundDataPtr->type == BOUND_DATA_STRING || \
777 				  boundDataPtr->type == BOUND_DATA_BLOB );
778 		REQUIRES( dbmsInfo->hasBinaryBlobs || \
779 				  ( !dbmsInfo->hasBinaryBlobs && \
780 					boundDataPtr->type == BOUND_DATA_STRING ) );
781 		REQUIRES( ( boundDataPtr->data == NULL && \
782 					boundDataPtr->dataLength == 0 ) || \
783 				  ( boundDataPtr->data != NULL && \
784 					boundDataPtr->dataLength > 0 &&
785 					boundDataPtr->dataLength < MAX_INTLENGTH_SHORT ) );
786 				  /* Bound data of { NULL, 0 } denotes a null parameter */
787 
788 		/* Null parameters have to be handled specially.  Note that we have
789 		   to set the ColumnSize parameter (no.6) to a nonzero value (even
790 		   though it's ignored, since this is a null parameter) otherwise
791 		   some drivers will complain about an "Invalid precision value" */
792 		if( boundDataPtr->dataLength <= 0 )
793 			{
794 			static const SQLINTEGER nullDataValue = SQL_NULL_DATA;
795 
796 			sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
797 										  SQL_C_CHAR, SQL_C_CHAR, 1, 0, NULL, 0,
798 										  ( SQLINTEGER * ) &nullDataValue );
799 			if( !sqlStatusOK( sqlStatus ) )
800 				return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
801 									  CRYPT_ERROR_BADDATA ) );
802 			continue;
803 			}
804 
805 		/* Bind in the query data */
806 		if( boundDataPtr->type == BOUND_DATA_BLOB )
807 			{
808 			valueType = SQL_C_BINARY;
809 			parameterType = dbmsInfo->blobType;
810 			}
811 		else
812 			valueType = parameterType = SQL_C_CHAR;
813 		boundDataState->lengthStorage[ i ] = boundDataPtr->dataLength;
814 		sqlStatus = SQLBindParameter( hStmt, paramNo++, SQL_PARAM_INPUT,
815 									  valueType, parameterType,
816 									  boundDataPtr->dataLength, 0,
817 									  ( SQLPOINTER ) boundDataPtr->data,
818 									  boundDataPtr->dataLength,
819 									  &boundDataState->lengthStorage[ i ] );
820 		if( !sqlStatusOK( sqlStatus ) )
821 			return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
822 								  CRYPT_ERROR_BADDATA ) );
823 		}
824 	ENSURES( i < BOUND_DATA_MAXITEMS );
825 
826 	return( CRYPT_OK );
827 	}
828 
829 /****************************************************************************
830 *																			*
831 *						 Get Database Back-end Information					*
832 *																			*
833 ****************************************************************************/
834 
835 /* Get data type information for this data source.  Since SQLGetTypeInfo()
836    returns a variable (and arbitrary) length result set we have to call
837    SQLCloseCursor() after each fetch before performing a new query */
838 
839 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
getBlobInfo(INOUT DBMS_STATE_INFO * dbmsInfo,const SQLSMALLINT type,OUT_LENGTH_SHORT_Z int * maxFieldSize)840 static int getBlobInfo( INOUT DBMS_STATE_INFO *dbmsInfo,
841 						const SQLSMALLINT type,
842 						OUT_LENGTH_SHORT_Z int *maxFieldSize )
843 	{
844 	const SQLHSTMT hStmt = dbmsInfo->hStmt[ DBMS_CACHEDQUERY_NONE ];
845 	SQLRETURN sqlStatus;
846 	SQLINTEGER blobNameLength, count, dummy;
847 
848 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
849 
850 	/* Clear return value */
851 	*maxFieldSize = 0;
852 
853 	/* Check for support for the requested type and get the results of the
854 	   transaction.  If the database doesn't support this we'll get an
855 	   SQL_NO_DATA status */
856 	sqlStatus = SQLGetTypeInfo( hStmt, type );
857 	if( !sqlStatusOK( sqlStatus ) )
858 		return( CRYPT_ERROR );
859 	sqlStatus = SQLFetch( hStmt );
860 	if( !sqlStatusOK( sqlStatus ) )
861 		{
862 		SQLCloseCursor( hStmt );
863 		return( CRYPT_ERROR );
864 		}
865 
866 	/* Get the type name (result column 1) and column size (= maximum
867 	   possible field length, result column 3).  We only check the second
868 	   return code since they both apply to the same row */
869 	SQLGetData( hStmt, 1, SQL_C_CHAR, dbmsInfo->blobName,
870 				CRYPT_MAX_TEXTSIZE, &blobNameLength );
871 	sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG, &count,
872 							sizeof( SQLINTEGER ), &dummy );
873 	SQLCloseCursor( hStmt );
874 	if( !sqlStatusOK( sqlStatus ) )
875 		return( CRYPT_ERROR );
876 	if( dbmsInfo->backendType == DBMS_MYSQL && blobNameLength == 0 )
877 		{
878 		/* Some older versions of the MySQL ODBC driver don't return a
879 		   length value so we have to set it ourselves by taking the length
880 		   of the returned string.  The null-termination occurs as a side-
881 		   effect of the buffer being initialised to zeroes */
882 		blobNameLength = strlen( dbmsInfo->blobName );
883 		}
884 	dbmsInfo->blobNameLength = ( int ) blobNameLength;
885 #ifdef __UNIX__
886 	if( dummy != sizeof( SQLINTEGER ) )
887 		{
888 		fprintf( stderr, "\ncryptlib: The ODBC driver is erroneously "
889 				 "returning a %ld-byte integer value\n          when a "
890 				 "%d-byte SQLINTEGER value is requested, which will "
891 				 "overwrite\n          adjacent memory locations.  To fix "
892 				 "this you need to recompile\n          with whatever "
893 				 "preprocessor options your ODBC header files require\n"
894 				 "          to force the use of 64-bit ODBC data types (and "
895 				 "report this issue\n          to the ODBC driver vendor so "
896 				 "that they can sync the driver and\n          headers)."
897 				 "\n\n", ( long ) dummy, ( int ) sizeof( SQLINTEGER ) );
898 				 /* Cast is nec. because sizeof() can be 32 or 64 bits */
899 		}
900 #endif /* __UNIX__ */
901 	*maxFieldSize = count;
902 
903 	/* We've got the type information, remember the details.  Postgres has
904 	   problems handling blobs via ODBC (or even in general) since it uses
905 	   its own BYTEA (byte array) type that's not really usable as an SQL
906 	   blob type because of weird escaping requirements when
907 	   sending/receiving data.  In addition it requires other Postgres-
908 	   specific oddities like specifying 'ByteaAsLongVarBinary=1' in the
909 	   connect string.  So even though the back-end sort-of supports blobs
910 	   we can't actually use them */
911 	if( ( type == SQL_LONGVARBINARY ) && \
912 		( dbmsInfo->backendType != DBMS_POSTGRES ) )
913 		dbmsInfo->hasBinaryBlobs = TRUE;
914 	dbmsInfo->blobType = type;
915 
916 	return( CRYPT_OK );
917 	}
918 
919 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getDateTimeInfo(INOUT DBMS_STATE_INFO * dbmsInfo)920 static int getDateTimeInfo( INOUT DBMS_STATE_INFO *dbmsInfo )
921 	{
922 	const SQLHSTMT hStmt = dbmsInfo->hStmt[ DBMS_CACHEDQUERY_NONE ];
923 	SQLRETURN sqlStatus;
924 	SQLINTEGER dateTimeNameLength, columnSize, dummy;
925 
926 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
927 
928 	/* The Postgres driver doesn't correctly detect the date/time type used
929 	   by the back-end so we have to hard-code in the actual value */
930 	if( dbmsInfo->backendType == DBMS_POSTGRES )
931 		{
932 		memcpy( dbmsInfo->dateTimeName, "TIMESTAMP", 9 );
933 		dbmsInfo->dateTimeNameLength = 9;
934 		dbmsInfo->dateTimeNameColSize = 16;
935 
936 		return( CRYPT_OK );
937 		}
938 
939 	/* Get information on the back-end's date+time data type  This changed
940 	   from SQL_TIMESTAMP in ODBC 2.x to SQL_TYPE_TIMESTAMP in ODBC 3.x,
941 	   since 3.x will be more common we try the 3.x version first and if
942 	   that fails fall back to 2.x */
943 	sqlStatus = SQLGetTypeInfo( hStmt, SQL_TYPE_TIMESTAMP );
944 	if( !sqlStatusOK( sqlStatus ) )
945 		{
946 		DEBUG_DIAG(( "Database backend uses pre-ODBC 3.0 data types" ));
947 		assert( DEBUG_WARN );	/* Warn of absenceof ODBC 3.0 types */
948 		sqlStatus = SQLGetTypeInfo( hStmt, SQL_TIMESTAMP );
949 		}
950 	if( !sqlStatusOK( sqlStatus ) )
951 		return( CRYPT_ERROR );
952 
953 	/* Fetch the results of the transaction and get the type name (result
954 	   column 1) and column size (result column 3) */
955 	sqlStatus = SQLFetch( hStmt );
956 	if( !sqlStatusOK( sqlStatus ) )
957 		{
958 		SQLCloseCursor( hStmt );
959 		return( CRYPT_ERROR );
960 		}
961 	sqlStatus = SQLGetData( hStmt, 1, SQL_C_CHAR, dbmsInfo->dateTimeName,
962 							CRYPT_MAX_TEXTSIZE, &dateTimeNameLength );
963 	if( sqlStatusOK( sqlStatus ) )
964 		sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG,
965 								&dbmsInfo->dateTimeNameColSize,
966 								sizeof( SQLINTEGER ), &dummy );
967 	if( !sqlStatusOK( sqlStatus ) )
968 		{
969 		SQLCloseCursor( hStmt );
970 		return( CRYPT_ERROR );
971 		}
972 	if( dbmsInfo->backendType == DBMS_MYSQL && dateTimeNameLength == 0 )
973 		{
974 		/* Some older versions of the MySQL ODBC driver don't return a
975 		   length value so we have to set it ourselves by taking the length
976 		   of the returned string.  The null-termination occurs as a side-
977 		   effect of the buffer being initialised to zeroes */
978 		dateTimeNameLength = strlen( dbmsInfo->dateTimeName );
979 		}
980 	dbmsInfo->dateTimeNameLength = ( int ) dateTimeNameLength;
981 
982 	/* The column size argument is quite problematic because although some
983 	   back-ends have a fixed size for this (and usually ignore the column-
984 	   size parameter) others allow multiple time representations and
985 	   require an explicit column-size indicator to decide which one they
986 	   should use.  The ODBC standard representation for example uses 19
987 	   chars (yyyy-mm-dd hh:mm:ss) for the full date+time that we use here
988 	   but also allows a 16-char version without the seconds and a 20+n-char
989 	   version for n digits of fractional seconds.  The back-end however may
990 	   use a completely different value, for example Oracle encodes the full
991 	   date+time as 7 bytes (century, year, month, day, hour, minute,
992 	   second).  To get around this we get the first column-size value
993 	   (which is usually the only one available) and if this is the same as
994 	   the ODBC standard minimum-size column we try for more results to see
995 	   if the full date+time form is available, and use that if it is */
996 	if( dbmsInfo->dateTimeNameColSize != 16 )
997 		{
998 		/* This isn't a potentially problematic column size, we're done */
999 		SQLCloseCursor( hStmt );
1000 		return( CRYPT_OK );
1001 		}
1002 
1003 	/* If the back-end has reported the short (no-seconds) ODBC-default
1004 	   format, see whether it'll support the longer (with seconds) format
1005 	   instead */
1006 	sqlStatus = SQLFetch( hStmt );
1007 	if( !sqlStatusOK( sqlStatus ) )
1008 		{
1009 		SQLCloseCursor( hStmt );
1010 		return( CRYPT_ERROR );
1011 		}
1012 	sqlStatus = SQLGetData( hStmt, 3, SQL_C_SLONG, &columnSize,
1013 							sizeof( SQLINTEGER ), &dummy );
1014 	if( sqlStatusOK( sqlStatus ) && columnSize == 19 )
1015 		dbmsInfo->dateTimeNameColSize = columnSize;
1016 	SQLCloseCursor( hStmt );
1017 
1018 	return( CRYPT_OK );
1019 	}
1020 
1021 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getDatatypeInfo(INOUT DBMS_STATE_INFO * dbmsInfo,OUT_FLAGS_Z (DBMS)int * featureFlags)1022 static int getDatatypeInfo( INOUT DBMS_STATE_INFO *dbmsInfo,
1023 							OUT_FLAGS_Z( DBMS ) int *featureFlags )
1024 	{
1025 #ifdef USE_ERRMSGS
1026 	ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
1027 #endif /* USE_ERRMSGS */
1028 	const SQLHSTMT hStmt = dbmsInfo->hStmt[ DBMS_CACHEDQUERY_NONE ];
1029 	SQLRETURN sqlStatus;
1030 	SQLSMALLINT bufLen;
1031 	SQLUSMALLINT transactBehaviour;
1032 	SQLINTEGER attrLength;
1033 	SQLUINTEGER privileges;
1034 	char buffer[ 8 + 8 ];
1035 	int maxBlobSize, status;
1036 
1037 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1038 	assert( isWritePtr( featureFlags, sizeof( int ) ) );
1039 
1040 	/* Clear return value */
1041 	*featureFlags = DBMS_FEATURE_FLAG_NONE;
1042 
1043 	/* First we see what the back-end's blob data type is.  Usually it'll
1044 	   be binary blobs, if that doesn't work we try for char blobs */
1045 	status = getBlobInfo( dbmsInfo, SQL_LONGVARBINARY, &maxBlobSize );
1046 	if( cryptStatusError( status ) )
1047 		status = getBlobInfo( dbmsInfo, SQL_LONGVARCHAR, &maxBlobSize );
1048 	if( cryptStatusError( status ) )
1049 		return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1050 							  CRYPT_ERROR_OPEN ) );
1051 	if( dbmsInfo->hasBinaryBlobs )
1052 		*featureFlags |= DBMS_FEATURE_FLAG_BINARYBLOBS;
1053 
1054 	/* If we couldn't get a blob type or the type is too short to use,
1055 	   report it back as a database open failure */
1056 	if( maxBlobSize < MAX_ENCODED_CERT_SIZE )
1057 		{
1058 		char errorMessage[ 128 + 8 ];
1059 		int errorMessageLength;
1060 
1061 		errorMessageLength = \
1062 			sprintf_s( errorMessage, 128,
1063 					   "Database blob type can only store %d bytes, we need "
1064 					   "at least %d", maxBlobSize, MAX_ENCODED_CERT_SIZE );
1065 		setErrorString( errorInfo, errorMessage, errorMessageLength );
1066 		return( CRYPT_ERROR_OPEN );
1067 		}
1068 
1069 	/* Sanity check, make sure that the source can return the required
1070 	   amount of data.  A number of data sources don't support this
1071 	   attribute (it's mostly meant to be set by applications rather than
1072 	   being read, and is intended to be used to reduce network traffic) and
1073 	   in addition the maximum query size is pretty short (the longest is a
1074 	   few hundred bytes for the table creation commands) so we don't worry
1075 	   if it's not available.  In addition to the maximum-size check we also
1076 	   have to perform a minimum-size check since a value of zero is used to
1077 	   indicate no length limit */
1078 	sqlStatus = SQLGetStmtAttr( hStmt, SQL_ATTR_MAX_LENGTH,
1079 								( SQLPOINTER ) &attrLength, SQL_IS_INTEGER,
1080 								NULL );
1081 	if( sqlStatusOK( sqlStatus ) && \
1082 		attrLength > 0 && attrLength < MAX_SQL_QUERY_SIZE )
1083 		{
1084 		char errorMessage[ 128 + 8 ];
1085 		int errorMessageLength;
1086 
1087 		errorMessageLength = \
1088 			sprintf_s( errorMessage, 128,
1089 					   "Database back-end can only transmit %d bytes per "
1090 					   "message, we need at least %d", attrLength,
1091 					   MAX_SQL_QUERY_SIZE );
1092 		setErrorString( errorInfo, errorMessage, errorMessageLength );
1093 		return( CRYPT_ERROR_OPEN );
1094 		}
1095 
1096 	/* Now do the same thing for the date+time data type */
1097 	status = getDateTimeInfo( dbmsInfo );
1098 	if( cryptStatusError( status ) )
1099 		return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1100 							  CRYPT_ERROR_OPEN ) );
1101 
1102 	/* Determine whether we can write to the database (result = 'Y') or not
1103 	   (result = 'N') */
1104 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_DATA_SOURCE_READ_ONLY,
1105 							buffer, 8, &bufLen );
1106 	if( sqlStatusOK( sqlStatus ) && *buffer == 'Y' )
1107 		*featureFlags |= DBMS_FEATURE_FLAG_READONLY;
1108 
1109 	/* Determine whether GRANT/REVOKE capabilities are available.  This gets
1110 	   a bit messy because it only specifies which extended GRANT/REVOKE
1111 	   options are available rather than whether GRANT/REVOKE is available
1112 	   at all.  To handle this we treat GRANT/REVOKE as being available if
1113 	   any information is returned (SQL Server typically returns only
1114 	   SQL_SG_WITH_GRANT_OPTION while other sources like DB2, Postgres, and
1115 	   Sybase return the correct set of flags) and not available if nothing
1116 	   is returned (Access, dBASE, Paradox, etc).  To make things especially
1117 	   challenging, Informix returns nothing for SQL_SQL92_GRANT but does
1118 	   return something for SQL_SQL92_REVOKE so we have to check both and
1119 	   allow GRANT/REVOKE if either test positive */
1120 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_SQL92_GRANT,
1121 							( SQLPOINTER ) &privileges,
1122 							sizeof( SQLUINTEGER ), &bufLen );
1123 	if( sqlStatusOK( sqlStatus ) && privileges )
1124 		*featureFlags |= DBMS_FEATURE_FLAG_PRIVILEGES;
1125 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_SQL92_REVOKE,
1126 							( SQLPOINTER ) &privileges,
1127 							sizeof( SQLUINTEGER ), &bufLen );
1128 	if( sqlStatusOK( sqlStatus ) && privileges )
1129 		*featureFlags |= DBMS_FEATURE_FLAG_PRIVILEGES;
1130 
1131 	/* Check how the back-end reacts to commit/rollback operations.  If
1132 	   transactions are destructive (that is, prepared statements are
1133 	   cleared when a commit/rollback is performed) we have to clear the
1134 	   hStmtPrepared[] array to indicate that all statements have to be
1135 	   re-prepared.  Fortunately this is quite rare, both because most
1136 	   back-ends don't do this (for virtually all ODBC-accessible data
1137 	   sources (SQL Server, Access, dBASE, Paradox, etc etc) the behaviour
1138 	   is SQL_CB_CLOSE, meaning that the currently active cursor is closed
1139 	   but there's no need to call SQLPrepare() again) and because
1140 	   transactions are used with CA certificate stores opened in read/write
1141 	   mode */
1142 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_CURSOR_COMMIT_BEHAVIOR,
1143 							&transactBehaviour, sizeof( SQLUSMALLINT ),
1144 							&bufLen );
1145 	if( sqlStatusOK( sqlStatus ) && transactBehaviour == SQL_CB_DELETE )
1146 		{
1147 		DEBUG_DIAG(( "Database uses destructive transactions" ));
1148 		assert( DEBUG_WARN );
1149 		dbmsInfo->transactIsDestructive = TRUE;
1150 		}
1151 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_CURSOR_ROLLBACK_BEHAVIOR,
1152 							&transactBehaviour, sizeof( SQLUSMALLINT ),
1153 							&bufLen );
1154 	if( sqlStatusOK( sqlStatus ) && transactBehaviour == SQL_CB_DELETE )
1155 		{
1156 		DEBUG_DIAG(( "Database uses destructive transactions" ));
1157 		assert( DEBUG_WARN );
1158 		dbmsInfo->transactIsDestructive = TRUE;
1159 		}
1160 
1161 	return( CRYPT_OK );
1162 	}
1163 
1164 /* Get the back-end type for this data source, which allows us to work
1165    around back-end-specific bugs and peculiarities */
1166 
1167 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getBackendInfo(INOUT DBMS_STATE_INFO * dbmsInfo)1168 static int getBackendInfo( INOUT DBMS_STATE_INFO *dbmsInfo )
1169 	{
1170 	SQLRETURN sqlStatus;
1171 	SQLSMALLINT bufLen;
1172 	char buffer[ 128 + 8 ];
1173 
1174 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1175 
1176 	/* Check for various back-ends that require special-case handling */
1177 	sqlStatus = SQLGetInfo( dbmsInfo->hDbc, SQL_DBMS_NAME, buffer, 128 - 1,
1178 							&bufLen );
1179 	if( sqlStatusOK( sqlStatus ) )
1180 		{
1181 		buffer[ bufLen ] = '\0';	/* Keep static source anal.tools happy */
1182 		if( bufLen >= 6 && !strCompare( buffer, "Access", 6 ) )
1183 			dbmsInfo->backendType = DBMS_ACCESS;
1184 		if( bufLen >= 9 && !strCompare( buffer, "Interbase", 9 ) )
1185 			dbmsInfo->backendType = DBMS_INTERBASE;
1186 		if( bufLen >= 5 && !strCompare( buffer, "MySQL", 5 ) )
1187 			dbmsInfo->backendType = DBMS_MYSQL;
1188 		if( bufLen >= 12 && !strCompare( buffer, "PostgreSQL", 10 ) )
1189 			dbmsInfo->backendType = DBMS_POSTGRES;
1190 		}
1191 
1192 	return( CRYPT_OK );
1193 	}
1194 
1195 /****************************************************************************
1196 *																			*
1197 *						 	Database Open/Close Routines					*
1198 *																			*
1199 ****************************************************************************/
1200 
1201 /* Close a previously-opened ODBC connection.  We have to have this before
1202    openDatabase() since it may be called by openDatabase() if the open
1203    process fails */
1204 
1205 STDC_NONNULL_ARG( ( 1 ) ) \
closeDatabase(INOUT DBMS_STATE_INFO * dbmsInfo)1206 static void closeDatabase( INOUT DBMS_STATE_INFO *dbmsInfo )
1207 	{
1208 	SQLRETURN sqlStatus;
1209 	int i;
1210 
1211 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1212 
1213 	/* Commit the transaction.  The default transaction mode is auto-commit
1214 	   so the SQLEndTran() call isn't strictly necessary, but we play it
1215 	   safe anyway */
1216 	if( dbmsInfo->needsUpdate )
1217 		{
1218 		sqlStatus = SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc, SQL_COMMIT );
1219 		if( !sqlStatusOK( sqlStatus ) )
1220 			{
1221 			DUMP_ODBCERROR( "SQLEndTran()", dbmsInfo, SQL_ERRLVL_DBC,
1222 							SQL_NULL_HSTMT );
1223 			assert( DEBUG_WARN );	/* Catch this if it ever occurs */
1224 			}
1225 		dbmsInfo->needsUpdate = FALSE;
1226 		}
1227 
1228 	/* Clean up */
1229 	for( i = 0; i < NO_CACHED_QUERIES; i++ )
1230 		{
1231 		if( dbmsInfo->hStmt[ i ] != NULL )
1232 			{
1233 			sqlStatus = SQLFreeHandle( SQL_HANDLE_STMT, dbmsInfo->hStmt[ i ] );
1234 			if( !sqlStatusOK( sqlStatus ) )
1235 				{
1236 				DUMP_ODBCERROR( "SQLFreeHandle()", dbmsInfo,
1237 								SQL_ERRLVL_STMT, dbmsInfo->hStmt[ i ] );
1238 				assert( DEBUG_WARN );	/* Catch this if it ever occurs */
1239 				}
1240 			dbmsInfo->hStmtPrepared[ i ] = FALSE;
1241 			dbmsInfo->hStmt[ i ] = NULL;
1242 			}
1243 		}
1244 	if( dbmsInfo->connectionOpen )
1245 		{
1246 		sqlStatus = SQLDisconnect( dbmsInfo->hDbc );
1247 		if( !sqlStatusOK( sqlStatus ) )
1248 			{
1249 			DUMP_ODBCERROR( "SQLDisconnect()", dbmsInfo, SQL_ERRLVL_DBC,
1250 							SQL_NULL_HSTMT );
1251 			assert( DEBUG_WARN );	/* Catch this if it ever occurs */
1252 			}
1253 		dbmsInfo->connectionOpen = FALSE;
1254 		}
1255 	sqlStatus = SQLFreeHandle( SQL_HANDLE_DBC, dbmsInfo->hDbc );
1256 	if( !sqlStatusOK( sqlStatus ) )
1257 		{
1258 		DUMP_ODBCERROR( "SQLFreeHandle()", dbmsInfo, SQL_ERRLVL_DBC,
1259 						SQL_NULL_HSTMT );
1260 		assert( DEBUG_WARN );	/* Catch this if it ever occurs */
1261 		}
1262 	sqlStatus = SQLFreeHandle( SQL_HANDLE_ENV, dbmsInfo->hEnv );
1263 	assert( sqlStatusOK( sqlStatus ) );			/* Warn of potential errors */
1264 	dbmsInfo->hDbc = NULL;
1265 	dbmsInfo->hEnv = NULL;
1266 	}
1267 
1268 /* Open a connection to a data source.  We don't check the return codes for
1269    many of the parameter-fiddling functions since the worst that can happen
1270    if they fail is that performance will be somewhat suboptimal and it's not
1271    worth abandoning the database open just because some obscure tweak isn't
1272    supported.
1273 
1274    In addition to the main hStmt handle we also allocate a number of
1275    additional hStmts used to contain pre-prepared, cached instances of
1276    frequently-executed queries.  This means that the expensive step of
1277    parsing the SQL query, validating it against the system catalog,
1278    preparing an access plan, and optimising the plan, are only performed
1279    once on the first query rather than at every single access */
1280 
1281 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
openDatabase(INOUT DBMS_STATE_INFO * dbmsInfo,IN_BUFFER (nameLen)const char * name,IN_LENGTH_NAME const int nameLen,IN_ENUM_OPT (CRYPT_KEYOPT)const CRYPT_KEYOPT_TYPE options,OUT_FLAGS_Z (DBMS)int * featureFlags)1282 static int openDatabase( INOUT DBMS_STATE_INFO *dbmsInfo,
1283 						 IN_BUFFER( nameLen ) const char *name,
1284 						 IN_LENGTH_NAME const int nameLen,
1285 						 IN_ENUM_OPT( CRYPT_KEYOPT ) \
1286 							const CRYPT_KEYOPT_TYPE options,
1287 						 OUT_FLAGS_Z( DBMS ) int *featureFlags )
1288 	{
1289 #ifdef USE_ERRMSGS
1290 	ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
1291 #endif /* USE_ERRMSGS */
1292 	DBMS_NAME_INFO nameInfo;
1293 	SQLRETURN sqlStatus;
1294 	int i, status;
1295 
1296 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1297 	assert( isReadPtr( name, nameLen ) );
1298 	assert( isWritePtr( featureFlags, sizeof( int ) ) );
1299 
1300 	REQUIRES( nameLen >= MIN_NAME_LENGTH && \
1301 			  nameLen < MAX_ATTRIBUTE_SIZE );
1302 	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
1303 
1304 	/* Clear return values */
1305 	memset( dbmsInfo, 0, sizeof( DBMS_STATE_INFO ) );
1306 	*featureFlags = DBMS_FEATURE_FLAG_NONE;
1307 
1308 #ifdef DYNAMIC_LOAD
1309 	/* Make sure that the driver is bound in */
1310 	if( hODBC == NULL_INSTANCE )
1311 		return( CRYPT_ERROR_OPEN );
1312 #endif /* DYNAMIC_LOAD */
1313 
1314 	/* Parse the data source into its individual components */
1315 	status = dbmsParseName( &nameInfo, name, nameLen );
1316 	if( cryptStatusError( status ) )
1317 		return( status );
1318 
1319 	/* Allocate environment and connection handles.  Before we do anything
1320 	   with the environment handle we have to set the ODBC version to 3 or
1321 	   any succeeding calls will fail with a function sequence error.  God
1322 	   knows why they couldn't assume a default setting of ODBC 3.x for this
1323 	   value when it requires an ODBC 3.x function call to get here in the
1324 	   first place */
1325 	sqlStatus = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE,
1326 								&dbmsInfo->hEnv );
1327 	if( !sqlStatusOK( sqlStatus ) )
1328 		{
1329 		/* We can't get any error details without at least an environment
1330 		   handle so all that we can do is return a generic allocation error
1331 		   message.  If we get a failure at this point (and in particular
1332 		   on the very first ODBC call) it's usually a sign of an incorrect
1333 		   ODBC install or config (on non-Windows systems where it's not
1334 		   part of the OS), since the ODBC driver can't initialise itself */
1335 #ifdef __WINDOWS__
1336 		setErrorString( errorInfo,
1337 						"Couldn't allocate database connection handle", 44 );
1338 #else
1339 		setErrorString( errorInfo,
1340 						"Couldn't allocate database connection handle, this "
1341 						"is probably due to an incorrect ODBC driver install "
1342 						"or an invalid configuration", 130 );
1343 #endif /* __WINDOWS__ */
1344 		return( CRYPT_ERROR_OPEN );
1345 		}
1346 	sqlStatus = SQLSetEnvAttr( dbmsInfo->hEnv, SQL_ATTR_ODBC_VERSION,
1347 								VALUE_TO_PTR( SQL_OV_ODBC3 ),
1348 								SQL_IS_INTEGER );
1349 	if( sqlStatusOK( sqlStatus ) )
1350 		sqlStatus = SQLAllocHandle( SQL_HANDLE_DBC, dbmsInfo->hEnv,
1351 									&dbmsInfo->hDbc );
1352 	if( !sqlStatusOK( sqlStatus ) )
1353 		{
1354 		status = getErrorInfo( dbmsInfo, SQL_ERRLVL_ENV, SQL_NULL_HSTMT,
1355 							   CRYPT_ERROR_OPEN );
1356 		SQLFreeHandle( SQL_HANDLE_ENV, dbmsInfo->hEnv );
1357 		return( status );
1358 		}
1359 
1360 	/* Once everything is set up the way that we want it, try to connect to
1361 	   a data source and allocate a statement handle.  If there's an error
1362 	   we dump the information to the error log, since this is a create-
1363 	   object function and so extended error information can't be read since
1364 	   the object won't be created */
1365 	sqlStatus = SQLConnect( dbmsInfo->hDbc,
1366 							( SQLCHAR * ) nameInfo.name,
1367 							( SQLSMALLINT ) nameInfo.nameLen,
1368 							( SQLCHAR * ) nameInfo.user,
1369 							( SQLSMALLINT ) nameInfo.userLen,
1370 							( SQLCHAR * ) nameInfo.password,
1371 							( SQLSMALLINT ) nameInfo.passwordLen );
1372 	if( !sqlStatusOK( sqlStatus ) )
1373 		{
1374 		status = getErrorInfo( dbmsInfo, SQL_ERRLVL_DBC, SQL_NULL_HSTMT,
1375 							   CRYPT_ERROR_OPEN );
1376 		DEBUG_DIAG(( "SQLConnect returned error %d, status:\n  '%s'.",
1377 					 sqlStatus, dbmsInfo->errorInfo.errorString ));
1378 		closeDatabase( dbmsInfo );
1379 		return( status );
1380 		}
1381 	dbmsInfo->connectionOpen = TRUE;
1382 
1383 	/* Now that the connection is open, allocate the statement handles */
1384 	for( i = 0; i < NO_CACHED_QUERIES && sqlStatusOK( sqlStatus ); i++ )
1385 		{
1386 		sqlStatus = SQLAllocHandle( SQL_HANDLE_STMT, dbmsInfo->hDbc,
1387 									&dbmsInfo->hStmt[ i ] );
1388 		}
1389 	if( !sqlStatusOK( sqlStatus ) )
1390 		{
1391 		status = getErrorInfo( dbmsInfo, SQL_ERRLVL_DBC, SQL_NULL_HSTMT,
1392 							   CRYPT_ERROR_OPEN );
1393 		DEBUG_DIAG(( "SQLAllocHandle returned error %d, status:\n  '%s'.",
1394 					 sqlStatus, dbmsInfo->errorInfo.errorString ));
1395 		closeDatabase( dbmsInfo );
1396 		return( status );
1397 		}
1398 
1399 	/* Set the access mode to read-only if we can.  The default is R/W, but
1400 	   setting it to read-only optimises transaction management */
1401 	if( options == CRYPT_KEYOPT_READONLY )
1402 		{
1403 		( void ) SQLSetStmtAttr( dbmsInfo->hDbc, SQL_ATTR_ACCESS_MODE,
1404 								 VALUE_TO_PTR( SQL_MODE_READ_ONLY ),
1405 								 SQL_IS_INTEGER );
1406 		}
1407 
1408 	/* Set the cursor type to forward-only (which should be the default
1409 	   anyway), concurrency to read-only if we're opening the database in
1410 	   read-only mode (this again should be the default), and turn off
1411 	   scanning for escape clauses in the SQL strings, which lets the driver
1412 	   pass the string directly to the data source.  The latter improves
1413 	   both performance and (to some extent) security by reducing the
1414 	   chances of hostile SQL injection, or at least by requiring specially
1415 	   crafted back-end specific SQL rather than generic ODBC SQL to
1416 	   function */
1417 	for( i = 0; i < NO_CACHED_QUERIES; i++ )
1418 		{
1419 		( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ], SQL_ATTR_CURSOR_TYPE,
1420 								 VALUE_TO_PTR( SQL_CURSOR_FORWARD_ONLY ),
1421 								 SQL_IS_INTEGER );
1422 		if( options == CRYPT_KEYOPT_READONLY )
1423 			{
1424 			( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ],
1425 									 SQL_ATTR_CONCURRENCY,
1426 									 VALUE_TO_PTR( SQL_CONCUR_READ_ONLY ),
1427 									 SQL_IS_INTEGER );
1428 			}
1429 		( void ) SQLSetStmtAttr( dbmsInfo->hStmt[ i ], SQL_ATTR_NOSCAN,
1430 								 VALUE_TO_PTR( SQL_NOSCAN_ON ),
1431 								 SQL_IS_INTEGER );
1432 		}
1433 
1434 	/* Get various driver and data source-specific information that we may
1435 	   need later on */
1436 	status = getDatatypeInfo( dbmsInfo, featureFlags );
1437 	if( cryptStatusOK( status ) )
1438 		status = getBackendInfo( dbmsInfo );
1439 	if( cryptStatusError( status ) )
1440 		{
1441 		closeDatabase( dbmsInfo );
1442 		return( status );
1443 		}
1444 
1445 	return( CRYPT_OK );
1446 	}
1447 
1448 /****************************************************************************
1449 *																			*
1450 *						 	Database Read Routines							*
1451 *																			*
1452 ****************************************************************************/
1453 
1454 /* Fetch data from a query */
1455 
1456 CHECK_RETVAL STDC_NONNULL_ARG( ( 6 ) ) \
fetchData(const SQLHSTMT hStmt,OUT_BUFFER_OPT (dataMaxLength,* dataLength)char * data,IN_LENGTH_SHORT_Z const int dataMaxLength,OUT_OPT_LENGTH_SHORT_Z int * dataLength,IN_ENUM (DBMS_QUERY)const DBMS_QUERY_TYPE queryType,INOUT DBMS_STATE_INFO * dbmsInfo)1457 static int fetchData( const SQLHSTMT hStmt,
1458 					  OUT_BUFFER_OPT( dataMaxLength, *dataLength ) \
1459 						char *data,
1460 					  IN_LENGTH_SHORT_Z const int dataMaxLength,
1461 					  OUT_OPT_LENGTH_SHORT_Z int *dataLength,
1462 					  IN_ENUM( DBMS_QUERY ) const DBMS_QUERY_TYPE queryType,
1463 					  INOUT DBMS_STATE_INFO *dbmsInfo )
1464 	{
1465 #ifdef USE_ERRMSGS
1466 	ERROR_INFO *errorInfo = &dbmsInfo->errorInfo;
1467 #endif /* USE_ERRMSGS */
1468 	const SQLSMALLINT dataType = ( SQLSMALLINT  ) \
1469 								 ( ( dbmsInfo->hasBinaryBlobs ) ? \
1470 								   SQL_C_BINARY : SQL_C_CHAR );
1471 	SQLRETURN sqlStatus;
1472 	SQLINTEGER length;
1473 
1474 	assert( ( queryType == DBMS_QUERY_CHECK && \
1475 			  data == NULL && dataMaxLength == 0 && dataLength == NULL ) || \
1476 			( queryType != DBMS_QUERY_CHECK && \
1477 			  isWritePtr( data, dataMaxLength ) && \
1478 			  isWritePtr( dataLength, sizeof( int ) ) ) );
1479 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1480 
1481 	REQUIRES( ( queryType == DBMS_QUERY_CHECK && \
1482 				data == NULL && dataMaxLength == 0 && \
1483 				dataLength == NULL ) || \
1484 			  ( queryType != DBMS_QUERY_CHECK && \
1485 				data != NULL && dataMaxLength >= 16 && \
1486 				dataMaxLength < MAX_INTLENGTH_SHORT && \
1487 				dataLength != NULL ) );
1488 	REQUIRES( queryType > DBMS_QUERY_NONE && \
1489 			  queryType < DBMS_QUERY_LAST );
1490 
1491 	/* Clear return value */
1492 	if( data != NULL )
1493 		{
1494 		memset( data, 0, min( 16, dataMaxLength ) );
1495 		*dataLength = 0;
1496 		}
1497 
1498 	/* Get the results of the transaction */
1499 	sqlStatus = SQLFetch( hStmt );
1500 	if( !sqlStatusOK( sqlStatus ) )
1501 		{
1502 		/* If the fetch status is SQL_NO_DATA, indicating the end of the
1503 		   result set, we handle it specially since some drivers only return
1504 		   the basic error code and don't provide any further diagnostic
1505 		   information to be fetched by SQLGetDiagRec() */
1506 		if( sqlStatus == SQL_NO_DATA )
1507 			{
1508 			if( queryType == DBMS_QUERY_CONTINUE )
1509 				{
1510 				setErrorString( errorInfo, "No more data found", 18 );
1511 				}
1512 			else
1513 				{
1514 				setErrorString( errorInfo, "No data found", 13 );
1515 				}
1516 			return( CRYPT_ERROR_NOTFOUND );
1517 			}
1518 		return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1519 							  CRYPT_ERROR_READ ) );
1520 		}
1521 
1522 	/* If we're just doing a presence check we don't bother fetching data */
1523 	if( queryType == DBMS_QUERY_CHECK )
1524 		return( CRYPT_OK );
1525 
1526 	/* Read the data */
1527 	sqlStatus = SQLGetData( hStmt, 1, dataType, data, dataMaxLength,
1528 							&length );
1529 	if( !sqlStatusOK( sqlStatus ) )
1530 		return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1531 							  CRYPT_ERROR_READ ) );
1532 	*dataLength = ( int ) length;
1533 	return( CRYPT_OK );
1534 	}
1535 
1536 /* Perform a transaction that returns information */
1537 
1538 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
performQuery(INOUT DBMS_STATE_INFO * dbmsInfo,IN_BUFFER_OPT (commandLength)const char * command,IN_LENGTH_SHORT_Z const int commandLength,OUT_BUFFER_OPT (dataMaxLength,* dataLength)void * data,IN_LENGTH_SHORT_Z const int dataMaxLength,OUT_LENGTH_BOUNDED_Z (dataMaxLength)int * dataLength,IN_ARRAY_OPT_C (BOUND_DATA_MAXITEMS)TYPECAST (BOUND_DATA)const void * boundData,IN_ENUM_OPT (DBMS_CACHEDQUERY)const DBMS_CACHEDQUERY_TYPE queryEntry,IN_ENUM (DBMS_QUERY)const DBMS_QUERY_TYPE queryType)1539 static int performQuery( INOUT DBMS_STATE_INFO *dbmsInfo,
1540 						 IN_BUFFER_OPT( commandLength ) const char *command,
1541 						 IN_LENGTH_SHORT_Z const int commandLength,
1542 						 OUT_BUFFER_OPT( dataMaxLength, *dataLength ) \
1543 							void *data,
1544 						 IN_LENGTH_SHORT_Z const int dataMaxLength,
1545 						 OUT_LENGTH_BOUNDED_Z( dataMaxLength ) \
1546 							int *dataLength,
1547 						 IN_ARRAY_OPT_C( BOUND_DATA_MAXITEMS ) \
1548 							TYPECAST( BOUND_DATA ) const void *boundData,
1549 						 IN_ENUM_OPT( DBMS_CACHEDQUERY ) \
1550 							const DBMS_CACHEDQUERY_TYPE queryEntry,
1551 						 IN_ENUM( DBMS_QUERY ) const DBMS_QUERY_TYPE queryType )
1552 	{
1553 	const SQLHSTMT hStmt = dbmsInfo->hStmt[ queryEntry ];
1554 	BOUND_DATA_STATE boundDataState;
1555 	SQLRETURN sqlStatus;
1556 	int status;
1557 
1558 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1559 	assert( ( command == NULL && commandLength == 0 && \
1560 			  ( queryType == DBMS_QUERY_CONTINUE || \
1561 				queryType == DBMS_QUERY_CANCEL ) ) || \
1562 			isReadPtr( command, commandLength ) );
1563 	assert( ( data == NULL && dataMaxLength == 0 && dataLength == NULL ) || \
1564 			( isWritePtr( data, dataMaxLength ) && \
1565 			  isWritePtr( dataLength, sizeof( int ) ) ) );
1566 	assert( ( boundData == NULL ) || \
1567 			isReadPtr( boundData, \
1568 					   sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS ) );
1569 
1570 	REQUIRES( ( ( queryType == DBMS_QUERY_CONTINUE || \
1571 				  queryType == DBMS_QUERY_CANCEL ) && \
1572 				command == NULL && commandLength == 0 ) || \
1573 			  ( ( queryType == DBMS_QUERY_START || \
1574 				  queryType == DBMS_QUERY_CHECK || \
1575 				  queryType == DBMS_QUERY_NORMAL ) && \
1576 				command != NULL && \
1577 				commandLength > 0 && commandLength < MAX_INTLENGTH_SHORT ) );
1578 	REQUIRES( ( data == NULL && dataMaxLength == 0 && \
1579 				dataLength == NULL ) || \
1580 			  ( data != NULL && dataMaxLength >= 16 && \
1581 				dataMaxLength < MAX_INTLENGTH_SHORT && \
1582 				dataLength != NULL ) );
1583 	REQUIRES( queryEntry >= DBMS_CACHEDQUERY_NONE && \
1584 			  queryEntry < DBMS_CACHEDQUERY_LAST );
1585 	REQUIRES( queryType > DBMS_QUERY_NONE && \
1586 			  queryType < DBMS_QUERY_LAST );
1587 
1588 	/* Clear return value */
1589 	if( dataLength != NULL )
1590 		*dataLength = 0;
1591 
1592 	/* If we're starting a new query, handle the query initialisation and
1593 	   parameter binding */
1594 	if( queryType == DBMS_QUERY_START || \
1595 		queryType == DBMS_QUERY_CHECK || \
1596 		queryType == DBMS_QUERY_NORMAL )
1597 		{
1598 		/* Prepare the query for execution if necessary.  The entry at
1599 		   position DBMS_CACHEDQUERY_NONE is never cached so the following
1600 		   code is always executed for this case */
1601 		if( !dbmsInfo->hStmtPrepared[ queryEntry ] )
1602 			{
1603 			char query[ SQL_QUERY_BUFSIZE + 8 ];
1604 			int queryLength;
1605 
1606 			status = convertQuery( dbmsInfo, query, SQL_QUERY_BUFSIZE,
1607 								   &queryLength, command, commandLength );
1608 			if( cryptStatusError( status ) )
1609 				return( status );
1610 			sqlStatus = SQLPrepare( hStmt, ( SQLCHAR * ) query,
1611 									queryLength );
1612 			if( !sqlStatusOK( sqlStatus ) )
1613 				return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1614 									  CRYPT_ERROR_READ ) );
1615 			if( queryEntry != DBMS_CACHEDQUERY_NONE )
1616 				dbmsInfo->hStmtPrepared[ queryEntry ] = TRUE;
1617 			}
1618 
1619 		/* Bind in any query parameters that may be required */
1620 		if( boundData != NULL )
1621 			{
1622 			status = bindParameters( hStmt, boundData, &boundDataState,
1623 									 dbmsInfo );
1624 			if( cryptStatusError( status ) )
1625 				return( status );
1626 			}
1627 		}
1628 
1629 	switch( queryType )
1630 		{
1631 		case DBMS_QUERY_START:
1632 			/* Execute the query */
1633 			sqlStatus = SQLExecute( hStmt );
1634 			if( !sqlStatusOK( sqlStatus ) )
1635 				return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1636 									  CRYPT_ERROR_READ ) );
1637 
1638 			/* If we're starting an ongoing query with results to be fetched
1639 			   later, we're done */
1640 			if( data == NULL )
1641 				return( CRYPT_OK );
1642 
1643 			/* Drop through to fetch the first set of results */
1644 
1645 		case DBMS_QUERY_CONTINUE:
1646 			assert( isWritePtr( data, dataMaxLength ) );
1647 
1648 			REQUIRES( data != NULL && \
1649 					  dataMaxLength >= 16 && \
1650 					  dataMaxLength < MAX_INTLENGTH_SHORT );
1651 
1652 			/* We're in the middle of a continuing query, fetch the next set
1653 			   of results.  If we've run out of results (indicated by a not-
1654 			   found status) we explicitly signal to the caller that the
1655 			   query has completed */
1656 			status = fetchData( dbmsInfo->hStmt[ queryEntry ], data,
1657 								dataMaxLength, dataLength,
1658 								DBMS_QUERY_CONTINUE, dbmsInfo );
1659 			return( cryptStatusOK( status ) ? CRYPT_OK : \
1660 					( status == CRYPT_ERROR_NOTFOUND ) ? \
1661 					CRYPT_ERROR_COMPLETE : status );
1662 
1663 		case DBMS_QUERY_CANCEL:
1664 			/* Cancel any outstanding requests to clear the hStmt and make
1665 			   it ready for re-use */
1666 			SQLCloseCursor( dbmsInfo->hStmt[ queryEntry ] );
1667 			return( CRYPT_OK );
1668 
1669 		case DBMS_QUERY_CHECK:
1670 		case DBMS_QUERY_NORMAL:
1671 			/* Only return a maximum of a single row in response to a point
1672 			   query.  This is a simple optimisation to ensure that the
1673 			   database client doesn't start sucking across huge amounts of
1674 			   data when it's not necessary */
1675 			( void ) SQLSetStmtAttr( hStmt, SQL_ATTR_MAX_ROWS,
1676 									 VALUE_TO_PTR( 1 ), SQL_IS_INTEGER );
1677 
1678 			/* Execute the SQL statement and fetch the results */
1679 			sqlStatus = SQLExecute( hStmt );
1680 			if( sqlStatusOK( sqlStatus ) )
1681 				{
1682 				status = fetchData( hStmt, data, dataMaxLength, dataLength,
1683 									queryType, dbmsInfo );
1684 				SQLCloseCursor( hStmt );
1685 				}
1686 			else
1687 				{
1688 				status = getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1689 									   CRYPT_ERROR_READ );
1690 				}
1691 
1692 			/* Reset the statement handle's multi-row result handling */
1693 			( void ) SQLSetStmtAttr( hStmt, SQL_ATTR_MAX_ROWS,
1694 									 VALUE_TO_PTR( 0 ), SQL_IS_INTEGER );
1695 			return( status );
1696 		}
1697 
1698 	retIntError();
1699 	}
1700 
1701 /****************************************************************************
1702 *																			*
1703 *						 	Database Write Routines							*
1704 *																			*
1705 ****************************************************************************/
1706 
1707 /* Perform a transaction that updates the database without returning any
1708    data */
1709 
1710 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
performUpdate(INOUT DBMS_STATE_INFO * dbmsInfo,IN_BUFFER_OPT (commandLength)const char * command,IN_LENGTH_SHORT_Z const int commandLength,IN_ARRAY_OPT_C (BOUND_DATA_MAXITEMS)TYPECAST (BOUND_DATA)const void * boundData,IN_ENUM (DBMS_UPDATE)const DBMS_UPDATE_TYPE updateType)1711 static int performUpdate( INOUT DBMS_STATE_INFO *dbmsInfo,
1712 						  IN_BUFFER_OPT( commandLength ) const char *command,
1713 						  IN_LENGTH_SHORT_Z const int commandLength,
1714 						  IN_ARRAY_OPT_C( BOUND_DATA_MAXITEMS ) \
1715 							TYPECAST( BOUND_DATA ) const void *boundData,
1716 						  IN_ENUM( DBMS_UPDATE ) \
1717 							const DBMS_UPDATE_TYPE updateType )
1718 	{
1719 	const SQLHSTMT hStmt = dbmsInfo->hStmt[ DBMS_CACHEDQUERY_NONE ];
1720 	BOUND_DATA_STATE boundDataState;
1721 	SQLRETURN sqlStatus;
1722 	char query[ SQL_QUERY_BUFSIZE + 8 ];
1723 	int queryLength, status;
1724 
1725 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_STATE_INFO ) ) );
1726 	assert( ( command == NULL && commandLength == 0 && \
1727 			  updateType == DBMS_UPDATE_ABORT ) || \
1728 			isReadPtr( command, commandLength ) );
1729 	assert( ( boundData == NULL ) || \
1730 			isReadPtr( boundData, \
1731 					   sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS ) );
1732 
1733 	REQUIRES( ( updateType == DBMS_UPDATE_ABORT && \
1734 				command == NULL && commandLength == 0 ) || \
1735 			  ( updateType != DBMS_UPDATE_ABORT && \
1736 				command != NULL && \
1737 				commandLength > 0 && commandLength < MAX_INTLENGTH_SHORT ) );
1738 	REQUIRES( updateType > DBMS_UPDATE_NONE && \
1739 			  updateType < DBMS_UPDATE_LAST );
1740 
1741 	/* If we're aborting a transaction, roll it back, re-enable autocommit,
1742 	   and clean up */
1743 	if( updateType == DBMS_UPDATE_ABORT )
1744 		{
1745 		sqlStatus = SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc,
1746 								SQL_ROLLBACK );
1747 		( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1748 									VALUE_TO_PTR( SQL_AUTOCOMMIT_ON ),
1749 									SQL_IS_UINTEGER );
1750 		if( !sqlStatusOK( sqlStatus ) )
1751 			return( getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1752 								  CRYPT_ERROR_WRITE ) );
1753 		return( CRYPT_OK );
1754 		}
1755 
1756 	/* If it's the start of a transaction, turn autocommit off */
1757 	if( updateType == DBMS_UPDATE_BEGIN )
1758 		{
1759 		( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1760 									VALUE_TO_PTR( SQL_AUTOCOMMIT_OFF ),
1761 									SQL_IS_UINTEGER );
1762 		}
1763 
1764 	/* Bind in any necessary parameters to the hStmt */
1765 	if( boundData != NULL )
1766 		{
1767 		status = bindParameters( hStmt, boundData, &boundDataState,
1768 								 dbmsInfo );
1769 		if( cryptStatusError( status ) )
1770 			return( status );
1771 		}
1772 
1773 	/* Execute the command */
1774 	status = convertQuery( dbmsInfo, query, SQL_QUERY_BUFSIZE, &queryLength,
1775 						   command, commandLength );
1776 	if( cryptStatusError( status ) )
1777 		return( status );
1778 	sqlStatus = SQLExecDirect( hStmt, ( SQLCHAR * ) query, queryLength );
1779 	if( !sqlStatusOK( sqlStatus ) )
1780 		{
1781 		/* If we were supposed to begin a transaction but it failed, reset
1782 		   the autocommit state.  This is necessary because the
1783 		   DBMS_FLAG_UPDATEACTIVE flag won't be set if the transaction
1784 		   isn't started and therefore the DBMS_UPDATE_COMMIT/
1785 		   DBMS_UPDATE_ABORT action that has to eventually follow a
1786 		   DBMS_UPDATE_BEGIN will never be performed */
1787 		if( updateType == DBMS_UPDATE_BEGIN )
1788 			{
1789 			( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1790 										VALUE_TO_PTR( SQL_AUTOCOMMIT_ON ),
1791 										SQL_IS_UINTEGER );
1792 			}
1793 
1794 		/* The return status from a delete operation can be reported in
1795 		   several ways at the whim of the driver.  Some drivers always
1796 		   report success even though nothing was found to delete (more
1797 		   common in ODBC 2.x drivers, see the code further on for the
1798 		   handling for this), others report a failure to delete anything
1799 		   with an SQL_NO_DATA status (more common in ODBC 3.x drivers).
1800 		   For this case we convert the overall status to a
1801 		   CRYPT_ERROR_NOTFOUND and update the sqlStatus as required if we
1802 		   need to continue */
1803 		if( sqlStatus == SQL_NO_DATA && \
1804 			command != NULL && commandLength >= 6 && \
1805 			!strCompare( command, "DELETE", 6 ) )
1806 			{
1807 			status = CRYPT_ERROR_NOTFOUND;
1808 			if( updateType != DBMS_UPDATE_COMMIT )
1809 				return( status );
1810 			}
1811 		else
1812 			{
1813 			/* If we hit an error at this point we can only exit if we're
1814 			   not finishing a transaction.  If we are, the commit turns
1815 			   into an abort further down */
1816 			status = getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1817 								   CRYPT_ERROR_WRITE );
1818 			if( updateType != DBMS_UPDATE_COMMIT )
1819 				return( status );
1820 			}
1821 		}
1822 	else
1823 		{
1824 		/* If we're performing a delete the operation will succeed even
1825 		   though nothing was found to delete so we make sure that we
1826 		   actually changed something */
1827 		if( command != NULL && commandLength >= 6 && \
1828 			!strCompare( command, "DELETE", 6 ) )
1829 			{
1830 			SQLINTEGER rowCount;
1831 
1832 			sqlStatus = SQLRowCount( hStmt, &rowCount );
1833 			if( !sqlStatusOK( sqlStatus ) || rowCount <= 0 )
1834 				status = CRYPT_ERROR_NOTFOUND;
1835 			}
1836 		}
1837 
1838 	/* If it's the end of a transaction, commit the transaction and turn
1839 	   autocommit on again */
1840 	if( updateType == DBMS_UPDATE_COMMIT )
1841 		{
1842 		/* If we've had a failure before this point, abort, otherwise
1843 		   commit.  The SQLSMALLINT cast is necessary (although spurious) in
1844 		   some development environments */
1845 		sqlStatus = SQLEndTran( SQL_HANDLE_DBC, dbmsInfo->hDbc,
1846 								( SQLSMALLINT ) \
1847 								( cryptStatusError( status ) ? \
1848 								  SQL_ROLLBACK : SQL_COMMIT ) );
1849 		if( dbmsInfo->transactIsDestructive )
1850 			{
1851 			int i;
1852 
1853 			/* If transactions are destructive for this back-end type,
1854 			   invalidate all prepared statements */
1855 			for( i = 0; i < NO_CACHED_QUERIES; i++ )
1856 				dbmsInfo->hStmtPrepared[ i ] = FALSE;
1857 			}
1858 		( void ) SQLSetConnectAttr( dbmsInfo->hDbc, SQL_ATTR_AUTOCOMMIT,
1859 									VALUE_TO_PTR( SQL_AUTOCOMMIT_ON ),
1860 									SQL_IS_UINTEGER );
1861 		if( cryptStatusOK( status ) && !sqlStatusOK( sqlStatus ) )
1862 			{
1863 			status = getErrorInfo( dbmsInfo, SQL_ERRLVL_STMT, hStmt,
1864 								   CRYPT_ERROR_WRITE );
1865 			}
1866 		}
1867 
1868 	return( status );
1869 	}
1870 
1871 #ifndef USE_RPCAPI
1872 
1873 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initDispatchODBC(INOUT DBMS_INFO * dbmsInfo)1874 int initDispatchODBC( INOUT DBMS_INFO *dbmsInfo )
1875 	{
1876 	assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
1877 
1878 	dbmsInfo->openDatabaseBackend = openDatabase;
1879 	dbmsInfo->closeDatabaseBackend = closeDatabase;
1880 	dbmsInfo->performUpdateBackend = performUpdate;
1881 	dbmsInfo->performQueryBackend = performQuery;
1882 
1883 	return( CRYPT_OK );
1884 	}
1885 #else
1886 
1887 /* Pull in the shared database RPC routines, renaming the generic dispatch
1888    function to the ODBC-specific one which is called directly by the
1889    marshalling code */
1890 
1891 #define processCommand( stateInfo, buffer ) \
1892 		odbcProcessCommand( stateInfo, buffer )
1893 #include "dbx_rpc.c"
1894 
1895 #endif /* !USE_RPCAPI */
1896 
1897 #endif /* USE_ODBC */
1898