📄 dbx_rpc.c
字号:
/****************************************************************************
* *
* cryptlib Database RPC Interface *
* Copyright Peter Gutmann 1997-2004 *
* *
****************************************************************************/
/* This file isn't a standalone module but is meant to be #included into
whichever of the database client files that it's used with */
#ifdef USE_RPCAPI
/* Set up query data so it can be sent to the database back-end */
static void extractQueryData( COMMAND_INFO *cmd, time_t *timeValuePtrPtr,
void **dataValuePtrPtr,
int *dataValueLengthPtr )
{
/* Clear return values */
*timeValuePtrPtr = 0;
*dataValuePtrPtr = NULL;
*dataValueLengthPtr = 0;
/* If there's only one string arg present (the command), we're done */
if( cmd->noStrArgs < 2 )
return;
/* If one of the string args is a bound date, convert it into a time_t */
if( cmd->strArgLen[ 1 ] == 8 )
{
const BYTE *timeValuePtr = cmd->strArg[ 1 ];
/* Extract the time_t from the 64-bit time value */
*timeValuePtrPtr = ( time_t ) timeValuePtr[ 4 ] << 24 | \
( time_t ) timeValuePtr[ 5 ] << 16 | \
( time_t ) timeValuePtr[ 6 ] << 8 | \
( time_t ) timeValuePtr[ 7 ];
#ifdef _BIG_WORDS
*timeValuePtrPtr |= ( time_t ) timeValuePtr[ 3 ] << 32;
#endif /* _BIG_WORDS */
/* Since the first arg is the date, the data (if any) will be in
the second arg */
if( cmd->strArgLen[ 2 ] > 0 )
{
*dataValuePtrPtr = cmd->strArg[ 2 ];
*dataValueLengthPtr = cmd->strArgLen[ 2 ];
}
return;
}
/* There's only one string arg present, which is the data */
if( cmd->strArgLen[ 1 ] > 0 )
{
*dataValuePtrPtr = cmd->strArg[ 1 ];
*dataValueLengthPtr = cmd->strArgLen[ 1 ];
}
}
/* Handlers for the various commands */
int cmdClose( void *stateInfo, COMMAND_INFO *cmd )
{
assert( cmd->type == DBX_COMMAND_CLOSE );
assert( cmd->flags == COMMAND_FLAG_NONE );
assert( cmd->noArgs == 0 );
assert( cmd->noStrArgs == 0 );
closeDatabase( stateInfo );
return( CRYPT_OK );
}
int cmdGetErrorInfo( void *stateInfo, COMMAND_INFO *cmd )
{
assert( cmd->type == DBX_COMMAND_GETERRORINFO );
assert( cmd->flags == COMMAND_FLAG_NONE );
assert( cmd->noArgs == 0 );
assert( cmd->noStrArgs == 1 );
performErrorQuery( stateInfo, &cmd->arg[ 0 ], cmd->strArg[ 0 ] );
cmd->strArgLen[ 0 ] = strlen( cmd->strArg[ 0 ] );
return( CRYPT_OK );
}
int cmdOpen( void *stateInfo, COMMAND_INFO *cmd )
{
int hasBinaryBlobs, status;
assert( cmd->type == DBX_COMMAND_OPEN );
assert( cmd->flags == COMMAND_FLAG_NONE );
assert( cmd->noArgs == 1 );
assert( cmd->arg[ 0 ] >= CRYPT_KEYOPT_NONE && \
cmd->arg[ 0 ] < CRYPT_KEYOPT_LAST );
assert( cmd->noStrArgs == 1 );
status = openDatabase( stateInfo, cmd->strArg[ 0 ], cmd->arg[ 0 ],
&hasBinaryBlobs );
if( cryptStatusOK( status ) )
cmd->arg[ 0 ] = hasBinaryBlobs;
return( status );
}
int cmdQuery( void *stateInfo, COMMAND_INFO *cmd )
{
const int argIndex = cmd->noStrArgs - 1;
void *dataValue;
time_t timeValue;
int dataValueLength, dataLength, status;
assert( cmd->type == DBX_COMMAND_QUERY );
assert( cmd->flags == COMMAND_FLAG_NONE );
assert( cmd->noArgs == 2 );
assert( cmd->arg[ 0 ] > DBMS_QUERY_NONE && \
cmd->arg[ 0 ] < DBMS_QUERY_LAST );
assert( cmd->arg[ 1 ] >= DBMS_CACHEDQUERY_NONE && \
cmd->arg[ 1 ] < DBMS_CACHEDQUERY_LAST );
assert( cmd->noStrArgs >= 2 && cmd->noStrArgs <= 4 );
extractQueryData( cmd, &timeValue, &dataValue, &dataValueLength );
status = performQuery( stateInfo, cmd->strArg[ 0 ],
cmd->strArg[ argIndex ], &dataLength, dataValue,
dataValueLength, timeValue, cmd->arg[ 1 ],
cmd->arg[ 0 ] );
if( cryptStatusOK( status ) )
cmd->strArgLen[ argIndex ] = \
( cmd->arg[ 0 ] == DBMS_QUERY_NORMAL || \
cmd->arg[ 0 ] == DBMS_QUERY_CONTINUE ) ? \
dataLength : 0;
return( status );
}
int cmdUpdate( void *stateInfo, COMMAND_INFO *cmd )
{
void *dataValue;
int dataValueLength;
time_t timeValue;
assert( cmd->type == DBX_COMMAND_UPDATE );
assert( cmd->flags == COMMAND_FLAG_NONE );
assert( cmd->noArgs == 1 );
assert( cmd->noStrArgs >= 0 && cmd->noStrArgs <= 3 );
extractQueryData( cmd, &timeValue, &dataValue, &dataValueLength );
return( performUpdate( stateInfo, cmd->strArg[ 0 ],
dataValueLength > 0 ? dataValue : NULL,
dataValueLength, timeValue, cmd->arg[ 0 ] ) );
}
/* Process a command from the client and send it to the appropriate handler */
static const COMMAND_HANDLER commandHandlers[] = {
NULL, NULL, cmdOpen, cmdClose, cmdQuery, cmdUpdate, cmdGetErrorInfo };
void processCommand( void *stateInfo, BYTE *buffer )
{
COMMAND_INFO cmd = { 0 };
BYTE header[ COMMAND_FIXED_DATA_SIZE ], *bufPtr;
long totalLength;
int i, status;
/* Read the client's message header */
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 );
totalLength = getMessageLength( header + COMMAND_WORDSIZE );
if( !dbxCheckCommandInfo( &cmd, totalLength ) || \
cmd.type == COMMAND_RESULT )
{
assert( NOTREACHED );
/* Return an invalid result message */
putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
return;
}
/* Read the rest of the clients 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 ];
}
if( !dbxCheckCommandConsistency( &cmd, totalLength ) )
{
assert( NOTREACHED );
/* Return an invalid result message */
putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
return;
}
/* If it's a command which returns a string value, obtain the returned
data in the buffer. Normally we limit the size to the maximum
attribute size, however encoded objects and data popped from
envelopes/sessions can be larger than this so we use the entire buffer
minus a safety margin */
if( cmd.type == DBX_COMMAND_QUERY || \
cmd.type == DBX_COMMAND_GETERRORINFO )
{
cmd.strArg[ cmd.noStrArgs ] = bufPtr;
cmd.strArgLen[ cmd.noStrArgs ] = ( cmd.type == DBX_COMMAND_QUERY ) ? \
MAX_ENCODED_CERT_SIZE : MAX_ERRMSG_SIZE;
cmd.noStrArgs++;
}
/* Null-terminate the first string arg if there's one present, either the
database name or the SQL command. If there's something following it
in the buffer this is redundant (but safe) because it'll already be
followed by the MSB of the next string arg's length, if there's
nothing following it it's safe as well */
if( cmd.type == DBX_COMMAND_OPEN || \
( cmd.type == DBX_COMMAND_UPDATE && \
cmd.arg[ 0 ] != DBMS_UPDATE_ABORT ) || \
( cmd.type == DBX_COMMAND_QUERY && \
( cmd.arg[ 0 ] == DBMS_QUERY_NORMAL || \
cmd.arg[ 0 ] == DBMS_QUERY_CHECK || \
cmd.arg[ 0 ] == DBMS_QUERY_START ) ) )
( ( char * ) cmd.strArg[ 0 ] )[ cmd.strArgLen[ 0 ] ] = '\0';
/* Process the command and copy any return information back to the
caller */
status = commandHandlers[ cmd.type ]( stateInfo, &cmd );
bufPtr = buffer;
if( cryptStatusError( status ) )
{
/* The command failed, return a simple status value */
putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE );
putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, status );
return;
}
if( cmd.type == DBX_COMMAND_OPEN )
{
/* Return numeric value */
putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 0 );
putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE * 2 );
putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
return;
}
if( cmd.type == DBX_COMMAND_QUERY )
{
const int argIndex = cmd.noStrArgs - 1;
const long dataLength = cmd.strArgLen[ argIndex ];
/* Return data and length. In some cases (during ongoing queries
with no submitted SQL data) we can be called without any incoming
args, there's no space at the start of the shared input/output
buffer so we have to move the returned string back in the buffer
to avoid overwriting it with the other information we're about to
return */
if( dataLength )
memmove( bufPtr + COMMAND_WORD3_OFFSET,
cmd.strArg[ argIndex ], dataLength );
putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 1 );
putMessageLength( bufPtr + COMMAND_WORDSIZE,
( COMMAND_WORDSIZE * 2 ) + cmd.strArgLen[ argIndex ] );
putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, dataLength );
return;
}
if( cmd.type == DBX_COMMAND_GETERRORINFO )
{
const long dataLength = cmd.strArgLen[ 0 ];
/* Return data and length. Because we were called without any
incoming args, there's no space at the start of the shared input/
output buffer so we have to move the returned string back in the
buffer to avoid overwriting it with the other information we're
about to return */
if( dataLength )
memmove( bufPtr + COMMAND_WORD4_OFFSET, cmd.strArg[ 0 ],
dataLength );
putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 1 );
putMessageLength( bufPtr + COMMAND_WORDSIZE,
( COMMAND_WORDSIZE * 2 ) + cmd.strArgLen[ 0 ] );
putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
putMessageWord( bufPtr + COMMAND_WORD3_OFFSET, dataLength );
return;
}
putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE );
putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
}
#endif /* USE_RPCAPI */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -