📄 dbxldap.c
字号:
RESOURCE_IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusOK( status ) )
*iCryptHandle = createInfo.cryptHandle;
ldap_value_free_len( valuePtrs );
}
else
status = CRYPT_ERROR_NOTFOUND;
/* Clean up. The ber_free() function is rather problematic because
Netscape uses the nonstandard ldap_ber_free() name (which can be fixed
with proprocessor trickery) and Microsoft first omitted it entirely
(up to NT4 SP4) and then later added it as a stub (Win2K, rumour has
it that the only reason this function even exists is because the
Netscape client required it). Because it may or may not exist in the
MS client, we call it if we resolved its address, otherwise we skip
it.
The function is further complicated by the fact that LDAPv3 says the
second parameter should be 0, however the Netscape client docs
require it to be 1 and the MS client ignores it so we pass in a 1
(actually the way the MS implementation handles the BER data is that
the BerElement returned by ldap_first_attribute() is (despite what the
MSDN docs claim) just a data structure pointed to by lm_ber in the
LDAPMessage structure, all that ldap_first_attribute() does is
redirect the lm_ber pointer inside the LDAPMessage, so actually
freeing this wouldn't be a good idea).
It gets worse than this though. Calling ber_free() with newer
versions of the Windows LDAP client causes internal data corruption
which typically first results in a soft failure (eg a data fetch
fails) and then eventually a hard failure such as an access violation
after further calls are made. The only real way to fix this is to
avoid calling it entirely, this doesn't seem to leak any more memory
than Winsock leaks anyway (that is, there are a considerable number
of memory and handle leaks, but the number doesn't increase if
ber_free() isn't called).
There have been reports that with some older versions of the Windows
LDAP client (eg the one in Win95) the ldap_msgfree() call generates
an exception in wldap.dll, if this is a problem you need to either
install a newer LDAP DLL or switch to the Netscape one */
#ifdef NETSCAPE_CLIENT
if( ber_free != NULL )
ber_free( ber, 1 );
#endif /* NETSCAPE_CLIENT */
ldap_memfree( attributePtr );
if( !keysetInfo->queryInProgress )
ldap_msgfree( result );
return( status );
}
/* Add an entry/attribute to an LDAP directory. The LDAP behaviour differs
somewhat from DAP in that assigning a value to a nonexistant attribute
implicitly creates the required attribute. In addition deleting the last
value automatically deletes the entire attribute, the delete item code
assumes the user is requesting a superset of this behaviour and deletes
the entire entry */
static int addCert( KEYSET_INFO *keysetInfo, const CRYPT_HANDLE iCryptHandle )
{
RESOURCE_DATA msgData;
LDAPMod *ldapMod[ MAX_LDAP_ATTRIBUTES ];
BYTE keyData[ MAX_CERT_SIZE ];
char dn[ MAX_DN_STRINGSIZE ];
char C[ CRYPT_MAX_TEXTSIZE + 1 ], SP[ CRYPT_MAX_TEXTSIZE + 1 ],
L[ CRYPT_MAX_TEXTSIZE + 1 ], O[ CRYPT_MAX_TEXTSIZE + 1 ],
OU[ CRYPT_MAX_TEXTSIZE + 1 ], CN[ CRYPT_MAX_TEXTSIZE + 1 ],
email[ CRYPT_MAX_TEXTSIZE + 1 ];
int keyDataLength, ldapModIndex = 1, status = CRYPT_OK;
*C = *SP = *L = *O = *OU = *CN = *email = '\0';
/* Extract the DN and altName components. This changes the currently
selected DN components, but this is OK since we've got the cert
locked and the prior state will be restored when we unlock it */
krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED, CRYPT_CERTINFO_SUBJECTNAME );
setResourceData( &msgData, C, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_COUNTRYNAME );
if( cryptStatusOK( status ) )
C[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setResourceData( &msgData, SP, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_STATEORPROVINCENAME );
}
if( cryptStatusOK( status ) )
SP[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setResourceData( &msgData, L, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_LOCALITYNAME );
}
if( cryptStatusOK( status ) )
L[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setResourceData( &msgData, O, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_ORGANIZATIONNAME );
}
if( cryptStatusOK( status ) )
O[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setResourceData( &msgData, OU, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
}
if( cryptStatusOK( status ) )
OU[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setResourceData( &msgData, CN, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_COMMONNAME );
}
if( cryptStatusOK( status ) )
CN[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
/* Get the string form of the DN */
status = encodeDN( dn, C, SP, L, O, OU, CN );
if( cryptStatusOK( status ) )
{
/* Get the certificate data */
setResourceData( &msgData, keyData, MAX_CERT_SIZE );
status = krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENC_CERT );
keyDataLength = msgData.length;
}
if( cryptStatusError( status ) )
/* Convert any low-level cert-specific error into something generic
which makes a bit more sense to the caller */
return( CRYPT_ARGERROR_NUM1 );
/* Set up the fixed attributes and certificate data. This currently
always adds a cert as a standard certificate rather than a CA
certificate because of uncertainty over what other implementations
will try and look for, once enough other software uses the CA cert
attribute this can be switched over */
if( ( ldapMod[ 0 ] = copyAttribute( keysetInfo->keysetLDAP.nameObjectClass,
"certPerson", 0 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( ( ldapMod[ ldapModIndex++ ] = copyAttribute( keysetInfo->keysetLDAP.nameCert,
keyData, keyDataLength ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
/* Set up the DN/identification information */
if( cryptStatusOK( status ) && *email && \
( ldapMod[ ldapModIndex++ ] = \
copyAttribute( keysetInfo->keysetLDAP.nameEmail, email, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *CN && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "CN", CN, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *OU && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "OU", OU, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *O && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "O", O, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *L && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "L", L, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *SP && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "SP", SP, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusOK( status ) && *C && \
( ldapMod[ ldapModIndex++ ] = copyAttribute( "C", C, 0 ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
ldapMod[ ldapModIndex ] = NULL;
/* Add the new attribute/entry */
if( cryptStatusOK( status ) )
{
int ldapStatus;
if( ( ldapStatus = ldap_add_s( keysetInfo->keysetLDAP.ld, dn,
ldapMod ) ) != LDAP_SUCCESS )
{
getErrorInfo( keysetInfo, ldapStatus );
status = mapLDAPerror( ldapStatus, CRYPT_ERROR_WRITE );
}
}
/* Clean up. We do it the hard way rather than using
ldap_mods_free() here partially because the ldapMod[] array
isn't malloc()'d, but mostly because for the Netscape client
library ldap_mods_free() causes some sort of memory corruption,
possibly because it's trying to free the mod_values[] entries
which are statically allocated, and for the MS client the
function doesn't exist */
for( ldapModIndex = 0; ldapMod[ ldapModIndex ] != NULL;
ldapModIndex++ )
{
if( ldapMod[ ldapModIndex ]->mod_op & LDAP_MOD_BVALUES )
free( ldapMod[ ldapModIndex ]->mod_bvalues[ 0 ] );
free( ldapMod[ ldapModIndex ]->mod_values );
free( ldapMod[ ldapModIndex ] );
}
return( status );
}
static int setItemFunction( KEYSET_INFO *keysetInfo,
const CRYPT_HANDLE iCryptHandle,
const KEYMGMT_ITEM_TYPE itemType,
const char *password, const int passwordLength,
const int flags )
{
BOOLEAN seenNonDuplicate = FALSE;
int type, status;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY );
assert( password == NULL ); assert( passwordLength == 0 );
/* Make sure we've been given a cert or cert chain */
status = krnlSendMessage( iCryptHandle, RESOURCE_MESSAGE_GETATTRIBUTE,
&type, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) )
return( CRYPT_ARGERROR_NUM1 );
if( type != CRYPT_CERTTYPE_CERTIFICATE && \
type != CRYPT_CERTTYPE_CERTCHAIN )
return( CRYPT_ARGERROR_NUM1 );
/* Lock the cert for our exclusive use (in case it's a cert chain, we
also select the first cert in the chain), update the keyset with the
cert(s), and unlock it to allow others access */
krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
status = krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_LOCK );
if( cryptStatusError( status ) )
return( status );
do
{
/* Add the certificate */
status = addCert( keysetInfo, iCryptHandle );
/* A cert being added may already be present, however we can't fail
immediately because what's being added may be a chain containing
further certs, so we keep track of whether we've successfully
added at least one cert and clear data duplicate errors */
if( status == CRYPT_OK )
seenNonDuplicate = TRUE;
else
if( status == CRYPT_ERROR_DUPLICATE )
status = CRYPT_OK;
}
while( cryptStatusOK( status ) && \
krnlSendMessage( iCryptHandle, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORNEXT,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
krnlSendNotifier( iCryptHandle, RESOURCE_IMESSAGE_UNLOCK );
if( cryptStatusOK( status ) && !seenNonDuplicate )
/* We reached the end of the chain without finding anything we could
add, return a data duplicate error */
status = CRYPT_ERROR_DUPLICATE;
return( status );
}
/* Delete an entry from an LDAP directory */
static int deleteItemFunction( KEYSET_INFO *keysetInfo,
const KEYMGMT_ITEM_TYPE itemType,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength )
{
char dn[ MAX_DN_STRINGSIZE ];
int ldapStatus;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY );
assert( keyIDtype == CRYPT_KEYID_NAME || keyIDtype == CRYPT_KEYID_EMAIL );
/* Convert the DN into a null-terminated form */
if( keyIDlength > MAX_DN_STRINGSIZE - 1 )
return( CRYPT_ARGERROR_STR1 );
memcpy( dn, keyID, keyIDlength );
dn[ keyIDlength ] = '\0';
/* Delete the entry */
if( ( ldapStatus = ldap_delete_s( keysetInfo->keysetLDAP.ld,
dn ) ) != LDAP_SUCCESS )
{
getErrorInfo( keysetInfo, ldapStatus );
return( mapLDAPerror( ldapStatus, CRYPT_ERROR_WRITE ) );
}
return( CRYPT_OK );
}
/* Perform a getFirst/getNext query on the LDAP directory */
static int getFirstItemFunction( KEYSET_INFO *keysetInfo,
CRYPT_CERTIFICATE *iCertificate,
int *stateInfo,
const CRYPT_KEYID_TYPE keyIDtype,
const void *keyID, const int keyIDlength,
const KEYMGMT_ITEM_TYPE itemType,
const int options )
{
assert( stateInfo == NULL );
assert( itemType == KEYMGMT_ITEM_PUBLICKEY );
assert( options == KEYMGMT_FLAG_NONE );
return( getItemFunction( keysetInfo, NULL, KEYMGMT_ITEM_PUBLICKEY,
CRYPT_KEYID_NAME, keyID, keyIDlength, NULL,
0, 0 ) );
}
static int getNextItemFunction( KEYSET_INFO *keysetInfo,
CRYPT_CERTIFICATE *iCertificate,
int *stateInfo, const int options )
{
assert( stateInfo == NULL );
return( getItemFunction( keysetInfo, iCertificate, KEYMGMT_ITEM_PUBLICKEY,
CRYPT_KEYID_NONE, NULL, 0, NULL, 0, 0 ) );
}
int setAccessMethodLDAP( KEYSET_INFO *keysetInfo )
{
#ifdef __WINDOWS__
/* Make sure the LDAP driver is bound in */
if( hLDAP == NULL_HINSTANCE )
return( CRYPT_ERROR_OPEN );
#endif /* __WINDOWS__ */
/* Set the access method pointers */
keysetInfo->initFunction = initFunction;
keysetInfo->shutdownFunction = shutdownFunction;
keysetInfo->getItemFunction = getItemFunction;
keysetInfo->setItemFunction = setItemFunction;
keysetInfo->deleteItemFunction = deleteItemFunction;
keysetInfo->getFirstItemFunction = getFirstItemFunction;
keysetInfo->getNextItemFunction = getNextItemFunction;
return( CRYPT_OK );
}
#endif /* ( __WINDOWS__ || __UNIX__ ) && DBX_LDAP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -