⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ldap.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
		timeout = 15;
	ldap_set_option( ldapInfo->ld, LDAP_OPT_TIMELIMIT, &timeout );
	ldap_set_option( ldapInfo->ld, LDAP_OPT_SIZELIMIT, &maxEntries );

	/* Set up the names of the objects and attributes */
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameObjectClass,
					 CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS );
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameFilter,
					 CRYPT_OPTION_KEYS_LDAP_FILTER );
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCACert,
					 CRYPT_OPTION_KEYS_LDAP_CACERTNAME );
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCert,
					 CRYPT_OPTION_KEYS_LDAP_CERTNAME );
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCRL,
					 CRYPT_OPTION_KEYS_LDAP_CRLNAME );
	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameEmail,
					 CRYPT_OPTION_KEYS_LDAP_EMAILNAME );
	krnlSendMessage( keysetInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
					 &ldapInfo->objectType,
					 CRYPT_OPTION_KEYS_LDAP_OBJECTTYPE );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*						 	Directory Access Routines						*
*																			*
****************************************************************************/

/* Send a query to an LDAP server */

static int sendLdapQuery( LDAP_INFO *ldapInfo, LDAPMessage **resultPtr,
						  const CRYPT_HANDLE iOwnerHandle, const char *dn )
	{
	const CRYPT_CERTTYPE_TYPE objectType = ldapInfo->objectType;
	const char *certAttributes[] = { ldapInfo->nameCert, NULL };
	const char *caCertAttributes[] = { ldapInfo->nameCACert, NULL };
	const char *crlAttributes[] = { ldapInfo->nameCRL, NULL };
	struct timeval ldapTimeout = { 0, 0 };
	int ldapStatus = LDAP_OTHER, timeout;

	/* Network I/O may be set to be nonblocking, so we make sure we try for 
	   at least 15s before timing out */
	krnlSendMessage( iOwnerHandle, IMESSAGE_GETATTRIBUTE, &timeout, 
					 CRYPT_OPTION_NET_READTIMEOUT );
	ldapTimeout.tv_sec = max( timeout, 15 );

	/* If the LDAP search-by-URL functions are available and the key ID is 
	   an LDAP URL, perform a search by URL */
	if( ldap_is_ldap_url != NULL && ldap_is_ldap_url( ( char * ) dn ) )
		return( ldap_url_search_st( ldapInfo->ld, ( char * ) dn, FALSE, 
									&ldapTimeout, resultPtr ) );

	/* Try and retrieve the entry for this DN from the directory.  We use a 
	   base specified by the DN, a chop of 0 (to return only the current 
	   entry), any object class (to get around the problem of 
	   implementations which stash certificates in whatever they feel like), 
	   and look for a certificate attribute.  If the search fails for this 
	   attribute, we try again but this time go for a CA certificate 
	   attribute which unfortunately slows down the search somewhat when the 
	   certificate isn't found but can't really be avoided since there's no 
	   way to tell in advance whether a certificate will be an end entity or 
	   a CA certificate.  To complicate things even further, we may also 
	   need to check for a CRL in case this is what the user is after */
	if( objectType == CRYPT_CERTTYPE_NONE || \
		objectType == CRYPT_CERTTYPE_CERTIFICATE )
		{
		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
									 ldapInfo->nameFilter,
									 ( char ** ) certAttributes, 0,
									 &ldapTimeout, resultPtr );
		if( ldapStatus == LDAP_SUCCESS )
			return( ldapStatus );
		}
	if( objectType == CRYPT_CERTTYPE_NONE || \
		objectType == CRYPT_CERTTYPE_CERTIFICATE )
		{
		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
									 ldapInfo->nameFilter,
									 ( char ** ) caCertAttributes, 0,
									 &ldapTimeout, resultPtr );
		if( ldapStatus == LDAP_SUCCESS )
			return( ldapStatus );
		}
	if( objectType == CRYPT_CERTTYPE_NONE || \
		objectType == CRYPT_CERTTYPE_CRL )
		{
		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
									 ldapInfo->nameFilter,
									 ( char ** ) crlAttributes, 0,
									 &ldapTimeout, resultPtr );
		if( ldapStatus == LDAP_SUCCESS )
			return( ldapStatus );
		}

	return( ldapStatus );
	}

