📄 ldap.c
字号:
documented behaviour, so we pass in 0 as the argument.
It gets worse than this though. Calling ber_free() with newer
versions of the Windows LDAP client with any argument at all 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.
The reason for some of the Windows problems are because the
wldap32.lib shipped with VC++ uses different ordinals than the
wldap32.dll which comes with the OS (see MSKB article Q283199), so
that simply using the out-of-the-box development tools with the out-
of-the-box OS can result in access violations and assorted other
problems */
#ifdef NETSCAPE_CLIENT
if( ber_free != NULL )
ber_free( ber, 0 );
#endif /* NETSCAPE_CLIENT */
ldap_memfree( attributePtr );
if( !ldapInfo->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 )
{
LDAP_INFO *ldapInfo = keysetInfo->keysetLDAP;
LDAPMod *ldapMod[ MAX_LDAP_ATTRIBUTES ];
RESOURCE_DATA msgData;
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, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED, CRYPT_CERTINFO_SUBJECTNAME );
setMessageData( &msgData, C, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_COUNTRYNAME );
if( cryptStatusOK( status ) )
C[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, SP, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_STATEORPROVINCENAME );
}
if( cryptStatusOK( status ) )
SP[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, L, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_LOCALITYNAME );
}
if( cryptStatusOK( status ) )
L[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, O, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_ORGANIZATIONNAME );
}
if( cryptStatusOK( status ) )
O[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, OU, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
}
if( cryptStatusOK( status ) )
OU[ msgData.length ] = '\0';
if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
{
setMessageData( &msgData, CN, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( iCryptHandle, 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 */
setMessageData( &msgData, keyData, MAX_CERT_SIZE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_CRT_EXPORT,
&msgData, CRYPT_CERTFORMAT_CERTIFICATE );
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( ldapInfo->nameObjectClass,
"certPerson", 0 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
if( ( ldapMod[ ldapModIndex++ ] = copyAttribute( ldapInfo->nameCert,
keyData, keyDataLength ) ) == NULL )
status = CRYPT_ERROR_MEMORY;
/* Set up the DN/identification information */
if( cryptStatusOK( status ) && *email && \
( ldapMod[ ldapModIndex++ ] = \
copyAttribute( ldapInfo->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( ldapInfo->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 )
clFree( "addCert", ldapMod[ ldapModIndex ]->mod_bvalues[ 0 ] );
clFree( "addCert", ldapMod[ ldapModIndex ]->mod_values );
clFree( "addCert", 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, 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, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
status = krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
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, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORNEXT,
CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK );
krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
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 )
{
LDAP_INFO *ldapInfo = keysetInfo->keysetLDAP;
char dn[ MAX_DN_STRINGSIZE ];
int ldapStatus;
assert( itemType == KEYMGMT_ITEM_PUBLICKEY );
assert( keyIDtype == CRYPT_KEYID_NAME || keyIDtype == CRYPT_KEYID_URI );
/* 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( ldapInfo->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 ) );
}
/* Return status info for the keyset */
static BOOLEAN isBusyFunction( KEYSET_INFO *keysetInfo )
{
return( keysetInfo->keysetLDAP->queryInProgress );
}
/* Get/set keyset attributes */
static void *getAttributeDataPtr( KEYSET_INFO *keysetInfo,
const CRYPT_ATTRIBUTE_TYPE type )
{
LDAP_INFO *ldapInfo = keysetInfo->keysetLDAP;
switch( type )
{
case CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS:
return( ldapInfo->nameObjectClass );
case CRYPT_OPTION_KEYS_LDAP_FILTER:
return( ldapInfo->nameFilter );
case CRYPT_OPTION_KEYS_LDAP_CACERTNAME:
return( ldapInfo->nameCACert );
case CRYPT_OPTION_KEYS_LDAP_CERTNAME:
return( ldapInfo->nameCert );
case CRYPT_OPTION_KEYS_LDAP_CRLNAME:
return( ldapInfo->nameCRL );
case CRYPT_OPTION_KEYS_LDAP_EMAILNAME:
return( ldapInfo->nameEmail );
}
return( NULL );
}
static int getAttributeFunction( KEYSET_INFO *keysetInfo, void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
const void *attributeDataPtr = getAttributeDataPtr( keysetInfo, type );
if( attributeDataPtr == NULL )
return( CRYPT_ARGERROR_VALUE );
return( attributeCopy( data, attributeDataPtr,
strlen( attributeDataPtr ) ) );
}
static int setAttributeFunction( KEYSET_INFO *keysetInfo, const void *data,
const CRYPT_ATTRIBUTE_TYPE type )
{
const RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) data;
BYTE *attributeDataPtr = getAttributeDataPtr( keysetInfo, type );
assert( msgData->length <= CRYPT_MAX_TEXTSIZE );
if( attributeDataPtr == NULL )
return( CRYPT_ARGERROR_VALUE );
memcpy( attributeDataPtr, msgData->data, msgData->length );
attributeDataPtr[ msgData->length ] = '\0';
return( CRYPT_OK );
}
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->getAttributeFunction = getAttributeFunction;
keysetInfo->setAttributeFunction = setAttributeFunction;
keysetInfo->getItemFunction = getItemFunction;
keysetInfo->setItemFunction = setItemFunction;
keysetInfo->deleteItemFunction = deleteItemFunction;
keysetInfo->getFirstItemFunction = getFirstItemFunction;
keysetInfo->getNextItemFunction = getNextItemFunction;
keysetInfo->isBusyFunction = isBusyFunction;
return( CRYPT_OK );
}
#endif /* USE_LDAP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -