📄 dbx_misc.c
字号:
"CREATE UNIQUE INDEX crlCertIDIdx ON CRLs (certID)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX userKeyIDIdx ON pkiUsers (keyID)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX userNameIDIdx ON pkiUsers (nameID)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
status = dbmsStaticUpdate(
"CREATE UNIQUE INDEX logCertIDIdx ON certLog (certID)" );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
{
char dummyCertID[ ENCODED_DBXKEYID_SIZE + 8 ];
const int dummyCertIDlength = ENCODED_DBXKEYID_SIZE;
/* Create a special dummy certID with an out-of-band value to mark
the first entry in the log */
memset( dummyCertID, '-', ENCODED_DBXKEYID_SIZE );
/* Add the initial log entry recording the creation of the log */
status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_CREATE,
dummyCertID, dummyCertIDlength,
NULL, 0, NULL, 0, NULL, 0,
DBMS_UPDATE_NORMAL );
}
if( cryptStatusError( status ) )
{
/* Undo the creation of the various tables */
dbmsStaticUpdate( "DROP TABLE certificates" );
dbmsStaticUpdate( "DROP TABLE CRLs" );
if( isCertStore( dbmsInfo ) )
{
dbmsStaticUpdate( "DROP TABLE pkiUsers" );
dbmsStaticUpdate( "DROP TABLE certRequests" );
dbmsStaticUpdate( "DROP TABLE certLog" );
}
retExtErr( CRYPT_ERROR_WRITE,
( CRYPT_ERROR_WRITE, errorInfo, getDbmsErrorInfo( dbmsInfo ),
"Couldn't create indexes for certificate%s database: ",
isCertStore( dbmsInfo ) ? " store" : "" ) );
}
/* If the back-end doesn't support access permissions (generally only
toy ones like Access and Paradox) or it's not a CA certificate
store, we're done */
if( !hasPermissions || !isCertStore( dbmsInfo ) )
return( CRYPT_OK );
/* Set access controls for the certificate store tables:
Users CAs
certRequests: - INS,SEL,DEL
certificates: SEL INS,SEL,DEL
CRLs: - INS,SEL,DEL
pkiUsers: - INS,SEL,DEL
certLog: - INS,SEL
Once role-based access controls are enabled we can allow only the CA
user to update the certstore tables and allow others only read access
to the certificates table. In addition the revocation should be
phrased as REVOKE ALL, GRANT <permitted> rather than revoking specific
privileges since each database vendor has their own nonstandard
additional privileges that a specific revoke won't cover.
Unfortunately configuring this will be somewhat difficult since it
requires that cryptlib users create database user roles, which in turn
requires that they read the manual */
#if 1
dbmsStaticUpdate( "REVOKE UPDATE ON certificates FROM PUBLIC" );
dbmsStaticUpdate( "REVOKE UPDATE ON CRLs FROM PUBLIC" );
dbmsStaticUpdate( "REVOKE UPDATE ON pkiUsers FROM PUBLIC" );
dbmsStaticUpdate( "REVOKE UPDATE ON certRequests FROM PUBLIC" );
dbmsStaticUpdate( "REVOKE DELETE,UPDATE ON certLog FROM PUBLIC" );
#else
dbmsStaticUpdate( "REVOKE ALL ON certificates FROM PUBLIC" );
dbmsStaticUpdate( "GRANT INSERT,SELECT,DELETE ON certificates TO ca" );
dbmsStaticUpdate( "GRANT SELECT ON certificates TO PUBLIC" );
dbmsStaticUpdate( "REVOKE ALL ON CRLs FROM PUBLIC" );
dbmsStaticUpdate( "GRANT INSERT,SELECT,DELETE ON CRLs TO ca" );
dbmsStaticUpdate( "REVOKE ALL ON pkiUsers FROM PUBLIC" );
dbmsStaticUpdate( "GRANT INSERT,SELECT,DELETE ON pkiUsers TO ca" );
dbmsStaticUpdate( "REVOKE ALL ON certRequests FROM PUBLIC" );
dbmsStaticUpdate( "GRANT INSERT,SELECT,DELETE ON certRequests TO ca" );
dbmsStaticUpdate( "REVOKE ALL ON certLog FROM PUBLIC" );
dbmsStaticUpdate( "GRANT INSERT,SELECT ON certLog TO ca" );
#endif /* 1 */
return( CRYPT_OK );
}
/* Return status information for the keyset */
CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
static BOOLEAN isBusyFunction( KEYSET_INFO *keysetInfoPtr )
{
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
return( ( keysetInfoPtr->keysetDBMS->flags & \
( DBMS_FLAG_UPDATEACTIVE | DBMS_FLAG_QUERYACTIVE ) ) ? \
TRUE : FALSE );
}
/* Open a connection to a database */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
IN_BUFFER( nameLen ) const char *name,
IN_LENGTH_NAME const int nameLen,
IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
{
DBMS_INFO *dbmsInfo = keysetInfoPtr->keysetDBMS;
DBMS_NAME_INFO nameInfo;
int featureFlags, status;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
assert( isReadPtr( name, nameLen ) );
REQUIRES( nameLen >= MIN_NAME_LENGTH && nameLen < MAX_ATTRIBUTE_SIZE );
REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
/* Parse the data source name. The parsed form isn't needed at this
point but it allows us to return a more meaningful error response */
status = dbmsParseName( &nameInfo, name, nameLen );
if( cryptStatusError( status ) )
retExt( status,
( status, KEYSET_ERRINFO, "Invalid database name" ) );
/* Perform a database back-end specific open */
status = dbmsOpen( name, nameLen,
( options == CRYPT_KEYOPT_READONLY ) ? \
options : CRYPT_KEYOPT_NONE, &featureFlags );
if( cryptStatusError( status ) )
{
endDbxSession( keysetInfoPtr );
return( status );
}
/* If the back-end is read-only (which would be extremely unusual,
usually related to misconfigured DBMS access permissions) and we're
not opening it in read-only mode, signal an error */
if( ( featureFlags & DBMS_FEATURE_FLAG_READONLY ) && \
options != CRYPT_KEYOPT_READONLY )
{
endDbxSession( keysetInfoPtr );
retExt( CRYPT_ERROR_PERMISSION,
( CRYPT_ERROR_PERMISSION, KEYSET_ERRINFO,
"Certificate database can only be accessed in read-only "
"mode" ) );
}
/* If we're being asked to create a new database, create it and exit */
if( options == CRYPT_KEYOPT_CREATE )
{
status = createDatabase( dbmsInfo,
( featureFlags & DBMS_FEATURE_FLAG_PRIVILEGES ) ? \
TRUE : FALSE, KEYSET_ERRINFO );
if( cryptStatusOK( status ) && isCertStore( dbmsInfo ) )
status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_CONNECT,
NULL, 0, NULL, 0, NULL, 0, NULL, 0,
DBMS_UPDATE_NORMAL );
if( cryptStatusError( status ) )
{
dbmsClose();
endDbxSession( keysetInfoPtr );
}
return( status );
}
/* Check to see whether it's a certificate store. We do this by
checking for the presence of the certificate store creation entry in
the log, this is always present with an action value of
CRYPT_CERTACTION_CREATE */
status = dbmsStaticQuery(
"SELECT certData FROM certLog WHERE action = "
TEXT_CERTACTION_CREATE,
DBMS_CACHEDQUERY_NONE, DBMS_QUERY_CHECK );
if( cryptStatusOK( status ) )
{
/* It's a certificate store, if we're opening it as a non-certificate
store it has to be in read-only mode. We return an error rather
than quietly changing the access mode to read-only both to make it
explicit to the user at open time that they can't make changes
and because we need to have the read-only flag set when we open
the database to optimise the buffering and locking strategy,
setting it at this point is too late */
if( !isCertStore( dbmsInfo ) )
{
if( options != CRYPT_KEYOPT_READONLY )
{
dbmsClose();
endDbxSession( keysetInfoPtr );
retExt( CRYPT_ERROR_PERMISSION,
( CRYPT_ERROR_PERMISSION, KEYSET_ERRINFO,
"Certificate store can't be accessed as a normal "
"database except in read-only mode" ) );
}
/* Remember that even though it's not functioning as a
certificate store we can still perform some extended queries
on it based on fields that are only present in certificate
stores */
dbmsInfo->flags |= DBMS_FLAG_CERTSTORE_FIELDS;
return( CRYPT_OK );
}
/* If this isn't a read-only open, record a connection to the
store */
if( options != CRYPT_KEYOPT_READONLY )
{
status = updateCertLog( dbmsInfo, CRYPT_CERTACTION_CONNECT,
NULL, 0, NULL, 0, NULL, 0, NULL, 0,
DBMS_UPDATE_NORMAL );
if( cryptStatusError( status ) )
{
/* This is a critical error, if we can't update the access
log at this point then it's not safe to use the
certificate store (if we fail during a general update
operation we give the caller the option of continuing
since the transaction itself will have been rolled back
so there's no permanent harm done) */
dbmsClose();
endDbxSession( keysetInfoPtr );
retExtArg( CRYPT_ARGERROR_NUM1,
( CRYPT_ARGERROR_NUM1, KEYSET_ERRINFO,
"Couldn't update certificate store log" ) );
}
}
return( CRYPT_OK );
}
/* It's not a certificate store, if the DBMS information indicates that
we're expecting to open it as one tell the caller */
if( isCertStore( dbmsInfo ) )
{
dbmsClose();
endDbxSession( keysetInfoPtr );
retExtArg( CRYPT_ARGERROR_NUM1,
( CRYPT_ARGERROR_NUM1, KEYSET_ERRINFO,
"Keyset isn't a certificate store" ) );
}
/* Since the failure of the query above will set the extended error
information we have to explicitly clear it here to avoid making the
(invisible) query side-effects visible to the user */
resetErrorInfo( dbmsInfo );
return( CRYPT_OK );
}
/* Close the connection to a database */
RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
{
DBMS_INFO *dbmsInfo = keysetInfoPtr->keysetDBMS;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
/* If it's a certificate store opened in read/write mode, record a
closed connection to the store */
if( isCertStore( dbmsInfo ) && \
keysetInfoPtr->options != CRYPT_KEYOPT_READONLY )
{
updateCertLog( dbmsInfo, CRYPT_CERTACTION_DISCONNECT,
NULL, 0, NULL, 0, NULL, 0, NULL, 0,
DBMS_UPDATE_NORMAL );
}
/* If we're in the middle of a query, cancel it. We always use
DBMS_CACHEDQUERY_NONE because this is the only query type that can
remain active outside the keyset object */
if( dbmsInfo->flags & DBMS_FLAG_QUERYACTIVE )
dbmsStaticQuery( NULL, DBMS_CACHEDQUERY_NONE, DBMS_QUERY_CANCEL );
dbmsClose();
return( endDbxSession( keysetInfoPtr ) );
}
/****************************************************************************
* *
* Database Access Routines *
* *
****************************************************************************/
/* Set up the function pointers to the keyset methods */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int setAccessMethodDBMS( INOUT KEYSET_INFO *keysetInfoPtr,
IN_ENUM( CRYPT_KEYSET ) const CRYPT_KEYSET_TYPE type )
{
int status;
assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
assert( DBMS_CACHEDQUERY_LAST == NO_CACHED_QUERIES );
REQUIRES( type > CRYPT_KEYSET_NONE && type < CRYPT_KEYSET_LAST );
/* Set up the lower-level interface functions */
status = initDbxSession( keysetInfoPtr, type );
if( cryptStatusError( status ) )
return( status );
/* Set the access method pointers */
keysetInfoPtr->initFunction = initFunction;
keysetInfoPtr->shutdownFunction = shutdownFunction;
status = initDBMSread( keysetInfoPtr );
if( cryptStatusOK( status ) )
status = initDBMSwrite( keysetInfoPtr );
if( cryptStatusError( status ) )
return( status );
if( type == CRYPT_KEYSET_ODBC_STORE || \
type == CRYPT_KEYSET_DATABASE_STORE || \
type == CRYPT_KEYSET_PLUGIN_STORE )
{
status = initDBMSCA( keysetInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
keysetInfoPtr->isBusyFunction = isBusyFunction;
return( CRYPT_OK );
}
#endif /* USE_DBMS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -