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