📄 dbms.c
字号:
/* Dispatch the command */
memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) );
DISPATCH_COMMAND_DBX( cmdClose, cmd, dbmsInfo );
}
static void performErrorQuery( DBMS_INFO *dbmsInfo )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_GETERRORINFO, COMMAND_FLAG_NONE, 0, 1 };
COMMAND_INFO cmd;
int status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
/* 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 = DISPATCH_COMMAND_DBX( cmdGetErrorInfo, cmd, dbmsInfo );
if( cryptStatusOK( status ) )
{
dbmsInfo->errorCode = cmd.arg[ 0 ];
dbmsInfo->errorMessage[ cmd.strArgLen[ 0 ] ] = '\0';
}
}
static int performUpdate( DBMS_INFO *dbmsInfo, const char *command,
const void *boundData, const int boundDataLength,
const time_t boundDate,
const DBMS_UPDATE_TYPE updateType )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_UPDATE, COMMAND_FLAG_NONE, 1, 1 };
COMMAND_INFO cmd;
BYTE encodedDate[ 8 ];
int status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( updateType > DBMS_UPDATE_NONE && \
updateType < DBMS_UPDATE_LAST );
/* If we're trying to abort a transaction that was never begun, don't
do anything */
if( updateType == DBMS_UPDATE_ABORT && \
!( dbmsInfo->flags & DBMS_FLAG_UPDATEACTIVE ) )
return( CRYPT_OK );
/* Dispatch the command */
initQueryData( &cmd, &cmdTemplate, encodedDate, dbmsInfo, command,
boundData, boundDataLength, boundDate, updateType );
status = DISPATCH_COMMAND_DBX( cmdUpdate, cmd, dbmsInfo );
if( cryptStatusError( status ) )
performErrorQuery( dbmsInfo );
else
{
/* If we're starting or ending an update, record the update state */
if( updateType == DBMS_UPDATE_BEGIN )
dbmsInfo->flags |= DBMS_FLAG_UPDATEACTIVE;
if( updateType == DBMS_UPDATE_COMMIT || \
updateType == DBMS_UPDATE_ABORT )
dbmsInfo->flags &= ~DBMS_FLAG_UPDATEACTIVE;
}
return( status );
}
static int performStaticUpdate( DBMS_INFO *dbmsInfo, const char *command )
{
return( performUpdate( dbmsInfo, command, NULL, 0, 0,
DBMS_UPDATE_NORMAL ) );
}
static int performQuery( DBMS_INFO *dbmsInfo, const char *command,
char *data, int *dataLength, const char *queryData,
const int queryDataLength, const time_t queryDate,
const DBMS_CACHEDQUERY_TYPE queryEntry,
const DBMS_QUERY_TYPE queryType )
{
static const COMMAND_INFO cmdTemplate = \
{ DBX_COMMAND_QUERY, COMMAND_FLAG_NONE, 2, 1 };
COMMAND_INFO cmd;
BYTE encodedDate[ 8 ];
int argIndex, status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( ( data == NULL && dataLength == NULL ) || \
isWritePtr( data, 16 ) );
assert( ( queryData == NULL && queryDataLength == 0 ) || \
( queryDataLength > 0 && \
isReadPtr( queryData, queryDataLength ) ) );
assert( DBMS_CACHEDQUERY_NONE >= 0 && \
queryEntry < DBMS_CACHEDQUERY_LAST );
assert( queryType > DBMS_QUERY_NONE && queryType < DBMS_QUERY_LAST );
/* Additional state checks: If we're starting a new query or performing
a point query there can't already be one active, and if we're
continuing or cancelling an existing query there has to be one
already active */
assert( ( ( queryType == DBMS_QUERY_START || \
queryType == DBMS_QUERY_CHECK || \
queryType == DBMS_QUERY_NORMAL ) && \
!( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) ||
( ( queryType == DBMS_QUERY_CONTINUE || \
queryType == DBMS_QUERY_CANCEL ) && \
( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) );
/* Clear return value */
if( data != NULL )
{
memset( data, 0, 16 );
*dataLength = 0;
}
/* Dispatch the command */
argIndex = initQueryData( &cmd, &cmdTemplate, encodedDate, dbmsInfo,
command, queryData, queryDataLength,
queryDate, queryType );
cmd.arg[ 1 ] = queryEntry;
cmd.strArg[ argIndex ] = data;
cmd.strArgLen[ argIndex ] = 0;
cmd.noStrArgs = argIndex + 1;
status = DISPATCH_COMMAND_DBX( cmdQuery, cmd, dbmsInfo );
if( cryptStatusError( status ) )
{
performErrorQuery( dbmsInfo );
return( status );
}
/* Update the state information based on the query we've just
performed */
if( queryType == DBMS_QUERY_START )
dbmsInfo->flags |= DBMS_FLAG_QUERYACTIVE;
if( queryType == DBMS_QUERY_CANCEL )
dbmsInfo->flags &= ~DBMS_FLAG_QUERYACTIVE;
if( dataLength != NULL )
{
*dataLength = cmd.strArgLen[ argIndex ];
if( *dataLength <= 0 || *dataLength > MAX_QUERY_RESULT_SIZE )
{
assert( NOTREACHED );
memset( data, 0, 16 );
*dataLength = 0;
return( CRYPT_ERROR_BADDATA );
}
}
return( CRYPT_OK );
}
static int performStaticQuery( DBMS_INFO *dbmsInfo, const char *command,
const DBMS_CACHEDQUERY_TYPE queryEntry,
const DBMS_QUERY_TYPE queryType )
{
return( performQuery( dbmsInfo, command, NULL, NULL, NULL, 0, 0,
queryEntry, queryType ) );
}
#else
/* Database access functions */
static int openDatabase( DBMS_INFO *dbmsInfo, const char *name,
const int options, int *featureFlags )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
int status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( isReadPtr( name, 2 ) );
assert( isWritePtr( featureFlags, sizeof( int ) ) );
/* Clear return value */
*featureFlags = DBMS_HAS_NONE;
status = dbmsInfo->openDatabaseBackend( dbmsStateInfo, name, options,
featureFlags );
if( cryptStatusError( status ) )
return( status );
/* Make long-term information returned as a back-end interface-specific
feature flags persistent if necessary */
if( *featureFlags & DBMS_HAS_BINARYBLOBS )
dbmsInfo->flags |= DBMS_FLAG_BINARYBLOBS;
return( status );
}
static void closeDatabase( DBMS_INFO *dbmsInfo )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
dbmsInfo->closeDatabaseBackend( dbmsStateInfo );
}
static void performErrorQuery( DBMS_INFO *dbmsInfo )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
/* Clear the return values */
memset( dbmsInfo->errorMessage, 0, MAX_ERRMSG_SIZE );
dbmsInfo->errorCode = 0;
dbmsInfo->performErrorQueryBackend( dbmsStateInfo, &dbmsInfo->errorCode,
dbmsInfo->errorMessage );
}
static int performUpdate( DBMS_INFO *dbmsInfo, const char *command,
const void *boundData, const int boundDataLength,
const time_t boundDate,
const DBMS_UPDATE_TYPE updateType )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
int status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( updateType > DBMS_UPDATE_NONE && \
updateType < DBMS_UPDATE_LAST );
/* If we're trying to abort a transaction that was never begun, don't
do anything */
if( updateType == DBMS_UPDATE_ABORT && \
!( dbmsInfo->flags & DBMS_FLAG_UPDATEACTIVE ) )
return( CRYPT_OK );
/* Process the update */
status = dbmsInfo->performUpdateBackend( dbmsStateInfo, command,
boundData, boundDataLength,
boundDate, updateType );
if( cryptStatusError( status ) )
performErrorQuery( dbmsInfo );
else
{
/* If we're starting or ending an update, record the update state */
if( updateType == DBMS_UPDATE_BEGIN )
dbmsInfo->flags |= DBMS_FLAG_UPDATEACTIVE;
if( updateType == DBMS_UPDATE_COMMIT || \
updateType == DBMS_UPDATE_ABORT )
dbmsInfo->flags &= ~DBMS_FLAG_UPDATEACTIVE;
}
return( status );
}
static int performStaticUpdate( DBMS_INFO *dbmsInfo, const char *command )
{
return( performUpdate( dbmsInfo, command, NULL, 0, 0,
DBMS_UPDATE_NORMAL ) );
}
static int performQuery( DBMS_INFO *dbmsInfo, const char *command,
char *data, int *dataLength, const char *queryData,
const int queryDataLength, const time_t queryDate,
const DBMS_CACHEDQUERY_TYPE queryEntry,
const DBMS_QUERY_TYPE queryType )
{
DBMS_STATE_INFO *dbmsStateInfo = dbmsInfo->stateInfo;
int status;
assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
assert( ( data == NULL && dataLength == NULL ) || \
isWritePtr( data, MAX_QUERY_RESULT_SIZE ) );
assert( ( queryData == NULL && queryDataLength == 0 ) || \
( queryDataLength > 0 && \
isReadPtr( queryData, queryDataLength ) ) );
assert( DBMS_CACHEDQUERY_NONE >= 0 && \
queryEntry < DBMS_CACHEDQUERY_LAST );
assert( queryType > DBMS_QUERY_NONE && queryType < DBMS_QUERY_LAST );
/* Additional state checks: If we're starting a new query or performing
a point query there can't already be one active, and if we're
continuing or cancelling an existing query there has to be one
already active */
assert( ( ( queryType == DBMS_QUERY_START || \
queryType == DBMS_QUERY_CHECK || \
queryType == DBMS_QUERY_NORMAL ) && \
!( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) ||
( ( queryType == DBMS_QUERY_CONTINUE || \
queryType == DBMS_QUERY_CANCEL ) && \
( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE ) ) );
/* Clear return value */
if( data != NULL )
{
memset( data, 0, 16 );
*dataLength = 0;
}
/* Process the query */
status = dbmsInfo->performQueryBackend( dbmsStateInfo, command, data,
dataLength, queryData,
queryDataLength, queryDate,
queryEntry, queryType );
if( cryptStatusError( status ) )
{
performErrorQuery( dbmsInfo );
return( status );
}
/* Sanity-check the result data from the back-end */
if( dataLength != NULL && \
( *dataLength <= 0 || *dataLength > MAX_QUERY_RESULT_SIZE ) )
{
assert( NOTREACHED );
memset( data, 0, 16 );
*dataLength = 0;
return( CRYPT_ERROR_BADDATA );
}
/* Update the state information based on the query we've just
performed */
if( queryType == DBMS_QUERY_START )
dbmsInfo->flags |= DBMS_FLAG_QUERYACTIVE;
if( queryType == DBMS_QUERY_CANCEL )
dbmsInfo->flags &= ~DBMS_FLAG_QUERYACTIVE;
return( CRYPT_OK );
}
static int performStaticQuery( DBMS_INFO *dbmsInfo, const char *command,
const DBMS_CACHEDQUERY_TYPE queryEntry,
const DBMS_QUERY_TYPE queryType )
{
return( performQuery( dbmsInfo, command, NULL, NULL, NULL, 0, 0,
queryEntry, queryType ) );
}
#endif /* USE_RPCAPI */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* The escape char used to escape potentially dangerous values in SQL
strings */
#define SQL_ESCAPE '\''
/* Format input parameters into SQL queries suitable for submission to the
DBMS back-end, with assorted safety checks of the query data. One
additional check that we could do is to try and explicitly strip SQL
keywords from queries, but this is somewhat problematic because apart
from the usual trickery (e.g. embedding one SQL keyword inside another
so that stripping SELECT from SELSELECTECT will still leave the outer
SELECT) there are also any number of backend-specific custom keywords
and ways of escaping keywords that we can't know about and therefore
can't easily strip. Since we're using parameterised queries wherever
possible the following stripping is really just belt-and-suspenders
security */
void dbmsFormatSQL( char *buffer, const char *format, ... )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -