📄 lib_dbms.c
字号:
putMessageWord( bufPtr, argLength );
if( argLength > 0 )
memcpy( bufPtr + COMMAND_WORDSIZE, sentCmd.strArg[ i ],
argLength );
bufPtr += COMMAND_WORDSIZE + argLength;
}
/* Send the command to the server and read the server's message header */
dispatchFunction( stateInfo, buffer );
memcpy( header, buffer, COMMAND_FIXED_DATA_SIZE );
/* Process the fixed message header and make sure it's valid */
getMessageType( header, cmd->type, cmd->flags,
cmd->noArgs, cmd->noStrArgs );
resultLength = getMessageLength( header + COMMAND_WORDSIZE );
if( !dbxCheckCommandInfo( cmd, resultLength ) || \
cmd->type != COMMAND_RESULT )
return( CRYPT_ERROR );
if( ( cmd->noStrArgs && cmd->strArgLen[ 0 ] ) && \
( sentCmd.type != DBX_COMMAND_QUERY && \
sentCmd.type != DBX_COMMAND_GETERRORINFO ) )
/* Only these commands can return data */
return( CRYPT_ERROR );
/* Read the rest of the server's message */
bufPtr = buffer + COMMAND_FIXED_DATA_SIZE;
for( i = 0; i < cmd->noArgs; i++ )
{
cmd->arg[ i ] = getMessageWord( bufPtr );
bufPtr += COMMAND_WORDSIZE;
}
for( i = 0; i < cmd->noStrArgs; i++ )
{
cmd->strArgLen[ i ] = getMessageWord( bufPtr );
cmd->strArg[ i ] = bufPtr + COMMAND_WORDSIZE;
bufPtr += COMMAND_WORDSIZE + cmd->strArgLen[ i ];
}
/* The first value returned is the status code, if it's nonzero return
it to the caller, otherwise move the other values down */
if( cryptStatusError( cmd->arg[ 0 ] ) )
return( cmd->arg[ 0 ] );
assert( cryptStatusOK( cmd->arg[ 0 ] ) );
for( i = 1; i < cmd->noArgs; i++ )
cmd->arg[ i - 1 ] = cmd->arg[ i ];
cmd->arg[ i ] = 0;
cmd->noArgs--;
/* Copy any string arg data back to the caller */
if( cmd->noStrArgs && cmd->strArgLen[ 0 ] )
{
const int maxBufSize = ( sentCmd.type == DBX_COMMAND_QUERY ) ? \
MAX_QUERY_RESULT_SIZE : MAX_ERRMSG_SIZE;
const int argIndex = sentCmd.noStrArgs;
memcpy( sentCmd.strArg[ argIndex ], cmd->strArg[ 0 ],
min( cmd->strArgLen[ 0 ], maxBufSize ) );
cmd->strArg[ 0 ] = sentCmd.strArg[ argIndex ];
}
return( CRYPT_OK );
}
/* Database access functions */
static int openDatabase( DBMS_INFO *dbmsInfo, const char *name,
const char *server, const char *user,
const char *password, const int options )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_OPEN, COMMAND_FLAG_NONE, 1, 1 };
COMMAND_INFO cmd;
int status;
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
cmd.arg[ 0 ] = options;
cmd.strArg[ 0 ] = ( void * ) name;
cmd.strArgLen[ 0 ] = strlen( name );
status = dispatchCommand( &cmd, dbmsInfo->stateInfo,
dbmsInfo->dispatchFunction );
if( cryptStatusOK( status ) )
dbmsInfo->hasBinaryBlobs = ( cmd.arg[ 0 ] & DBMS_FLAG_BINARYBLOBS ) ? \
TRUE : FALSE;
return( status );
}
static void closeDatabase( DBMS_INFO *dbmsInfo )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_CLOSE, COMMAND_FLAG_NONE, 0, 0 };
COMMAND_INFO cmd;
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
dispatchCommand( &cmd, dbmsInfo->stateInfo, dbmsInfo->dispatchFunction );
}
static void performErrorQuery( DBMS_INFO *dbmsInfo )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_GETERRORINFO, COMMAND_FLAG_NONE, 0, 0 };
COMMAND_INFO cmd;
int status;
/* Clear the return values */
memset( dbmsInfo->errorMessage, 0, MAX_ERRMSG_SIZE );
*dbmsInfo->errorCode = 0;
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
cmd.strArg[ 0 ] = dbmsInfo->errorMessage;
cmd.strArgLen[ 0 ] = 0;
status = dispatchCommand( &cmd, dbmsInfo->stateInfo,
dbmsInfo->dispatchFunction );
if( cryptStatusOK( status ) )
{
*dbmsInfo->errorCode = cmd.arg[ 0 ];
dbmsInfo->errorMessage[ cmd.strArgLen[ 0 ] ] = '\0';
}
}
static int performUpdate( DBMS_INFO *dbmsInfo, const char *command,
const BOOLEAN hasBoundData,
const time_t boundDate,
const DBMS_UPDATE_TYPE updateType )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_UPDATE, COMMAND_FLAG_NONE, 1, 0 };
COMMAND_INFO cmd;
BYTE encodedDate[ 8 ];
int argIndex = 1, status;
/* If we're trying to abort a transaction which was never begun, don't
do anything */
if( updateType == DBMS_UPDATE_ABORT && !dbmsInfo->updateActive )
return( CRYPT_OK );
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
cmd.arg[ 0 ] = updateType;
if( command != NULL )
{
cmd.noStrArgs = 1;
cmd.strArg[ 0 ] = ( void * ) command;
cmd.strArgLen[ 0 ] = strlen( command );
}
if( boundDate )
{
#ifndef _BIG_WORDS
assert( sizeof( time_t ) <= 4 );
#endif /* !_BIG_WORDS */
/* Encode the date as a 64-bit value */
memset( encodedDate, 0, 8 );
#ifdef _BIG_WORDS
encodedDate[ 3 ] = ( BYTE )( ( boundDate >> 32 ) & 0xFF );
#endif /* _BIG_WORDS */
encodedDate[ 4 ] = ( BYTE )( ( boundDate >> 24 ) & 0xFF );
encodedDate[ 5 ] = ( BYTE )( ( boundDate >> 16 ) & 0xFF );
encodedDate[ 6 ] = ( BYTE )( ( boundDate >> 8 ) & 0xFF );
encodedDate[ 7 ] = ( BYTE )( ( boundDate ) & 0xFF );
cmd.noStrArgs++;
cmd.strArg[ argIndex ] = encodedDate;
cmd.strArgLen[ argIndex++ ] = 8;
}
if( hasBoundData )
{
cmd.noStrArgs++;
cmd.strArg[ argIndex ] = dbmsInfo->boundCertData;
cmd.strArgLen[ argIndex++ ] = dbmsInfo->boundCertDataLen;
}
status = dispatchCommand( &cmd, dbmsInfo->stateInfo,
dbmsInfo->dispatchFunction );
if( cryptStatusError( status ) )
performErrorQuery( dbmsInfo );
else
{
/* If we're starting or ending an update, record the update state */
if( updateType == DBMS_UPDATE_BEGIN )
dbmsInfo->updateActive = TRUE;
if( updateType == DBMS_UPDATE_COMMIT || \
updateType == DBMS_UPDATE_ABORT )
dbmsInfo->updateActive = FALSE;
}
return( status );
}
static int performStaticUpdate( DBMS_INFO *dbmsInfo, const char *command )
{
return( performUpdate( dbmsInfo, command, FALSE, 0,
DBMS_UPDATE_NORMAL ) );
}
static int performQuery( DBMS_INFO *dbmsInfo, const char *command,
char *data, int *dataLength, const time_t date,
const DBMS_QUERY_TYPE queryType )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_QUERY, COMMAND_FLAG_NONE, 1, 1 };
COMMAND_INFO cmd;
BYTE encodedDate[ 8 ];
int argIndex = 1, status;
/* Clear return value */
if( data != NULL )
{
memset( data, 0, 16 );
*dataLength = -1;
}
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
cmd.arg[ 0 ] = queryType;
if( command != NULL )
{
cmd.strArg[ 0 ] = ( void * ) command;
cmd.strArgLen[ 0 ] = strlen( command );
}
else
{
cmd.noStrArgs = 0;
argIndex = 0;
}
if( date )
{
#ifndef _BIG_WORDS
assert( sizeof( time_t ) <= 4 );
#endif /* !_BIG_WORDS */
/* Encode the date as a 64-bit value */
memset( encodedDate, 0, 8 );
#ifdef _BIG_WORDS
encodedDate[ 3 ] = ( BYTE )( ( date >> 32 ) & 0xFF );
#endif /* _BIG_WORDS */
encodedDate[ 4 ] = ( BYTE )( ( date >> 24 ) & 0xFF );
encodedDate[ 5 ] = ( BYTE )( ( date >> 16 ) & 0xFF );
encodedDate[ 6 ] = ( BYTE )( ( date >> 8 ) & 0xFF );
encodedDate[ 7 ] = ( BYTE )( ( date ) & 0xFF );
cmd.strArg[ 1 ] = encodedDate;
cmd.strArgLen[ 1 ] = 8;
cmd.noStrArgs++;
argIndex++;
}
cmd.strArg[ argIndex ] = data;
cmd.strArgLen[ argIndex ] = 0;
status = dispatchCommand( &cmd, dbmsInfo->stateInfo,
dbmsInfo->dispatchFunction );
if( cryptStatusOK( status ) )
{
if( dataLength != NULL )
*dataLength = cmd.strArgLen[ 0 ];
}
else
performErrorQuery( dbmsInfo );
return( status );
}
static int performStaticQuery( DBMS_INFO *dbmsInfo, const char *command,
const DBMS_QUERY_TYPE queryType )
{
return( performQuery( dbmsInfo, command, NULL, NULL, 0, queryType ) );
}
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Format input parameters into SQL queries suitable for submission to the
DBMS backend. We could use sprintf() but there are problems with
potential buffer overruns for long args, so we use the following function
which acts as a (very minimal) string formatter in which all '$'s in the
input are replaced by the next input string */
static void formatSQL( char *buffer, const char *format, ... )
{
va_list argPtr;
char *formatPtr = ( char * ) format;
int bufPos = 0;
va_start( argPtr, format );
while( *formatPtr )
{
if( *formatPtr == '$' )
{
char *strPtr = va_arg( argPtr, char * );
assert( strPtr != NULL ); /* Catch a shortage of args */
/* Copy the string to the output buffer with conversion of any
special characters which are used by SQL */
while( *strPtr )
{
int ch = *strPtr++;
/* If it's a control character, skip it */
if( ( ch & 0x7F ) < ' ' )
continue;
/* Escape metacharacters which could be misused in queries,
for example by specifying a key 'foo; DROP TABLE bar' or
similar shenanigans. We catch the obvious ' and ;, as
well as the less obvious %, which could be used to hide
other metacharacters. Note that none of these characters
are valid in base64, which makes it safe to escape them
in the few instances where they do occur */
if( ch == '\'' || ch == '\\' || ch == ';' || ch == '%' )
/* Escape the character */
buffer[ bufPos++ ] = '\'';
#ifdef __WINDOWS__
/* Bypass a Microsoft ODBC "enhancement" in which the driver
will execute anything delimited by '|'s as an expression
(an example being '|shell("cmd /c echo " & chr(124) &
" format c:")|'). Because of this we strip gazintas if
we're running under Windoze */
if( ch != '|' )
#endif /* __WINDOWS__ */
buffer[ bufPos++ ] = ch;
/* Make sure we haven't overflowed the input buffer. We
check for MAX_SQL_QUERY_SIZE - 3 rather than
MAX_SQL_QUERY_SIZE - 2 in case the next character needs
escaping which expands it to two chars (MAX_SQL_QUERY_SIZE
- 1 is used for the '\0') */
if( bufPos > MAX_SQL_QUERY_SIZE - 3 )
{
bufPos = 0;
formatPtr = ""; /* Force exit on outer loop */
break;
}
}
formatPtr++;
}
else
{
/* Just copy the char over, with a length check */
if( bufPos > MAX_SQL_QUERY_SIZE - 1 )
{
bufPos = 0;
break;
}
buffer[ bufPos++ ] = *formatPtr++;
}
}
buffer[ bufPos++ ] = '\0'; /* Add der terminador */
va_end( argPtr );
}
/* Format input parameters into SQL queries, replacing meta-values with
actual column names */
static int formatQuery( char *output, const char *input, const int inputLength,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -