cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dbx_rpc.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Database RPC Interface *
4 * Copyright Peter Gutmann 1997-2004 *
5 * *
6 ****************************************************************************/
7 
8 /* This file isn't a standalone module but is meant to be #included into
9  whichever of the database client files that it's used with */
10 
11 #ifdef USE_RPCAPI
12 
13 /* Set up query data so it can be sent to the database back-end */
14 
15 static void extractQueryData( COMMAND_INFO *cmd, time_t *timeValuePtrPtr,
16  void **dataValuePtrPtr,
17  int *dataValueLengthPtr )
18  {
19  /* Clear return values */
20  *timeValuePtrPtr = 0;
21  *dataValuePtrPtr = NULL;
22  *dataValueLengthPtr = 0;
23 
24  /* If there's only one string arg present (the command), we're done */
25  if( cmd->noStrArgs < 2 )
26  return;
27 
28  /* If one of the string args is a bound date, convert it into a time_t */
29  if( cmd->strArgLen[ 1 ] == 8 )
30  {
31  const BYTE *timeValuePtr = cmd->strArg[ 1 ];
32 
33  /* Extract the time_t from the 64-bit time value */
34  *timeValuePtrPtr = ( time_t ) timeValuePtr[ 4 ] << 24 | \
35  ( time_t ) timeValuePtr[ 5 ] << 16 | \
36  ( time_t ) timeValuePtr[ 6 ] << 8 | \
37  ( time_t ) timeValuePtr[ 7 ];
38 #ifdef SYSTEM_64BIT
39  *timeValuePtrPtr |= ( time_t ) timeValuePtr[ 3 ] << 32;
40 #endif /* SYSTEM_64BIT */
41 
42  /* Since the first arg is the date, the data (if any) will be in
43  the second arg */
44  if( cmd->strArgLen[ 2 ] > 0 )
45  {
46  *dataValuePtrPtr = cmd->strArg[ 2 ];
47  *dataValueLengthPtr = cmd->strArgLen[ 2 ];
48  }
49 
50  return;
51  }
52 
53  /* There's only one string arg present, which is the data */
54  if( cmd->strArgLen[ 1 ] > 0 )
55  {
56  *dataValuePtrPtr = cmd->strArg[ 1 ];
57  *dataValueLengthPtr = cmd->strArgLen[ 1 ];
58  }
59  }
60 
61 /* Handlers for the various commands */
62 
63 int cmdClose( void *stateInfo, COMMAND_INFO *cmd )
64  {
65  assert( cmd->type == DBX_COMMAND_CLOSE );
66  assert( cmd->flags == COMMAND_FLAG_NONE );
67  assert( cmd->noArgs == 0 );
68  assert( cmd->noStrArgs == 0 );
69 
70  closeDatabase( stateInfo );
71  return( CRYPT_OK );
72  }
73 
74 int cmdGetErrorInfo( void *stateInfo, COMMAND_INFO *cmd )
75  {
76  assert( cmd->type == DBX_COMMAND_GETERRORINFO );
77  assert( cmd->flags == COMMAND_FLAG_NONE );
78  assert( cmd->noArgs == 0 );
79  assert( cmd->noStrArgs == 1 );
80 
81  performErrorQuery( stateInfo, &cmd->arg[ 0 ], cmd->strArg[ 0 ] );
82  cmd->strArgLen[ 0 ] = strlen( cmd->strArg[ 0 ] );
83  return( CRYPT_OK );
84  }
85 
86 int cmdOpen( void *stateInfo, COMMAND_INFO *cmd )
87  {
89 
90  assert( cmd->type == DBX_COMMAND_OPEN );
91  assert( cmd->flags == COMMAND_FLAG_NONE );
92  assert( cmd->noArgs == 1 );
93  assert( cmd->arg[ 0 ] >= CRYPT_KEYOPT_NONE && \
94  cmd->arg[ 0 ] < CRYPT_KEYOPT_LAST );
95  assert( cmd->noStrArgs == 1 );
96 
97  status = openDatabase( stateInfo, cmd->strArg[ 0 ], cmd->arg[ 0 ],
98  &hasBinaryBlobs );
99  if( cryptStatusOK( status ) )
100  cmd->arg[ 0 ] = hasBinaryBlobs;
101  return( status );
102  }
103 
104 int cmdQuery( void *stateInfo, COMMAND_INFO *cmd )
105  {
106  const int argIndex = cmd->noStrArgs - 1;
107  void *dataValue;
108  time_t timeValue;
109  int dataValueLength, dataLength, status;
110 
111  assert( cmd->type == DBX_COMMAND_QUERY );
112  assert( cmd->flags == COMMAND_FLAG_NONE );
113  assert( cmd->noArgs == 2 );
114  assert( cmd->arg[ 0 ] > DBMS_QUERY_NONE && \
115  cmd->arg[ 0 ] < DBMS_QUERY_LAST );
116  assert( cmd->arg[ 1 ] >= DBMS_CACHEDQUERY_NONE && \
117  cmd->arg[ 1 ] < DBMS_CACHEDQUERY_LAST );
118  assert( cmd->noStrArgs >= 2 && cmd->noStrArgs <= 4 );
119 
120  extractQueryData( cmd, &timeValue, &dataValue, &dataValueLength );
121  status = performQuery( stateInfo, cmd->strArg[ 0 ],
122  cmd->strArg[ argIndex ], &dataLength, dataValue,
123  dataValueLength, timeValue, cmd->arg[ 1 ],
124  cmd->arg[ 0 ] );
125  if( cryptStatusOK( status ) )
126  cmd->strArgLen[ argIndex ] = \
127  ( cmd->arg[ 0 ] == DBMS_QUERY_NORMAL || \
128  cmd->arg[ 0 ] == DBMS_QUERY_CONTINUE ) ? \
129  dataLength : 0;
130  return( status );
131  }
132 
133 int cmdUpdate( void *stateInfo, COMMAND_INFO *cmd )
134  {
135  void *dataValue;
136  int dataValueLength;
137  time_t timeValue;
138 
139  assert( cmd->type == DBX_COMMAND_UPDATE );
140  assert( cmd->flags == COMMAND_FLAG_NONE );
141  assert( cmd->noArgs == 1 );
142  assert( cmd->noStrArgs >= 0 && cmd->noStrArgs <= 3 );
143 
144  extractQueryData( cmd, &timeValue, &dataValue, &dataValueLength );
145  return( performUpdate( stateInfo, cmd->strArg[ 0 ],
146  dataValueLength > 0 ? dataValue : NULL,
147  dataValueLength, timeValue, cmd->arg[ 0 ] ) );
148  }
149 
150 /* Process a command from the client and send it to the appropriate handler */
151 
152 static const COMMAND_HANDLER commandHandlers[] = {
153  NULL, NULL, cmdOpen, cmdClose, cmdQuery, cmdUpdate, cmdGetErrorInfo };
154 
155 void processCommand( void *stateInfo, BYTE *buffer )
156  {
157  COMMAND_INFO cmd = { 0 };
158  BYTE header[ COMMAND_FIXED_DATA_SIZE ], *bufPtr;
159  long totalLength;
160  int i, status;
161 
162  /* Read the client's message header */
163  memcpy( header, buffer, COMMAND_FIXED_DATA_SIZE );
164 
165  /* Process the fixed message header and make sure it's valid */
166  getMessageType( header, cmd.type, cmd.flags, cmd.noArgs, cmd.noStrArgs );
167  totalLength = getMessageLength( header + COMMAND_WORDSIZE );
168  if( !dbxCheckCommandInfo( &cmd, totalLength ) || \
169  cmd.type == COMMAND_RESULT )
170  {
171  assert( NOTREACHED );
172 
173  /* Return an invalid result message */
174  putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
175  putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
176  return;
177  }
178 
179  /* Read the rest of the clients message */
180  bufPtr = buffer + COMMAND_FIXED_DATA_SIZE;
181  for( i = 0; i < cmd.noArgs; i++ )
182  {
183  cmd.arg[ i ] = getMessageWord( bufPtr );
184  bufPtr += COMMAND_WORDSIZE;
185  }
186  for( i = 0; i < cmd.noStrArgs; i++ )
187  {
188  cmd.strArgLen[ i ] = getMessageWord( bufPtr );
189  cmd.strArg[ i ] = bufPtr + COMMAND_WORDSIZE;
190  bufPtr += COMMAND_WORDSIZE + cmd.strArgLen[ i ];
191  }
192  if( !dbxCheckCommandConsistency( &cmd, totalLength ) )
193  {
194  assert( NOTREACHED );
195 
196  /* Return an invalid result message */
197  putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
198  putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
199  return;
200  }
201 
202  /* If it's a command which returns a string value, obtain the returned
203  data in the buffer. Normally we limit the size to the maximum
204  attribute size, however encoded objects and data popped from
205  envelopes/sessions can be larger than this so we use the entire buffer
206  minus a safety margin */
207  if( cmd.type == DBX_COMMAND_QUERY || \
209  {
210  cmd.strArg[ cmd.noStrArgs ] = bufPtr;
211  cmd.strArgLen[ cmd.noStrArgs ] = ( cmd.type == DBX_COMMAND_QUERY ) ? \
213  cmd.noStrArgs++;
214  }
215 
216  /* Null-terminate the first string arg if there's one present, either the
217  database name or the SQL command. If there's something following it
218  in the buffer this is redundant (but safe) because it'll already be
219  followed by the MSB of the next string arg's length, if there's
220  nothing following it it's safe as well */
221  if( cmd.type == DBX_COMMAND_OPEN || \
222  ( cmd.type == DBX_COMMAND_UPDATE && \
223  cmd.arg[ 0 ] != DBMS_UPDATE_ABORT ) || \
224  ( cmd.type == DBX_COMMAND_QUERY && \
225  ( cmd.arg[ 0 ] == DBMS_QUERY_NORMAL || \
226  cmd.arg[ 0 ] == DBMS_QUERY_CHECK || \
227  cmd.arg[ 0 ] == DBMS_QUERY_START ) ) )
228  ( ( char * ) cmd.strArg[ 0 ] )[ cmd.strArgLen[ 0 ] ] = '\0';
229 
230  /* Process the command and copy any return information back to the
231  caller */
232  status = commandHandlers[ cmd.type ]( stateInfo, &cmd );
233  bufPtr = buffer;
234  if( cryptStatusError( status ) )
235  {
236  /* The command failed, return a simple status value */
237  putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
239  putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, status );
240  return;
241  }
242  if( cmd.type == DBX_COMMAND_OPEN )
243  {
244  /* Return numeric value */
245  putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 0 );
248  putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
249  return;
250  }
251  if( cmd.type == DBX_COMMAND_QUERY )
252  {
253  const int argIndex = cmd.noStrArgs - 1;
254  const long dataLength = cmd.strArgLen[ argIndex ];
255 
256  /* Return data and length. In some cases (during ongoing queries
257  with no submitted SQL data) we can be called without any incoming
258  args, there's no space at the start of the shared input/output
259  buffer so we have to move the returned string back in the buffer
260  to avoid overwriting it with the other information we're about to
261  return */
262  if( dataLength )
263  memmove( bufPtr + COMMAND_WORD3_OFFSET,
264  cmd.strArg[ argIndex ], dataLength );
265  putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 1 );
267  ( COMMAND_WORDSIZE * 2 ) + cmd.strArgLen[ argIndex ] );
269  putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, dataLength );
270  return;
271  }
272  if( cmd.type == DBX_COMMAND_GETERRORINFO )
273  {
274  const long dataLength = cmd.strArgLen[ 0 ];
275 
276  /* Return data and length. Because we were called without any
277  incoming args, there's no space at the start of the shared input/
278  output buffer so we have to move the returned string back in the
279  buffer to avoid overwriting it with the other information we're
280  about to return */
281  if( dataLength )
282  memmove( bufPtr + COMMAND_WORD4_OFFSET, cmd.strArg[ 0 ],
283  dataLength );
284  putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 1 );
286  ( COMMAND_WORDSIZE * 2 ) + cmd.strArgLen[ 0 ] );
288  putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
289  putMessageWord( bufPtr + COMMAND_WORD3_OFFSET, dataLength );
290  return;
291  }
292  putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
295  }
296 #endif /* USE_RPCAPI */