cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dbms.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib DBMS Backend Interface *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include <ctype.h>
9 #include <stdarg.h>
10 #if defined( INC_ALL )
11  #include "crypt.h"
12  #include "keyset.h"
13  #include "dbms.h"
14  #include "rpc.h"
15 #else
16  #include "crypt.h"
17  #include "keyset/keyset.h"
18  #include "keyset/dbms.h"
19  #include "misc/rpc.h"
20 #endif /* Compiler-specific includes */
21 
22 #ifdef USE_DBMS
23 
24 /****************************************************************************
25 * *
26 * Backend Database Access Functions *
27 * *
28 ****************************************************************************/
29 
30 /* Dispatch functions for various database types. ODBC is the native keyset
31  for Windows and (frequently) Unix, the rest are accessible via database
32  plugins */
33 
34 #ifdef USE_ODBC
35  int initDispatchODBC( DBMS_INFO *dbmsInfo );
36 #else
37  #define initDispatchODBC( dbmsInfo ) CRYPT_ERROR
38 #endif /* USE_ODBC */
39 #if defined( USE_DATABASE )
40  int initDispatchDatabase( DBMS_INFO *dbmsInfo );
41 #else
42  #define initDispatchDatabase( dbmsInfo ) CRYPT_ERROR
43 #endif /* General database interface */
44 
45 /* Database access functions */
46 
47 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
48 static int openDatabase( INOUT DBMS_INFO *dbmsInfo,
49  IN_BUFFER( nameLen ) const char *name,
50  IN_LENGTH_NAME const int nameLen,
51  IN_ENUM_OPT( CRYPT_KEYOPT ) \
53  OUT_FLAGS_Z( DBMS_FEATURE ) int *featureFlags )
54  {
55  DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
56  int status;
57 
58  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
59  assert( isReadPtr( name, nameLen ) );
60  assert( isWritePtr( featureFlags, sizeof( int ) ) );
61 
62  REQUIRES( nameLen >= MIN_NAME_LENGTH && \
63  nameLen < MAX_ATTRIBUTE_SIZE );
64  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
65 
66  /* Clear return value */
67  *featureFlags = DBMS_FEATURE_FLAG_NONE;
68 
69  status = dbmsInfo->openDatabaseBackend( dbmsStateInfo, name, nameLen,
70  options, featureFlags );
71  if( cryptStatusError( status ) )
72  return( status );
73 
74  /* Make long-term information returned as a back-end interface-specific
75  feature flags persistent if necessary */
76  if( *featureFlags & DBMS_FEATURE_FLAG_BINARYBLOBS )
77  dbmsInfo->flags |= DBMS_FLAG_BINARYBLOBS;
78 
79  return( CRYPT_OK );
80  }
81 
82 STDC_NONNULL_ARG( ( 1 ) ) \
83 static void closeDatabase( INOUT DBMS_INFO *dbmsInfo )
84  {
85  DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
86 
87  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
88 
89  dbmsInfo->closeDatabaseBackend( dbmsStateInfo );
90  }
91 
93 static int performUpdate( INOUT DBMS_INFO *dbmsInfo,
94  IN_STRING_OPT const char *command,
96  TYPECAST( BOUND_DATA ) const void *boundData,
97  IN_ENUM( DBMS_UPDATE ) \
98  const DBMS_UPDATE_TYPE updateType )
99  {
100  DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
101  const int commandLength = ( command != NULL ) ? strlen( command ) : 0;
102  int status;
103 
104  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
105  assert( ( command == NULL && commandLength == 0 && \
106  updateType == DBMS_UPDATE_ABORT ) || \
107  isReadPtr( command, commandLength ) );
108  assert( ( boundData == NULL ) || \
109  isReadPtr( boundData, \
110  sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS ) );
111 
112  REQUIRES( ( updateType == DBMS_UPDATE_ABORT && \
113  command == NULL && commandLength == 0 ) || \
114  ( updateType != DBMS_UPDATE_ABORT && \
115  command != NULL && \
116  commandLength > 0 && commandLength < MAX_INTLENGTH_SHORT ) );
117  REQUIRES( updateType > DBMS_UPDATE_NONE && \
118  updateType < DBMS_UPDATE_LAST );
119 
120  /* If we're trying to abort a transaction that was never begun, don't
121  do anything */
122  if( updateType == DBMS_UPDATE_ABORT && \
123  !( dbmsInfo->flags & DBMS_FLAG_UPDATEACTIVE ) )
124  return( CRYPT_OK );
125 
126  /* Process the update */
127  status = dbmsInfo->performUpdateBackend( dbmsStateInfo, command,
128  commandLength, boundData,
129  updateType );
130  if( cryptStatusOK( status ) )
131  {
132  /* If we're starting or ending an update, record the update state */
133  if( updateType == DBMS_UPDATE_BEGIN )
134  dbmsInfo->flags |= DBMS_FLAG_UPDATEACTIVE;
135  if( updateType == DBMS_UPDATE_COMMIT || \
136  updateType == DBMS_UPDATE_ABORT )
137  dbmsInfo->flags &= ~DBMS_FLAG_UPDATEACTIVE;
138  }
139  return( status );
140  }
141 
142 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
143 static int performStaticUpdate( INOUT DBMS_INFO *dbmsInfo,
144  IN_STRING const char *command )
145  {
146  return( performUpdate( dbmsInfo, command, NULL, DBMS_UPDATE_NORMAL ) );
147  }
148 
150 static int performQuery( INOUT DBMS_INFO *dbmsInfo,
151  IN_STRING_OPT const char *command,
153  void *data,
154  IN_LENGTH_SHORT_Z const int dataMaxLength,
157  TYPECAST( BOUND_DATA ) const void *boundData,
158  IN_ENUM_OPT( DBMS_CACHEDQUERY ) \
159  const DBMS_CACHEDQUERY_TYPE queryEntry,
160  IN_ENUM( DBMS_QUERY ) const DBMS_QUERY_TYPE queryType )
161  {
162  DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
163  const int commandLength = ( command != NULL ) ? strlen( command ) : 0;
164  int status;
165 
166  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
167  assert( ( command == NULL && commandLength == 0 && \
168  ( queryType == DBMS_QUERY_CONTINUE || \
169  queryType == DBMS_QUERY_CANCEL ) ) || \
170  isReadPtr( command, commandLength ) );
171  assert( ( data == NULL && dataLength == NULL ) || \
173  assert( ( boundData == NULL ) || \
174  isReadPtr( boundData, \
175  sizeof( BOUND_DATA ) * BOUND_DATA_MAXITEMS ) );
176 
177  REQUIRES( ( ( queryType == DBMS_QUERY_CONTINUE || \
178  queryType == DBMS_QUERY_CANCEL ) && \
179  command == NULL && commandLength == 0 ) || \
180  ( ( queryType == DBMS_QUERY_START || \
181  queryType == DBMS_QUERY_CHECK || \
182  queryType == DBMS_QUERY_NORMAL ) && \
183  command != NULL && \
184  commandLength > 0 && commandLength < MAX_INTLENGTH_SHORT ) );
185  REQUIRES( ( data == NULL && dataMaxLength == 0 && \
186  dataLength == NULL ) || \
187  ( data != NULL && dataMaxLength >= 16 && \
188  dataMaxLength < MAX_INTLENGTH_SHORT && \
189  dataLength != NULL ) );
190  REQUIRES( queryEntry >= DBMS_CACHEDQUERY_NONE && \
191  queryEntry < DBMS_CACHEDQUERY_LAST );
192  REQUIRES( queryType > DBMS_QUERY_NONE && \
193  queryType < DBMS_QUERY_LAST );
194 
195  /* Additional state checks: If we're starting a new query or performing
196  a point query there can't already be one active and if we're
197  continuing or cancelling an existing query there has to be one
198  already active */
199  REQUIRES( ( ( queryType == DBMS_QUERY_START || \
200  queryType == DBMS_QUERY_CHECK || \
201  queryType == DBMS_QUERY_NORMAL ) && \
202  !( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) ||
203  ( ( queryType == DBMS_QUERY_CONTINUE || \
204  queryType == DBMS_QUERY_CANCEL ) && \
205  ( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) );
206 
207  /* Clear return value */
208  if( data != NULL )
209  {
210  memset( data, 0, min( 16, dataMaxLength ) );
211  *dataLength = 0;
212  }
213 
214  /* Process the query */
215  status = dbmsInfo->performQueryBackend( dbmsStateInfo, command,
216  commandLength, data, dataMaxLength,
217  dataLength, boundData,
218  queryEntry, queryType );
219  if( cryptStatusError( status ) )
220  return( status );
221 
222  /* Sanity-check the result data from the back-end */
223  if( dataLength != NULL && \
224  ( *dataLength <= 0 || *dataLength > MAX_QUERY_RESULT_SIZE ) )
225  {
226  DEBUG_DIAG(( "Database backend return invalid data size" ));
227  assert( DEBUG_WARN );
228  memset( data, 0, min( 16, dataMaxLength ) );
229  *dataLength = 0;
230  return( CRYPT_ERROR_BADDATA );
231  }
232 
233  /* Update the state information based on the query that we've just
234  performed */
235  if( queryType == DBMS_QUERY_START )
236  dbmsInfo->flags |= DBMS_FLAG_QUERYACTIVE;
237  if( queryType == DBMS_QUERY_CANCEL )
238  dbmsInfo->flags &= ~DBMS_FLAG_QUERYACTIVE;
239  return( CRYPT_OK );
240  }
241 
243 static int performStaticQuery( INOUT DBMS_INFO *dbmsInfo,
244  IN_STRING_OPT const char *command,
245  IN_ENUM_OPT( DBMS_CACHEDQUERY ) \
246  const DBMS_CACHEDQUERY_TYPE queryEntry,
247  IN_ENUM( DBMS_QUERY ) \
248  const DBMS_QUERY_TYPE queryType )
249  {
250  return( performQuery( dbmsInfo, command, NULL, 0, NULL, NULL,
251  queryEntry, queryType ) );
252  }
253 
254 /****************************************************************************
255 * *
256 * SQL Rewrite Routines *
257 * *
258 ****************************************************************************/
259 
260 /* In order to allow general certificate database queries we have to be able
261  to process user-supplied query strings. The cryptlib manual contains
262  strong warnings about the correct way to do this (if it's done at all),
263  the best that we can do is apply assorted safety checks of the query data
264  to try and reduce the chances of SQL injection. Unfortunately this can
265  get arbitrarily complicated:
266 
267  '; The standard SQL-injection method, used with values like
268  'foo; DROP TABLE bar', or '1=1' to return all entries in a table.
269 
270  -- Comment delimiter (other values also exist, e.g. MySQL's '#') to
271  truncate queries beyond the end of the injected SQL.
272 
273  char(0xNN) Bypass the first level of filtering, e.g. char(0x41)
274  produces the banned character '.
275 
276  One additional check that we could do is to try and explicitly strip
277  SQL keywords from queries but this is somewhat problematic because apart
278  from the usual trickery (e.g. embedding one SQL keyword inside another so
279  that stripping SELECT from SELSELECTECT will still leave the outer
280  SELECT, requiring recursive stripping, or taking advantage of the fact
281  that VARBINARY values are implicitly cast to VARCHARS so that 0x42434445
282  would turn into ABCD, or further escaping the encoding with values like
283  'sel'+'ect') there are also any number of backend-specific custom
284  keywords and ways of escaping keywords that we can't know about and
285  therefore can't easily strip */
286 
287 #define SQL_ESCAPE '\''
288 
289 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
290 static int copyChar( OUT_BUFFER( bufMaxLen, *bufPos ) char *buffer,
291  IN_LENGTH_SHORT const int bufMaxLen,
292  OUT_LENGTH_SHORT_Z int *bufPos,
293  IN_BYTE const int ch, const BOOLEAN escapeQuotes )
294  {
295  int position = 0;
296 
297  assert( isWritePtr( buffer, bufMaxLen ) );
298  assert( isWritePtr( bufPos, sizeof( int ) ) );
299 
300  REQUIRES( bufMaxLen > 0 && bufMaxLen < MAX_INTLENGTH_SHORT );
301  REQUIRES( ch >= 0 && ch <= 0xFF );
302 
303  /* Clear return value */
304  *bufPos = 0;
305 
306  /* If it's a control character, skip it */
307  if( ( ch & 0x7F ) < ' ' )
308  return( CRYPT_OK );
309 
310  /* Escape metacharacters that could be misused in queries. We catch the
311  obvious ' and ; as well as the less obvious %, which could be used to
312  hide other metacharacters, and \, used by some databases (e.g. MySQL)
313  as an escape. Note that none of these characters are valid in base64,
314  which makes it safe to escape them in the few instances where they do
315  occur */
316  if( ( ch == '\'' && escapeQuotes ) || \
317  ch == '\\' || ch == ';' || ch == '%' )
318  {
319  /* Escape the character */
320  buffer[ position++ ] = SQL_ESCAPE;
321  if( position >= bufMaxLen )
322  return( CRYPT_ERROR_OVERFLOW );
323  }
324 
325  /* Bypass various dangerous SQL "enhancements". For Windows ODBC (at
326  least for MS Jet 3.x, but not 4.x any more) the driver will execute
327  anything delimited by '|'s as an expression (an example being
328  '|shell("cmd /c echo " & chr(124) & " format c:")|'), because of this
329  we strip gazintas. Since ODBC uses '{' and '}' as escape delimiters
330  we also strip these */
331  if( ch != '|' && ch != '{' && ch != '}' )
332  buffer[ position++ ] = intToByte( ch );
333 
334  /* Make sure that we haven't overflowed the output buffer. This
335  overflowing can be done deliberately, for example by using large
336  numbers of escape chars (which are in turn escaped) to force
337  truncation of the query beyond the injected SQL if the processing
338  simply stops at a given point */
339  if( position >= bufMaxLen )
340  return( CRYPT_ERROR_OVERFLOW );
341  *bufPos = position;
342 
343  return( CRYPT_OK );
344  }
345 
346 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
347 static int copyStringArg( OUT_BUFFER( bufMaxLen, *bufPos ) char *buffer,
348  IN_LENGTH_SHORT_Z const int bufMaxLen,
349  OUT_LENGTH_SHORT_Z int *bufPos,
350  IN_BUFFER( stringLen ) const char *string,
351  IN_LENGTH_SHORT const int stringLen )
352  {
353  int index, position = 0;
354 
355  assert( isWritePtr( buffer, bufMaxLen ) );
356  assert( isWritePtr( bufPos, sizeof( int ) ) );
357  assert( isReadPtr( string, stringLen ) );
358 
359  REQUIRES( bufMaxLen >= 0 && bufMaxLen < MAX_INTLENGTH_SHORT );
360  REQUIRES( stringLen > 0 && stringLen < MAX_INTLENGTH_SHORT );
361 
362  /* Make sure that there's room for at least one more character of
363  output */
364  if( bufMaxLen < 1 )
365  return( CRYPT_ERROR_OVERFLOW );
366 
367  /* Copy the string to the output buffer with conversion of any special
368  characters that are used by SQL */
369  for( index = 0; index < stringLen && \
370  index < FAILSAFE_ITERATIONS_MAX; index++ )
371  {
372  int charsWritten, status;
373 
374  status = copyChar( buffer + position, bufMaxLen - position,
375  &charsWritten, string[ index ], TRUE );
376  if( cryptStatusError( status ) )
377  return( status );
378  position += charsWritten;
379  if( position > bufMaxLen )
380  {
381  /* Already checked in copyChar() but we double-check here to be
382  safe */
383  return( CRYPT_ERROR_OVERFLOW );
384  }
385  }
386  ENSURES( index < FAILSAFE_ITERATIONS_MAX );
387  *bufPos = position;
388 
389  return( CRYPT_OK );
390  }
391 
392 /* Format input parameters into SQL queries, replacing meta-values with
393  actual column names, and null-terminate the resulting string so that
394  it can be fed to the database backend */
395 
396 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
397 int dbmsFormatQuery( OUT_BUFFER( outMaxLength, *outLength ) char *output,
398  IN_LENGTH_SHORT const int outMaxLength,
400  IN_BUFFER( inputLength ) const char *input,
401  IN_LENGTH_SHORT const int inputLength )
402  {
403  int inPos, outPos = 0, status = CRYPT_OK;
404 
405  assert( isWritePtr( output, outMaxLength ) );
406  assert( isWritePtr( outLength, sizeof( int ) ) );
407  assert( isReadPtr( input, inputLength ) );
408 
409  REQUIRES( outMaxLength >= 0 && outMaxLength < MAX_INTLENGTH_SHORT );
410  REQUIRES( inputLength > 0 && inputLength < MAX_INTLENGTH_SHORT );
411 
412  /* Clear return values */
413  memset( output, 0, min( 16, outMaxLength ) );
414  *outLength = 0;
415 
416  for( inPos = 0; inPos < inputLength && inPos < FAILSAFE_ITERATIONS_MAX; )
417  {
418  int length;
419 
420  if( input[ inPos ] == '$' )
421  {
422  typedef struct {
424  char *sourceName;
425  int sourceLength;
427  char *destName;
428  int destLength;
429  } NAMEMAP_INFO;
430  static const NAMEMAP_INFO nameMapTbl[] = {
431  { "C", 1, "C", 1 }, { "SP", 2, "SP", 2 },
432  { "L", 1, "L", 1 }, { "O", 1, "O", 1 },
433  { "OU", 2, "OU", 2 }, { "CN", 2, "CN", 2 },
434  { "email", 5, "email", 5 }, { "uri", 3, "email", 5 },
435  { "date", 4, "validTo", 7 },
436  { NULL, 0, NULL, 0 }, { NULL, 0, NULL, 0 }
437  };
438  const int fieldPos = inPos + 1;
439  const char *fieldName = input + fieldPos;
440  int i;
441 
442  inPos++; /* Skip '$' */
443 
444  /* Extract the field name and translate it into the table
445  column name */
446  while( inPos < inputLength && isAlpha( input[ inPos ] ) )
447  inPos++;
448  length = inPos - fieldPos;
449  if( length <= 0 || length > 5 )
450  {
451  status = CRYPT_ERROR_BADDATA;
452  break;
453  }
454  for( i = 0; nameMapTbl[ i ].sourceName != NULL && \
455  i < FAILSAFE_ARRAYSIZE( nameMapTbl, NAMEMAP_INFO );
456  i++ )
457  {
458  if( length == nameMapTbl[ i ].sourceLength && \
459  !strCompare( fieldName, nameMapTbl[ i ].sourceName, \
460  length ) )
461  break;
462  }
463  ENSURES( i < FAILSAFE_ARRAYSIZE( nameMapTbl, NAMEMAP_INFO ) );
464  if( nameMapTbl[ i ].sourceName == NULL )
465  {
466  status = CRYPT_ERROR_BADDATA;
467  break;
468  }
469 
470  /* Copy the translated name to the output buffer */
471  status = copyStringArg( output + outPos, outMaxLength - outPos,
472  &length, nameMapTbl[ i ].destName,
473  nameMapTbl[ i ].destLength );
474  }
475  else
476  {
477  /* Just copy the character over, with a length check. We don't
478  escape single quotes in this case because we use these
479  ourselves in SQL queries */
480  status = copyChar( output + outPos, outMaxLength - outPos,
481  &length, input[ inPos++ ], FALSE );
482  }
483  if( cryptStatusError( status ) )
484  break;
485  outPos += length;
486  }
487  ENSURES( inPos < FAILSAFE_ITERATIONS_MAX );
488  if( cryptStatusError( status ) )
489  outPos = 0;
490  output[ outPos ] = '\0'; /* Add der terminador */
491  *outLength = outPos;
492 
493  return( status );
494  }
495 
496 /****************************************************************************
497 * *
498 * Back-end Interface Routines *
499 * *
500 ****************************************************************************/
501 
502 /* Parse a user-supplied database name into individual components, used by
503  the database back-end connect functions. We don't do a syntax check
504  (since the exact syntax is database-specific) but merely break the single
505  string up into any recognisable components. The database back-end can
506  determine whether the format is valid or not. The general format that we
507  look for is:
508 
509  [generic name]
510  user:pass
511  user@server
512  user:pass@server
513  user:pass@server/name
514 
515  One distinction that we make is that if there's something after an '@'
516  and there's no server/name separator present we treat it as a name rather
517  than a server. In other words @foo results in name=foo while @foo/bar
518  results in server=foo, name=bar. This is because the most common
519  situation that we have to handle is ODBC, which identifies the database
520  by name rather than by server */
521 
522 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
523 int dbmsParseName( INOUT DBMS_NAME_INFO *nameInfo,
524  IN_BUFFER( nameLen ) const char *name,
525  IN_LENGTH_NAME const int nameLen )
526  {
527  int offset, offset2, length;
528 
529  assert( isWritePtr( nameInfo, sizeof( DBMS_NAME_INFO ) ) );
530  assert( isReadPtr( name, nameLen ) );
531 
532  REQUIRES( nameLen >= MIN_NAME_LENGTH && \
533  nameLen < MAX_ATTRIBUTE_SIZE );
534 
535  memset( nameInfo, 0, sizeof( DBMS_NAME_INFO ) );
536 
537  /* Check for a complex database name */
538  if( ( offset = strFindCh( name, nameLen, ':' ) ) < 0 && \
539  ( offset = strFindCh( name, nameLen, '@' ) ) < 0 )
540  {
541  /* It's a straightforward name, use it directly */
542  nameInfo->name = ( char * ) name;
543  nameInfo->nameLen = nameLen;
544 
545  return( CRYPT_OK );
546  }
547 
548  /* Extract the user name */
549  length = min( offset, CRYPT_MAX_TEXTSIZE );
550  if( length <= 0 )
551  return( CRYPT_ERROR_OPEN );
552  memcpy( nameInfo->userBuffer, name, length );
553  nameInfo->user = nameInfo->userBuffer;
554  nameInfo->userLen = length;
555 
556  /* We're either at the server name or password, extract the password
557  if there is one */
558  ENSURES( name[ offset ] == ':' || name[ offset ] == '@' );
559  if( name[ offset++ ] == ':' )
560  {
561  offset2 = strFindCh( name + offset, nameLen - offset, '@' );
562  if( offset2 < 0 )
563  offset2 = nameLen - offset; /* Password is rest of string */
564  length = min( offset2, CRYPT_MAX_TEXTSIZE );
565  if( length <= 0 )
566  return( CRYPT_ERROR_OPEN );
567  memcpy( nameInfo->passwordBuffer, name + offset, length );
568  nameInfo->password = nameInfo->passwordBuffer;
569  nameInfo->passwordLen = length;
570  offset += offset2 + 1;
571  if( offset >= nameLen )
572  return( CRYPT_OK );
573  }
574 
575  /* Separate the server and database name if necessary */
576  offset2 = strFindCh( name + offset, nameLen - offset, '/' );
577  if( offset2 >= 0 )
578  {
579  /* There's a distinction between the server name and database name,
580  extract the server name */
581  length = min( offset2, CRYPT_MAX_TEXTSIZE );
582  if( length <= 0 )
583  return( CRYPT_ERROR_OPEN );
584  memcpy( nameInfo->serverBuffer, name + offset, length );
585  nameInfo->server = nameInfo->serverBuffer;
586  nameInfo->serverLen = length;
587  offset += offset2 + 1;
588  }
589 
590  /* Extract the database name if there is one */
591  if( offset < nameLen )
592  {
593  length = nameLen - offset;
594  if( length <= 0 || length > CRYPT_MAX_TEXTSIZE )
595  return( CRYPT_ERROR_OPEN );
596  memcpy( nameInfo->nameBuffer, name + offset, length );
597  nameInfo->name = nameInfo->nameBuffer;
598  nameInfo->nameLen = length;
599  }
600 
601  return( CRYPT_OK );
602  }
603 
604 /* Initialise and shut down a session with a database back-end */
605 
607 int initDbxSession( INOUT KEYSET_INFO *keysetInfoPtr,
609  {
610  DBMS_INFO *dbmsInfo = keysetInfoPtr->keysetDBMS;
611  int status = CRYPT_ERROR;
612 
613  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
614 
615  REQUIRES( keysetInfoPtr->type == KEYSET_DBMS );
616  REQUIRES( type > CRYPT_KEYSET_NONE && type < CRYPT_KEYSET_LAST );
617 
618  /* Select the appropriate dispatch function for the keyset type */
619  switch( type )
620  {
621  case CRYPT_KEYSET_ODBC:
623  status = initDispatchODBC( dbmsInfo );
624  break;
625 
628  status = initDispatchDatabase( dbmsInfo );
629  break;
630 
631  default:
632  retIntError();
633  }
634  if( cryptStatusError( status ) )
635  return( CRYPT_ARGERROR_NUM1 );
636 
637  /* Set up the remaining function pointers */
638  dbmsInfo->openDatabaseFunction = openDatabase;
639  dbmsInfo->closeDatabaseFunction = closeDatabase;
640  dbmsInfo->performUpdateFunction = performUpdate;
641  dbmsInfo->performStaticUpdateFunction = performStaticUpdate;
642  dbmsInfo->performQueryFunction = performQuery;
643  dbmsInfo->performStaticQueryFunction = performStaticQuery;
644 
645  /* Allocate the database session state information */
646  if( ( keysetInfoPtr->keyData = \
647  clAlloc( "initDbxSession", sizeof( DBMS_STATE_INFO ) ) ) == NULL )
648  return( CRYPT_ERROR_MEMORY );
649  memset( keysetInfoPtr->keyData, 0, sizeof( DBMS_STATE_INFO ) );
650  keysetInfoPtr->keyDataSize = sizeof( DBMS_STATE_INFO );
651  dbmsInfo->stateInfo = keysetInfoPtr->keyData;
652  if( type == CRYPT_KEYSET_ODBC_STORE || \
655 
656  return( CRYPT_OK );
657  }
658 
659 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
660 int endDbxSession( INOUT KEYSET_INFO *keysetInfoPtr )
661  {
662  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
663 
664  REQUIRES( keysetInfoPtr->type == KEYSET_DBMS );
665 
666  /* Free the database session state information if necessary */
667  if( keysetInfoPtr->keyData != NULL )
668  {
669  memset( keysetInfoPtr->keyData, 0, keysetInfoPtr->keyDataSize );
670  clFree( "endDbxSession", keysetInfoPtr->keyData );
671  keysetInfoPtr->keyData = NULL;
672  }
673 
674  return( CRYPT_OK );
675  }
676 #endif /* USE_DBMS */