/* Retrieve a key attribute from an LDAP directory */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
static int getItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
							OUT_HANDLE_OPT CRYPT_HANDLE *iCryptHandle,
							IN_ENUM( KEYMGMT_ITEM ) \
								const KEYMGMT_ITEM_TYPE itemType,
							IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
							IN_BUFFER( keyIDlength ) const void *keyID, 
							IN_LENGTH_KEYID const int keyIDlength,
							IN_OPT void *auxInfo, 
							INOUT_OPT int *auxInfoLength,
							IN_FLAGS_Z( KEYMGMT ) const int flags )
	{
	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
	LDAPMessage *result = DUMMY_INIT_PTR, *resultEntry;
	BerElement *ber;
	struct berval **valuePtrs;
	char dn[ MAX_DN_STRINGSIZE + 8 ];
	char *attributePtr;
	int ldapStatus, status = CRYPT_OK;

	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
	assert( isWritePtr( iCryptHandle, sizeof( CRYPT_HANDLE ) ) );
	assert( isReadPtr( keyID, keyIDlength ) );

	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
	REQUIRES( keyIDtype != CRYPT_KEYID_NONE || iCryptHandle != NULL );
	REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
			  keyIDlength < MAX_ATTRIBUTE_SIZE );
	REQUIRES( auxInfo == NULL && *auxInfoLength == 0 );
	REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX );

	/* 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';

	/* Send the LDAP query to the server */
	ldapStatus = sendLdapQuery( ldapInfo, &result, 
								keysetInfoPtr->ownerHandle, dn );
	if( ldapStatus != LDAP_SUCCESS )
		{
		getErrorInfo( keysetInfoPtr, ldapStatus );
		return( mapLdapError( ldapStatus, CRYPT_ERROR_READ ) );
		}

	/* We got something, start fetching the results */
	if( ( resultEntry = ldap_first_entry( ldapInfo->ld, result ) ) == NULL )
		{
		ldap_msgfree( result );
		return( CRYPT_ERROR_NOTFOUND );
		}

	/* Copy out the certificate */
	if( ( attributePtr = ldap_first_attribute( ldapInfo->ld, resultEntry, 
											   &ber ) ) == NULL )
		{
		ldap_msgfree( result );
		return( CRYPT_ERROR_NOTFOUND );
		}
	valuePtrs = ldap_get_values_len( ldapInfo->ld, resultEntry, 
									 attributePtr );
	if( valuePtrs != NULL )
		{
		MESSAGE_CREATEOBJECT_INFO createInfo;

		/* Create a certificate object from the returned data */
		setMessageCreateObjectIndirectInfo( &createInfo, valuePtrs[ 0 ]->bv_val,
											valuePtrs[ 0 ]->bv_len,
											CRYPT_CERTTYPE_NONE );
		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
								  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), 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), and OpenLDAP doesn't use it at all.  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 used to
	   require it to be 1 and the MS client was supposed to ignore it so the
	   code passed 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).

	   Later, the Netscape docs were updated to require a 0, presumably to
	   align them with the LDAPv3 spec.  On some systems it makes no
	   difference whether you pass in a 0 or 1 to the call, but on others it
	   can cause an access violation.  Presumably eventually everyone will
	   move to something which implements the new rather than old Netscape-
	   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 (e.g. 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 (e.g. 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 );
	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 *keysetInfoPtr, 
					const CRYPT_HANDLE iCryptHandle )
	{
	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
	LDAPMod *ldapMod[ MAX_LDAP_ATTRIBUTES + 8 ];
	MESSAGE_DATA msgData;
	BYTE keyData[ MAX_CERT_SIZE + 8 ];
	char dn[ MAX_DN_STRINGSIZE + 8 ];
	char C[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], SP[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
		L[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], O[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
		OU[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], CN[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
		email[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
	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 
	   certificate 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, MAX_DN_STRINGSIZE, C, SP, L, O, OU, CN );
		}
	if( cryptStatusError( status ) )
		{
		/* Convert any low-level certificate-specific error into something 
		   generic which makes a bit more sense to the caller */
		return( CRYPT_ARGERROR_NUM1 );
		}

	/* 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 certificate-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 certificate 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 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -