1 /****************************************************************************
2 *																			*
3 *						cryptlib LDAP Mapping Routines						*
4 *					  Copyright Peter Gutmann 1998-2004						*
5 *																			*
6 ****************************************************************************/
7 
8 /* The following code can be built to use most of the various subtly
9    incompatible LDAP clients.  By default the Windows client is used under
10    Windows and the OpenLDAP client is used elsewhere, this can be overridden
11    by defining NETSCAPE_CLIENT which causes the Netscape client to be used
12    instead.  Old versions of the Windows client were considerably more buggy
13    than the Netscape one, so if you get data corruption and other problems
14    try switching to the Netscape client (see the comment next to ber_free()
15    for more details on some of these problems).  Note that there are at least
16    five incompatible LDAP APIs, the one defined in the RFCs, the older
17    OpenLDAP API, the newer OpenLDAP API, the Windows API, and the Netscape
18    API.  The following code tries to auto-adjust itself for all of the
19    different versions, but it may need some hand-tweaking.
20 
21    A generalisation of this is that you shouldn't be using LDAP for
22    certificate storage at all unless you're absolutely forced to.  LDAP
23    is a truly awful mechanism for storing and retrieving certificates,
24    technical reasons for this may be found in the Godzilla crypto tutorial
25    and in any database text written within the last 20 years */
26 
27 #if defined( INC_ALL )
28   #include "crypt.h"
29   #include "keyset.h"
30 #else
31   #include "crypt.h"
32   #include "keyset/keyset.h"
33 #endif /* Compiler-specific includes */
34 
35 #ifdef USE_LDAP
36 
37 #if defined( _MSC_VER ) || defined( __GNUC__ )
38   #pragma message( "  Building with LDAP enabled." )
39 #endif /* Warn with VC++ */
40 
41 /* LDAP requires us to set up complicated structures to handle DN's.  The
42    following values define the upper limit for DN string data and the
43    maximum number of attributes we write to a directory */
44 
45 #define MAX_DN_STRINGSIZE		1024
46 #define MAX_LDAP_ATTRIBUTES		20
47 
48 /* These should really be taken from the system include directory but this
49    leads to too many complaints from people who don't read the LDAP
50    installation section of the manual */
51 
52 #if defined( __WINDOWS__ )
53   /* cryptlib.h includes a trap for inclusion of wincrypt.h before
54      cryptlib.h which results in a compiler error if both files are
55 	 included.  To disable this, we need to undefine the CRYPT_MODE_ECB
56 	 defined in cryptlib.h */
57   #undef CRYPT_MODE_ECB
58   #include <winldap.h>
59   #define LDAP_API		LDAPAPI		/* Windows LDAP API type */
60   #define timeval		l_timeval	/* Windows uses nonstandard name */
61 #elif defined( NETSCAPE_CLIENT )
62   #include <ldap.h>
63   #define LDAP_API		LDAP_CALL	/* Netscape LDAP API type */
64   #define ber_free		ldap_ber_free	/* Netscape uses nonstandard name */
65 #else
66   #include <ldap.h>
67   #include <sys/time.h>				/* For 'struct timeval' */
68   #ifdef LDAP_API
69 	/* Some OpenLDAP versions have their own LDAP_API macro which is
70 	   incompatible with the usage here, so we clear it before we define our
71 	   own */
72 	#undef LDAP_API
73   #endif /* LDAP_API */
74   #define LDAP_API					/* OpenLDAP LDAP API type */
75 #endif /* Different LDAP client types */
76 
77 /****************************************************************************
78 *																			*
79 *						 	Windows Init/Shutdown Routines					*
80 *																			*
81 ****************************************************************************/
82 
83 #ifdef DYNAMIC_LOAD
84 
85 /* Global function pointers.  These are necessary because the functions need
86    to be dynamically linked since older systems won't contain the necessary
87    DLL's.  Explicitly linking to them will make cryptlib unloadable on these
88    systems */
89 
90 static INSTANCE_HANDLE hLDAP = NULL_INSTANCE;
91 
92 typedef void ( LDAP_API *BER_FREE )( BerElement *ber, int freebuf );
93 typedef int ( LDAP_API *LDAP_ADD_S )( LDAP *ld, const char *dn, LDAPMod **attrs );
94 typedef int ( LDAP_API *LDAP_DELETE_S )( LDAP *ld, const char *dn );
95 typedef char * ( LDAP_API *LDAP_ERR2STRING )( int err );
96 typedef char * ( LDAP_API *LDAP_FIRST_ATTRIBUTE )( LDAP *ld, LDAPMessage *entry,
97 										  BerElement **ber );
98 typedef LDAPMessage * ( LDAP_API *LDAP_FIRST_ENTRY )( LDAP *ld, LDAPMessage *result );
99 #if defined( __WINDOWS__ )
100   typedef int ( LDAP_API *LDAP_GETLASTERROR )( void );
101 #elif defined( NETSCAPE_CLIENT )
102   typedef int ( LDAP_API *LDAP_GET_LDERRNO )( LDAP *ld, char **m, char **s );
103 #else
104   typedef int ( LDAP_API *LDAP_GET_OPTION )( LDAP *ld, int option, void *outvalue );
105 #endif /* Different LDAP client types */
106 typedef struct berval ** ( LDAP_API *LDAP_GET_VALUES_LEN )( LDAP *ld, LDAPMessage *entry,
107 												   const char *attr );
108 typedef LDAP * ( LDAP_API *LDAP_INIT )( const char *host, int port );
109 typedef int ( LDAP_API *LDAP_IS_LDAP_URL )( char *url );
110 typedef void ( LDAP_API *LDAP_MEMFREE )( void *p );
111 typedef void ( LDAP_API *LDAP_MODSFREE )( LDAPMod **mods, int freemods );
112 typedef int ( LDAP_API *LDAP_MSGFREE )( LDAPMessage *lm );
113 typedef LDAPMessage * ( LDAP_API *LDAP_NEXT_ENTRY )( LDAP *ld, LDAPMessage *result );
114 typedef int ( LDAP_API *LDAP_SEARCH_ST )( LDAP *ld, const char *base, int scope,
115 								const char *filter, char **attrs,
116 								int attrsonly, struct timeval *timeout,
117 								LDAPMessage **res );
118 typedef int ( LDAP_API *LDAP_SET_OPTION )( LDAP *ld, int option, void *optdata );
119 typedef int ( LDAP_API *LDAP_SIMPLE_BIND_S )( LDAP *ld, const char *who,
120 									 const char *passwd );
121 typedef int ( LDAP_API *LDAP_UNBIND )( LDAP *ld );
122 typedef int ( LDAP_API *LDAP_URL_SEARCH_ST )( LDAP *ld, char *url, int attrsonly,
123 											  struct timeval *timeout,
124 											  LDAPMessage **res );
125 typedef void ( LDAP_API *LDAP_VALUE_FREE_LEN )( struct berval **vals );
126 #if defined( __WINDOWS__ ) || defined( NETSCAPE_CLIENT )
127   static BER_FREE p_ber_free = NULL;
128 #endif /* __WINDOWS__ || NETSCAPE_CLIENT */
129 static LDAP_ADD_S p_ldap_add_s = NULL;
130 static LDAP_DELETE_S p_ldap_delete_s = NULL;
131 static LDAP_ERR2STRING p_ldap_err2string = NULL;
132 static LDAP_FIRST_ATTRIBUTE p_ldap_first_attribute = NULL;
133 static LDAP_FIRST_ENTRY p_ldap_first_entry = NULL;
134 #if defined( __WINDOWS__ )
135   static LDAP_GETLASTERROR p_LdapGetLastError = NULL;
136 #elif defined( NETSCAPE_CLIENT )
137   static LDAP_GET_LDERRNO p_ldap_get_lderrno = NULL;
138 #else
139   static LDAP_GET_OPTION p_ldap_get_option = NULL;
140 #endif /* Different LDAP client types */
141 static LDAP_GET_VALUES_LEN p_ldap_get_values_len = NULL;
142 static LDAP_INIT p_ldap_init = NULL;
143 static LDAP_IS_LDAP_URL p_ldap_is_ldap_url = NULL;
144 static LDAP_MEMFREE p_ldap_memfree = NULL;
145 static LDAP_NEXT_ENTRY p_ldap_next_entry = NULL;
146 static LDAP_MSGFREE p_ldap_msgfree = NULL;
147 static LDAP_SEARCH_ST p_ldap_search_st = NULL;
148 static LDAP_SET_OPTION p_ldap_set_option = NULL;
149 static LDAP_SIMPLE_BIND_S p_ldap_simple_bind_s = NULL;
150 static LDAP_UNBIND p_ldap_unbind = NULL;
151 static LDAP_URL_SEARCH_ST p_ldap_url_search_st = NULL;
152 static LDAP_VALUE_FREE_LEN p_ldap_value_free_len = NULL;
153 
154 /* The use of dynamically bound function pointers vs.statically linked
155    functions requires a bit of sleight of hand since we can't give the
156    pointers the same names as prototyped functions.  To get around this we
157    redefine the actual function names to the names of the pointers */
158 
159 #define ber_free				p_ber_free
160 #define ldap_add_s				p_ldap_add_s
161 #define ldap_delete_s			p_ldap_delete_s
162 #define ldap_err2string			p_ldap_err2string
163 #define ldap_first_attribute	p_ldap_first_attribute
164 #define ldap_first_entry		p_ldap_first_entry
165 #if defined( __WINDOWS__ )
166   #define LdapGetLastError		p_LdapGetLastError
167 #elif defined( NETSCAPE_CLIENT )
168   #define ldap_get_lderrno		p_ldap_get_lderrno
169 #else
170   #define ldap_get_option		p_ldap_get_option
171 #endif /* Different LDAP client types */
172 #define ldap_get_values_len		p_ldap_get_values_len
173 #define ldap_init				p_ldap_init
174 #define ldap_is_ldap_url		p_ldap_is_ldap_url
175 #define ldap_memfree			p_ldap_memfree
176 #define ldap_msgfree			p_ldap_msgfree
177 #define ldap_next_entry			p_ldap_next_entry
178 #define ldap_search_st			p_ldap_search_st
179 #define ldap_set_option			p_ldap_set_option
180 #define ldap_simple_bind_s		p_ldap_simple_bind_s
181 #define ldap_unbind				p_ldap_unbind
182 #define ldap_url_search_st		p_ldap_url_search_st
183 #define ldap_value_free_len		p_ldap_value_free_len
184 
185 /* The name of the LDAP driver, in this case the Netscape LDAPv3 driver */
186 
187 #ifdef __WIN16__
188   #define LDAP_LIBNAME			"NSLDSS16.DLL"
189 #elif defined( __WIN32__ )
190   #define LDAP_LIBNAME			"wldap32.dll"
191 #elif defined( __UNIX__ )
192   #if defined( __APPLE__ )
193 	/* OS X has built-in LDAP support via OpenLDAP */
194 	#define LDAP_LIBNAME		"libldap.dylib"
195   #elif defined NETSCAPE_CLIENT
196 	#define LDAP_LIBNAME		"libldap50.so"
197   #else
198 	#define LDAP_LIBNAME		"libldap.so"
199   #endif /* NETSCAPE_CLIENT */
200 #endif /* System-specific ODBC library names */
201 
202 /* Dynamically load and unload any necessary LDAP libraries */
203 
204 CHECK_RETVAL \
dbxInitLDAP(void)205 int dbxInitLDAP( void )
206 	{
207 #ifdef __WIN16__
208 	UINT errorMode;
209 #endif /* __WIN16__ */
210 
211 	/* If the LDAP module is already linked in, don't do anything */
212 	if( hLDAP != NULL_INSTANCE )
213 		return( CRYPT_OK );
214 
215 	/* Obtain a handle to the module containing the LDAP functions */
216 #ifdef __WIN16__
217 	errorMode = SetErrorMode( SEM_NOOPENFILEERRORBOX );
218 	hLDAP = LoadLibrary( LDAP_LIBNAME );
219 	SetErrorMode( errorMode );
220 	if( hLDAP < HINSTANCE_ERROR )
221 		{
222 		hLDAP = NULL_INSTANCE;
223 		return( CRYPT_ERROR );
224 		}
225 #else
226 	if( ( hLDAP = DynamicLoad( LDAP_LIBNAME ) ) == NULL_INSTANCE )
227 		return( CRYPT_ERROR );
228 #endif /* __WIN32__ */
229 
230 	/* Now get pointers to the functions */
231 #if defined( __WINDOWS__ )
232 	p_ber_free = ( BER_FREE ) DynamicBind( hLDAP, "ber_free" );
233 #elif defined( NETSCAPE_CLIENT )
234 	p_ber_free = ( BER_FREE ) DynamicBind( hLDAP, "ldap_ber_free" );
235 #endif /* __WINDOWS__ || NETSCAPE_CLIENT */
236 	p_ldap_add_s = ( LDAP_ADD_S ) DynamicBind( hLDAP, "ldap_add_s" );
237 	p_ldap_delete_s = ( LDAP_DELETE_S ) DynamicBind( hLDAP, "ldap_delete_s" );
238 	p_ldap_err2string = ( LDAP_ERR2STRING ) DynamicBind( hLDAP, "ldap_err2string" );
239 	p_ldap_first_attribute = ( LDAP_FIRST_ATTRIBUTE ) DynamicBind( hLDAP, "ldap_first_attribute" );
240 	p_ldap_first_entry = ( LDAP_FIRST_ENTRY ) DynamicBind( hLDAP, "ldap_first_entry" );
241 #if defined( __WINDOWS__ )
242 	p_LdapGetLastError = ( LDAP_GETLASTERROR ) DynamicBind( hLDAP, "LdapGetLastError" );
243 #elif defined( NETSCAPE_CLIENT )
244 	p_ldap_get_lderrno = ( LDAP_GET_LDERRNO ) DynamicBind( hLDAP, "ldap_get_lderrno" );
245 #else
246 	p_ldap_get_option = ( LDAP_GET_OPTION ) DynamicBind( hLDAP, "ldap_get_option" );
247 #endif /* Different LDAP client types */
248 	p_ldap_get_values_len = ( LDAP_GET_VALUES_LEN ) DynamicBind( hLDAP, "ldap_get_values_len" );
249 	p_ldap_init = ( LDAP_INIT ) DynamicBind( hLDAP, "ldap_init" );
250 	p_ldap_is_ldap_url = ( LDAP_IS_LDAP_URL ) DynamicBind( hLDAP, "ldap_is_ldap_url" );
251 	p_ldap_memfree = ( LDAP_MEMFREE ) DynamicBind( hLDAP, "ldap_memfree" );
252 	p_ldap_msgfree = ( LDAP_MSGFREE ) DynamicBind( hLDAP, "ldap_msgfree" );
253 	p_ldap_next_entry = ( LDAP_NEXT_ENTRY ) DynamicBind( hLDAP, "ldap_next_entry" );
254 	p_ldap_search_st = ( LDAP_SEARCH_ST ) DynamicBind( hLDAP, "ldap_search_st" );
255 	p_ldap_set_option = ( LDAP_SET_OPTION ) DynamicBind( hLDAP, "ldap_set_option" );
256 	p_ldap_simple_bind_s = ( LDAP_SIMPLE_BIND_S ) DynamicBind( hLDAP, "ldap_simple_bind_s" );
257 	p_ldap_unbind = ( LDAP_UNBIND ) DynamicBind( hLDAP, "ldap_unbind" );
258 	p_ldap_url_search_st = ( LDAP_URL_SEARCH_ST ) DynamicBind( hLDAP, "ldap_url_search_st" );
259 	p_ldap_value_free_len = ( LDAP_VALUE_FREE_LEN ) DynamicBind( hLDAP, "ldap_value_free_len" );
260 
261 	/* Make sure that we got valid pointers for every LDAP function */
262 	if( p_ldap_add_s == NULL ||
263 #ifdef NETSCAPE_CLIENT
264 		p_ber_free == NULL ||
265 #endif /* NETSCAPE_CLIENT */
266 		p_ldap_delete_s == NULL || p_ldap_err2string == NULL || \
267 		p_ldap_first_attribute == NULL || p_ldap_first_entry == NULL || \
268 		p_ldap_init == NULL ||
269 #if defined( __WINDOWS__ )
270 		p_LdapGetLastError == NULL ||
271 #elif defined( NETSCAPE_CLIENT )
272 		p_ldap_get_lderrno == NULL || p_ldap_is_ldap_url == NULL ||
273 		p_ldap_url_search_st == NULL ||
274 #else
275 		p_ldap_get_option == NULL ||
276 #endif /* NETSCAPE_CLIENT */
277 		p_ldap_get_values_len == NULL || p_ldap_memfree == NULL || \
278 		p_ldap_msgfree == NULL || p_ldap_next_entry == NULL || \
279 		p_ldap_search_st == NULL || p_ldap_set_option == NULL || \
280 		p_ldap_simple_bind_s == NULL || p_ldap_unbind == NULL || \
281 		p_ldap_value_free_len == NULL )
282 		{
283 		/* Free the library reference and reset the handle */
284 		DynamicUnload( hLDAP );
285 		hLDAP = NULL_INSTANCE;
286 		return( CRYPT_ERROR );
287 		}
288 
289 	/* Some versions of OpenLDAP define ldap_is_ldap_url() but not
290 	   ldap_url_search_st() (which makes the former more or less useless),
291 	   so if the latter isn't defined we remove the former as well */
292 	if( p_ldap_url_search_st == NULL )
293 		p_ldap_is_ldap_url = NULL;
294 
295 	return( CRYPT_OK );
296 	}
297 
dbxEndLDAP(void)298 void dbxEndLDAP( void )
299 	{
300 	if( hLDAP != NULL_INSTANCE )
301 		DynamicUnload( hLDAP );
302 	hLDAP = NULL_INSTANCE;
303 	}
304 #else
305 
306 CHECK_RETVAL \
dbxInitLDAP(void)307 int dbxInitLDAP( void )
308 	{
309 	return( CRYPT_OK );
310 	}
311 
dbxEndLDAP(void)312 void dbxEndLDAP( void )
313 	{
314 	}
315 #endif /* __WINDOWS__ */
316 
317 /****************************************************************************
318 *																			*
319 *						 		Utility Routines							*
320 *																			*
321 ****************************************************************************/
322 
323 /* Assign a name for an LDAP object/attribute field */
324 
assignFieldName(const CRYPT_USER cryptOwner,char * buffer,CRYPT_ATTRIBUTE_TYPE option)325 static void assignFieldName( const CRYPT_USER cryptOwner, char *buffer,
326 							 CRYPT_ATTRIBUTE_TYPE option )
327 	{
328 	MESSAGE_DATA msgData;
329 	int status;
330 
331 	setMessageData( &msgData, buffer, CRYPT_MAX_TEXTSIZE );
332 	status = krnlSendMessage( cryptOwner, IMESSAGE_GETATTRIBUTE_S,
333 							  &msgData, option );
334 	assert( cryptStatusOK( status ) );
335 	buffer[ msgData.length ] = '\0';
336 	}
337 
338 /* Get information on an LDAP error */
339 
getErrorInfo(KEYSET_INFO * keysetInfoPtr,int ldapStatus)340 static void getErrorInfo( KEYSET_INFO *keysetInfoPtr, int ldapStatus )
341 	{
342 #ifdef USE_ERRMSGS
343 	ERROR_INFO *errorInfo = &keysetInfoPtr->errorInfo;
344 #endif /* USE_ERRMSGS */
345 #ifndef __WINDOWS__
346 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
347 #endif /* !__WINDOWS__ */
348 #ifdef __WINDOWS__
349 	int errorCode;
350 #endif /* __WINDOWS__ */
351 	char *errorMessage;
352 
353 #if defined( __WINDOWS__ )
354 	errorCode = LdapGetLastError();
355 	if( errorCode == LDAP_SUCCESS )
356 		{
357 		/* In true Microsoft fashion LdapGetLastError() can return
358 		   LDAP_SUCCESS with the error string set to "Success." so if we
359 		   get this we use the status value returned by the original LDAP
360 		   function call instead */
361 		errorCode = ldapStatus;
362 		}
363 	errorMessage = ldap_err2string( errorCode );
364   #if 0
365 	/* The exact conditions under which ldap_err2string() does something
366 	   useful are somewhat undefined, it may be necessary to use the
367 	   following which works with general Windows error codes rather than
368 	   special-case LDAP function result codes */
369 	errorCode = GetLastError();
370 	FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
371 				   NULL, errorCode, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
372 				   ldapInfo->errorMessage, MAX_ERRMSG_SIZE - 1, NULL );
373   #endif /* 0 */
374 #elif defined( NETSCAPE_CLIENT )
375 	ldap_get_lderrno( ldapInfo->ld, NULL, &errorMessage );
376 #else
377 	ldap_get_option( ldapInfo->ld, LDAP_OPT_ERROR_STRING, &errorMessage );
378 #endif /* Different LDAP client types */
379 	if( errorMessage != NULL )
380 		{
381 		setErrorString( errorInfo, errorMessage, strlen( errorMessage ) );
382 		}
383 	else
384 		clearErrorString( errorInfo );
385 	}
386 
387 /* Map an LDAP error to the corresponding cryptlib error.  The various LDAP
388    imlpementations differ slightly in their error codes, so we have to
389    adjust them as appropriate */
390 
mapLdapError(const int ldapError,const int defaultError)391 static int mapLdapError( const int ldapError, const int defaultError )
392 	{
393 	switch( ldapError )
394 		{
395 		case LDAP_INAPPROPRIATE_AUTH:
396 		case LDAP_INVALID_CREDENTIALS:
397 		case LDAP_AUTH_UNKNOWN:
398 #if defined( __WINDOWS__ )
399 		case LDAP_INSUFFICIENT_RIGHTS:
400 		case LDAP_AUTH_METHOD_NOT_SUPPORTED:
401 #elif defined( NETSCAPE_CLIENT )
402 		case LDAP_INSUFFICIENT_ACCESS:
403 #else
404 		case LDAP_INSUFFICIENT_ACCESS:
405 		case LDAP_AUTH_METHOD_NOT_SUPPORTED:
406 #endif /* Different client types */
407 			return( CRYPT_ERROR_PERMISSION );
408 
409 #if defined( __WINDOWS__ )
410 		case LDAP_ATTRIBUTE_OR_VALUE_EXISTS:
411 		case LDAP_ALREADY_EXISTS:
412 #elif defined( NETSCAPE_CLIENT )
413 		case LDAP_TYPE_OR_VALUE_EXISTS:
414 #else
415 		case LDAP_TYPE_OR_VALUE_EXISTS:
416 		case LDAP_ALREADY_EXISTS:
417 #endif /* Different client types */
418 			return( CRYPT_ERROR_DUPLICATE );
419 
420 #if defined( __WINDOWS__ )
421 		case LDAP_CONFIDENTIALITY_REQUIRED:
422 #elif defined( NETSCAPE_CLIENT )
423 		/* Nothing */
424 #else
425 		case LDAP_CONFIDENTIALITY_REQUIRED:
426 		case LDAP_STRONG_AUTH_REQUIRED:
427 			return( CRYPT_ERROR_NOSECURE );
428 #endif /* Different client types */
429 
430 		case LDAP_INVALID_DN_SYNTAX:
431 			return( CRYPT_ARGERROR_STR1 );
432 
433 		case LDAP_TIMELIMIT_EXCEEDED:
434 		case LDAP_TIMEOUT:
435 			return( CRYPT_ERROR_TIMEOUT );
436 
437 #ifndef NETSCAPE_CLIENT
438 		case LDAP_NO_RESULTS_RETURNED:
439 #endif /* NETSCAPE_CLIENT */
440 		case LDAP_NO_SUCH_ATTRIBUTE:
441 		case LDAP_NO_SUCH_OBJECT:
442 			return( CRYPT_ERROR_NOTFOUND );
443 
444 #ifndef NETSCAPE_CLIENT
445 		case LDAP_NOT_SUPPORTED:
446 		case LDAP_UNAVAILABLE:
447 			return( CRYPT_ERROR_NOTAVAIL );
448 #endif /* NETSCAPE_CLIENT */
449 
450 		case LDAP_SIZELIMIT_EXCEEDED:
451 		case LDAP_RESULTS_TOO_LARGE:
452 			return( CRYPT_ERROR_OVERFLOW );
453 
454 		case LDAP_NO_MEMORY:
455 			return( CRYPT_ERROR_MEMORY );
456 		}
457 
458 	return( defaultError );
459 	}
460 
461 /* Copy attribute information into an LDAPMod structure so it can be written to
462    the directory */
463 
copyAttribute(const char * attributeName,const void * attributeValue,const int attributeLength)464 static LDAPMod *copyAttribute( const char *attributeName,
465 							   const void *attributeValue,
466 							   const int attributeLength )
467 	{
468 	LDAPMod *ldapModPtr;
469 
470 	/* Allocate room for the LDAPMod structure */
471 	if( ( ldapModPtr = ( LDAPMod * ) clAlloc( "copyAttribute", \
472 											  sizeof( LDAPMod ) ) ) == NULL )
473 		return( NULL );
474 
475 	/* Set up the pointers to the attribute information.  This differs
476 	   slightly depending on whether we're adding text or binary data */
477 	if( !attributeLength )
478 		{
479 		if( ( ldapModPtr->mod_values = \
480 					clAlloc( "copyAttribute", \
481 							 2 * sizeof( void * ) ) ) == NULL )
482 			{
483 			clFree( "copyAttribute", ldapModPtr );
484 			return( NULL );
485 			}
486 		ldapModPtr->mod_op = LDAP_MOD_ADD;
487 		ldapModPtr->mod_type = ( char * ) attributeName;
488 		ldapModPtr->mod_values[ 0 ] = ( char * ) attributeValue;
489 		ldapModPtr->mod_values[ 1 ] = NULL;
490 		}
491 	else
492 		{
493 		if( ( ldapModPtr->mod_bvalues = \
494 					clAlloc( "copyAttribute", \
495 							 2 * sizeof( struct berval ) ) ) == NULL )
496 			{
497 			clFree( "copyAttribute", ldapModPtr );
498 			return( NULL );
499 			}
500 		ldapModPtr->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
501 		ldapModPtr->mod_type = ( char * ) attributeName;
502 		ldapModPtr->mod_bvalues[ 0 ]->bv_len = attributeLength;
503 		ldapModPtr->mod_bvalues[ 0 ]->bv_val = ( char * ) attributeValue;
504 		ldapModPtr->mod_bvalues[ 1 ] = NULL;
505 		}
506 
507 	return( ldapModPtr );
508 	}
509 
510 /* Encode DN information in the RFC 1779 reversed format.  We don't have to
511    explicitly check for overflows (which will lead to truncation of the
512    resulting encoded DN) because the certificate management code limits the
513    size of each component to a small fraction of the total buffer size.
514    Besides which, it's LDAP, anyone using this crap as a certificate store
515    is asking for it anyway */
516 
catComponent(char * dest,const int destLen,char * src)517 static void catComponent( char *dest, const int destLen, char *src )
518 	{
519 	int i;
520 
521 	/* Find the end of the existing destination string */
522 	for( i = 0; i < destLen && dest[ i ] != '\0'; i++ );
523 	if( i >= destLen )
524 		retIntError_Void();
525 
526 	/* Append the source string, escaping special chars */
527 	while( i < destLen - 1 && *src != '\0' )
528 		{
529 		const char ch = *src++;
530 
531 		if( ch == ',' )
532 			{
533 			dest[ i++ ] = '\\';
534 			if( i >= destLen )
535 				break;
536 			}
537 		dest[ i++ ] = ch;
538 		}
539 	dest[ i ] = '\0';
540 	}
541 
encodeDN(char * dn,const int maxDnLen,char * C,char * SP,char * L,char * O,char * OU,char * CN)542 static int encodeDN( char *dn, const int maxDnLen, char *C, char *SP,
543 					 char *L, char *O, char *OU, char *CN )
544 	{
545 	strlcpy_s( dn, maxDnLen, "CN=" );
546 	catComponent( dn, maxDnLen, CN );
547 	if( *OU )
548 		{
549 		strlcat_s( dn, maxDnLen, ",OU=" );
550 		catComponent( dn, maxDnLen, OU );
551 		}
552 	if( *O )
553 		{
554 		strlcat_s( dn, maxDnLen, ",O=" );
555 		catComponent( dn, maxDnLen, O );
556 		}
557 	if( *L )
558 		{
559 		strlcat_s( dn, maxDnLen, ",L=" );
560 		catComponent( dn, maxDnLen, L );
561 		}
562 	if( *SP )
563 		{
564 		strlcat_s( dn, maxDnLen, ",ST=" );	/* Not to be confused with ST=street */
565 		catComponent( dn, maxDnLen, SP );
566 		}
567 	strlcat_s( dn, maxDnLen, ",C=" );
568 	catComponent( dn, maxDnLen, C );
569 
570 	return( CRYPT_OK );
571 	}
572 
573 /****************************************************************************
574 *																			*
575 *						 	Directory Open/Close Routines					*
576 *																			*
577 ****************************************************************************/
578 
579 /* Close a previously-opened LDAP connection.  We have to have this before
580    the init function since it may be called by it if the open process fails.
581    This is necessary because the complex LDAP open may require a fairly
582    extensive cleanup afterwards */
583 
584 STDC_NONNULL_ARG( ( 1 ) ) \
shutdownFunction(INOUT KEYSET_INFO * keysetInfoPtr)585 static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
586 	{
587 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
588 
589 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
590 
591 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
592 
593 	ldap_unbind( ldapInfo->ld );
594 	ldapInfo->ld = NULL;
595 
596 	return( CRYPT_OK );
597 	}
598 
599 /* Open a connection to an LDAP directory */
600 
601 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initFunction(INOUT KEYSET_INFO * keysetInfoPtr,IN_BUFFER (nameLength)const char * name,IN_LENGTH_SHORT const int nameLength,IN_ENUM (CRYPT_KEYOPT)const CRYPT_KEYOPT_TYPE options)602 static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
603 						 IN_BUFFER( nameLength ) const char *name,
604 						 IN_LENGTH_SHORT const int nameLength,
605 						 IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
606 	{
607 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
608 	URL_INFO urlInfo;
609 	const char *ldapUser = NULL;
610 	char ldapServer[ MAX_URL_SIZE + 8 ];
611 	int maxEntries = 2, timeout, ldapPort, ldapStatus = LDAP_OTHER, status;
612 
613 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
614 	assert( isReadPtr( name, nameLength ) );
615 
616 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
617 	REQUIRES( nameLength >= MIN_URL_SIZE && nameLength < MAX_URL_SIZE );
618 	REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
619 
620 	/* Check the URL.  The Netscape and OpenLDAP APIs provide the function
621 	   ldap_is_ldap_url() for this, but this requires a complete LDAP URL
622 	   rather than just a server name and port */
623 	if( nameLength > MAX_URL_SIZE - 1 )
624 		return( CRYPT_ARGERROR_STR1 );
625 	status = sNetParseURL( &urlInfo, name, nameLength, URL_TYPE_LDAP );
626 	if( cryptStatusError( status ) )
627 		return( CRYPT_ARGERROR_STR1 );
628 	memcpy( ldapServer, urlInfo.host, urlInfo.hostLen );
629 	ldapServer[ urlInfo.hostLen ] = '\0';
630 	ldapPort = ( urlInfo.port > 0 ) ? urlInfo.port : LDAP_PORT;
631 	if( urlInfo.locationLen > 0 )
632 		ldapUser = urlInfo.location;
633 
634 	/* Open the connection to the server */
635 	if( ( ldapInfo->ld = ldap_init( ldapServer, ldapPort ) ) == NULL )
636 		return( CRYPT_ERROR_OPEN );
637 	if( ( ldapStatus = ldap_simple_bind_s( ldapInfo->ld, ldapUser,
638 										   NULL ) ) != LDAP_SUCCESS )
639 		{
640 		getErrorInfo( keysetInfoPtr, ldapStatus );
641 		ldap_unbind( ldapInfo->ld );
642 		ldapInfo->ld = NULL;
643 		return( mapLdapError( ldapStatus, CRYPT_ERROR_OPEN ) );
644 		}
645 
646 	/* Set the search timeout and limit the maximum number of returned
647 	   entries to 2 (setting the search timeout is mostly redundant since we
648 	   use search_st anyway, however there may be other operations which also
649 	   require some sort of timeout which can't be explicitly specified */
650 	krnlSendMessage( keysetInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
651 					 &timeout, CRYPT_OPTION_NET_READTIMEOUT );
652 	if( timeout < 15 )
653 		{
654 		/* Network I/O may be set to be nonblocking, so we make sure we try
655 		   for at least 15s before timing out */
656 		timeout = 15;
657 		}
658 	ldap_set_option( ldapInfo->ld, LDAP_OPT_TIMELIMIT, &timeout );
659 	ldap_set_option( ldapInfo->ld, LDAP_OPT_SIZELIMIT, &maxEntries );
660 
661 	/* Set up the names of the objects and attributes */
662 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameObjectClass,
663 					 CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS );
664 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameFilter,
665 					 CRYPT_OPTION_KEYS_LDAP_FILTER );
666 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCACert,
667 					 CRYPT_OPTION_KEYS_LDAP_CACERTNAME );
668 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCert,
669 					 CRYPT_OPTION_KEYS_LDAP_CERTNAME );
670 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameCRL,
671 					 CRYPT_OPTION_KEYS_LDAP_CRLNAME );
672 	assignFieldName( keysetInfoPtr->ownerHandle, ldapInfo->nameEmail,
673 					 CRYPT_OPTION_KEYS_LDAP_EMAILNAME );
674 	krnlSendMessage( keysetInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE,
675 					 &ldapInfo->objectType,
676 					 CRYPT_OPTION_KEYS_LDAP_OBJECTTYPE );
677 
678 	return( CRYPT_OK );
679 	}
680 
681 /****************************************************************************
682 *																			*
683 *						 	Directory Access Routines						*
684 *																			*
685 ****************************************************************************/
686 
687 /* Send a query to an LDAP server */
688 
sendLdapQuery(LDAP_INFO * ldapInfo,LDAPMessage ** resultPtr,const CRYPT_HANDLE iOwnerHandle,const char * dn)689 static int sendLdapQuery( LDAP_INFO *ldapInfo, LDAPMessage **resultPtr,
690 						  const CRYPT_HANDLE iOwnerHandle, const char *dn )
691 	{
692 	const CRYPT_CERTTYPE_TYPE objectType = ldapInfo->objectType;
693 	const char *certAttributes[] = { ldapInfo->nameCert, NULL };
694 	const char *caCertAttributes[] = { ldapInfo->nameCACert, NULL };
695 	const char *crlAttributes[] = { ldapInfo->nameCRL, NULL };
696 	struct timeval ldapTimeout = { 0, 0 };
697 	int ldapStatus = LDAP_OTHER, timeout;
698 
699 	/* Network I/O may be set to be nonblocking, so we make sure we try for
700 	   at least 15s before timing out */
701 	krnlSendMessage( iOwnerHandle, IMESSAGE_GETATTRIBUTE, &timeout,
702 					 CRYPT_OPTION_NET_READTIMEOUT );
703 	ldapTimeout.tv_sec = max( timeout, 15 );
704 
705 	/* If the LDAP search-by-URL functions are available and the key ID is
706 	   an LDAP URL, perform a search by URL */
707 	if( ldap_is_ldap_url != NULL && ldap_is_ldap_url( ( char * ) dn ) )
708 		{
709 		return( ldap_url_search_st( ldapInfo->ld, ( char * ) dn, FALSE,
710 									&ldapTimeout, resultPtr ) );
711 		}
712 
713 	/* Try and retrieve the entry for this DN from the directory.  We use a
714 	   base specified by the DN, a chop of 0 (to return only the current
715 	   entry), any object class (to get around the problem of
716 	   implementations which stash certificates in whatever they feel like),
717 	   and look for a certificate attribute.  If the search fails for this
718 	   attribute, we try again but this time go for a CA certificate
719 	   attribute which unfortunately slows down the search somewhat when the
720 	   certificate isn't found but can't really be avoided since there's no
721 	   way to tell in advance whether a certificate will be an end entity or
722 	   a CA certificate.  To complicate things even further, we may also
723 	   need to check for a CRL in case this is what the user is after */
724 	if( objectType == CRYPT_CERTTYPE_NONE || \
725 		objectType == CRYPT_CERTTYPE_CERTIFICATE )
726 		{
727 		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
728 									 ldapInfo->nameFilter,
729 									 ( char ** ) certAttributes, 0,
730 									 &ldapTimeout, resultPtr );
731 		if( ldapStatus == LDAP_SUCCESS )
732 			return( ldapStatus );
733 		}
734 	if( objectType == CRYPT_CERTTYPE_NONE || \
735 		objectType == CRYPT_CERTTYPE_CERTIFICATE )
736 		{
737 		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
738 									 ldapInfo->nameFilter,
739 									 ( char ** ) caCertAttributes, 0,
740 									 &ldapTimeout, resultPtr );
741 		if( ldapStatus == LDAP_SUCCESS )
742 			return( ldapStatus );
743 		}
744 	if( objectType == CRYPT_CERTTYPE_NONE || \
745 		objectType == CRYPT_CERTTYPE_CRL )
746 		{
747 		ldapStatus = ldap_search_st( ldapInfo->ld, dn, LDAP_SCOPE_BASE,
748 									 ldapInfo->nameFilter,
749 									 ( char ** ) crlAttributes, 0,
750 									 &ldapTimeout, resultPtr );
751 		if( ldapStatus == LDAP_SUCCESS )
752 			return( ldapStatus );
753 		}
754 
755 	return( ldapStatus );
756 	}
757 
758 /* Retrieve a key attribute from an LDAP directory */
759 
760 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
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,STDC_UNUSED void * auxInfo,STDC_UNUSED int * auxInfoLength,IN_FLAGS_Z (KEYMGMT)const int flags)761 static int getItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
762 							OUT_HANDLE_OPT CRYPT_HANDLE *iCryptHandle,
763 							IN_ENUM( KEYMGMT_ITEM ) \
764 								const KEYMGMT_ITEM_TYPE itemType,
765 							IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
766 							IN_BUFFER( keyIDlength ) const void *keyID,
767 							IN_LENGTH_KEYID const int keyIDlength,
768 							STDC_UNUSED void *auxInfo,
769 							STDC_UNUSED int *auxInfoLength,
770 							IN_FLAGS_Z( KEYMGMT ) const int flags )
771 	{
772 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
773 	LDAPMessage *result DUMMY_INIT_PTR, *resultEntry;
774 	BerElement *ber;
775 	struct berval **valuePtrs;
776 	char dn[ MAX_DN_STRINGSIZE + 8 ];
777 	char *attributePtr;
778 	int ldapStatus, status = CRYPT_OK;
779 
780 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
781 	assert( isWritePtr( iCryptHandle, sizeof( CRYPT_HANDLE ) ) );
782 	assert( isReadPtr( keyID, keyIDlength ) );
783 
784 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
785 	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
786 	REQUIRES( keyIDtype != CRYPT_KEYID_NONE || iCryptHandle != NULL );
787 	REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
788 			  keyIDlength < MAX_ATTRIBUTE_SIZE );
789 	REQUIRES( auxInfo == NULL && *auxInfoLength == 0 );
790 	REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX );
791 
792 	/* Clear return value */
793 	*iCryptHandle = CRYPT_ERROR;
794 
795 	/* Convert the DN into a null-terminated form */
796 	if( keyIDlength > MAX_DN_STRINGSIZE - 1 )
797 		return( CRYPT_ARGERROR_STR1 );
798 	memcpy( dn, keyID, keyIDlength );
799 	dn[ keyIDlength ] = '\0';
800 
801 	/* Send the LDAP query to the server */
802 	ldapStatus = sendLdapQuery( ldapInfo, &result,
803 								keysetInfoPtr->ownerHandle, dn );
804 	if( ldapStatus != LDAP_SUCCESS )
805 		{
806 		getErrorInfo( keysetInfoPtr, ldapStatus );
807 		return( mapLdapError( ldapStatus, CRYPT_ERROR_READ ) );
808 		}
809 
810 	/* We got something, start fetching the results */
811 	if( ( resultEntry = ldap_first_entry( ldapInfo->ld, result ) ) == NULL )
812 		{
813 		ldap_msgfree( result );
814 		return( CRYPT_ERROR_NOTFOUND );
815 		}
816 
817 	/* Copy out the certificate */
818 	if( ( attributePtr = ldap_first_attribute( ldapInfo->ld, resultEntry,
819 											   &ber ) ) == NULL )
820 		{
821 		ldap_msgfree( result );
822 		return( CRYPT_ERROR_NOTFOUND );
823 		}
824 	valuePtrs = ldap_get_values_len( ldapInfo->ld, resultEntry,
825 									 attributePtr );
826 	if( valuePtrs != NULL )
827 		{
828 		MESSAGE_CREATEOBJECT_INFO createInfo;
829 
830 		/* Create a certificate object from the returned data */
831 		setMessageCreateObjectIndirectInfo( &createInfo, valuePtrs[ 0 ]->bv_val,
832 											valuePtrs[ 0 ]->bv_len,
833 											CRYPT_CERTTYPE_NONE );
834 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
835 								  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
836 								  &createInfo, OBJECT_TYPE_CERTIFICATE );
837 		if( cryptStatusOK( status ) )
838 			{
839 			status = iCryptVerifyID( createInfo.cryptHandle, keyIDtype,
840 									 keyID, keyIDlength );
841 			if( cryptStatusError( status ) )
842 				{
843 				krnlSendNotifier( createInfo.cryptHandle,
844 								  IMESSAGE_DECREFCOUNT );
845 				}
846 			else
847 				*iCryptHandle = createInfo.cryptHandle;
848 			}
849 		ldap_value_free_len( valuePtrs );
850 		}
851 	else
852 		status = CRYPT_ERROR_NOTFOUND;
853 
854 	/* Clean up.  The ber_free() function is rather problematic because
855 	   Netscape uses the nonstandard ldap_ber_free() name (which can be fixed
856 	   with proprocessor trickery), Microsoft first omitted it entirely (up
857 	   to NT4 SP4) and then later added it as a stub (Win2K, rumour has it
858 	   that the only reason this function even exists is because the Netscape
859 	   client required it), and OpenLDAP doesn't use it at all.  Because it
860 	   may or may not exist in the MS client, we call it if we resolved its
861 	   address, otherwise we skip it.
862 
863 	   The function is further complicated by the fact that LDAPv3 says the
864 	   second parameter should be 0, however the Netscape client docs used to
865 	   require it to be 1 and the MS client was supposed to ignore it so the
866 	   code passed in a 1.  Actually the way the MS implementation handles
867 	   the BER data is that the BerElement returned by ldap_first_attribute()
868 	   is (despite what the MSDN docs claim) just a data structure pointed to
869 	   by lm_ber in the LDAPMessage structure, all that
870 	   ldap_first_attribute() does is redirect the lm_ber pointer inside the
871 	   LDAPMessage, so actually freeing this wouldn't be a good idea).
872 
873 	   Later, the Netscape docs were updated to require a 0, presumably to
874 	   align them with the LDAPv3 spec.  On some systems it makes no
875 	   difference whether you pass in a 0 or 1 to the call, but on others it
876 	   can cause an access violation.  Presumably eventually everyone will
877 	   move to something which implements the new rather than old Netscape-
878 	   documented behaviour, so we pass in 0 as the argument.
879 
880 	   It gets worse than this though.  Calling ber_free() with newer
881 	   versions of the Windows LDAP client with any argument at all causes
882 	   internal data corruption which typically first results in a soft
883 	   failure (e.g. a data fetch fails) and then eventually a hard failure
884 	   such as an access violation after further calls are made.  The only
885 	   real way to fix this is to avoid calling it entirely, this doesn't
886 	   seem to leak any more memory than Winsock leaks anyway (that is,
887 	   there are a considerable number of memory and handle leaks, but the
888 	   number doesn't increase if ber_free() isn't called).
889 
890 	   There have been reports that with some older versions of the Windows
891 	   LDAP client (e.g. the one in Win95) the ldap_msgfree() call generates
892 	   an exception in wldap.dll, if this is a problem you need to either
893 	   install a newer LDAP DLL or switch to the Netscape one.
894 
895 	   The reason for some of the Windows problems are because the
896 	   wldap32.lib shipped with VC++ uses different ordinals than the
897 	   wldap32.dll which comes with the OS (see MSKB article Q283199), so
898 	   that simply using the out-of-the-box development tools with the out-
899 	   of-the-box OS can result in access violations and assorted other
900 	   problems */
901 #ifdef NETSCAPE_CLIENT
902 	if( ber_free != NULL )
903 		ber_free( ber, 0 );
904 #endif /* NETSCAPE_CLIENT */
905 	ldap_memfree( attributePtr );
906 	ldap_msgfree( result );
907 
908 	return( status );
909 	}
910 
911 /* Add an entry/attribute to an LDAP directory.  The LDAP behaviour differs
912    somewhat from DAP in that assigning a value to a nonexistant attribute
913    implicitly creates the required attribute.  In addition deleting the last
914    value automatically deletes the entire attribute, the delete item code
915    assumes the user is requesting a superset of this behaviour and deletes
916    the entire entry */
917 
addCert(KEYSET_INFO * keysetInfoPtr,const CRYPT_HANDLE iCryptHandle)918 static int addCert( KEYSET_INFO *keysetInfoPtr,
919 					const CRYPT_HANDLE iCryptHandle )
920 	{
921 	static const int nameValue = CRYPT_CERTINFO_SUBJECTNAME;
922 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
923 	LDAPMod *ldapMod[ MAX_LDAP_ATTRIBUTES + 8 ];
924 	MESSAGE_DATA msgData;
925 	BYTE keyData[ MAX_CERT_SIZE + 8 ];
926 	char dn[ MAX_DN_STRINGSIZE + 8 ];
927 	char C[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], SP[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
928 		L[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], O[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
929 		OU[ CRYPT_MAX_TEXTSIZE + 1 + 8 ], CN[ CRYPT_MAX_TEXTSIZE + 1 + 8 ],
930 		email[ CRYPT_MAX_TEXTSIZE + 1 + 8 ];
931 	int keyDataLength, ldapModIndex = 1, status;
932 
933 	*C = *SP = *L = *O = *OU = *CN = *email = '\0';
934 
935 	/* Extract the DN and altName components.  This changes the currently
936 	   selected DN components, but this is OK since we've got the
937 	   certificate locked and the prior state will be restored when we
938 	   unlock it */
939 	krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
940 					 ( MESSAGE_CAST ) &nameValue, CRYPT_ATTRIBUTE_CURRENT );
941 	setMessageData( &msgData, C, CRYPT_MAX_TEXTSIZE );
942 	status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
943 							  &msgData, CRYPT_CERTINFO_COUNTRYNAME );
944 	if( cryptStatusOK( status ) )
945 		C[ msgData.length ] = '\0';
946 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
947 		{
948 		setMessageData( &msgData, SP, CRYPT_MAX_TEXTSIZE );
949 		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
950 							&msgData, CRYPT_CERTINFO_STATEORPROVINCENAME );
951 		}
952 	if( cryptStatusOK( status ) )
953 		SP[ msgData.length ] = '\0';
954 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
955 		{
956 		setMessageData( &msgData, L, CRYPT_MAX_TEXTSIZE );
957 		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
958 							&msgData, CRYPT_CERTINFO_LOCALITYNAME );
959 		}
960 	if( cryptStatusOK( status ) )
961 		L[ msgData.length ] = '\0';
962 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
963 		{
964 		setMessageData( &msgData, O, CRYPT_MAX_TEXTSIZE );
965 		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
966 							&msgData, CRYPT_CERTINFO_ORGANIZATIONNAME );
967 		}
968 	if( cryptStatusOK( status ) )
969 		O[ msgData.length ] = '\0';
970 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
971 		{
972 		setMessageData( &msgData, OU, CRYPT_MAX_TEXTSIZE );
973 		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
974 							&msgData, CRYPT_CERTINFO_ORGANIZATIONALUNITNAME );
975 		}
976 	if( cryptStatusOK( status ) )
977 		OU[ msgData.length ] = '\0';
978 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
979 		{
980 		setMessageData( &msgData, CN, CRYPT_MAX_TEXTSIZE );
981 		status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE_S,
982 							&msgData, CRYPT_CERTINFO_COMMONNAME );
983 		}
984 	if( cryptStatusOK( status ) )
985 		CN[ msgData.length ] = '\0';
986 	if( cryptStatusOK( status ) || status == CRYPT_ERROR_NOTFOUND )
987 		{
988 		/* Get the string form of the DN */
989 		status = encodeDN( dn, MAX_DN_STRINGSIZE, C, SP, L, O, OU, CN );
990 		}
991 	if( cryptStatusError( status ) )
992 		{
993 		/* Convert any low-level certificate-specific error into something
994 		   generic which makes a bit more sense to the caller */
995 		return( CRYPT_ARGERROR_NUM1 );
996 		}
997 
998 	/* Get the certificate data */
999 	setMessageData( &msgData, keyData, MAX_CERT_SIZE );
1000 	status = krnlSendMessage( iCryptHandle, IMESSAGE_CRT_EXPORT, &msgData,
1001 							  CRYPT_CERTFORMAT_CERTIFICATE );
1002 	keyDataLength = msgData.length;
1003 	if( cryptStatusError( status ) )
1004 		{
1005 		/* Convert any low-level certificate-specific error into something
1006 		   generic which makes a bit more sense to the caller */
1007 		return( CRYPT_ARGERROR_NUM1 );
1008 		}
1009 
1010 	/* Set up the fixed attributes and certificate data.  This currently
1011 	   always adds a certificate as a standard certificate rather than a CA
1012 	   certificate because of uncertainty over what other implementations
1013 	   will try and look for, once enough other software uses the CA
1014 	   certificate attribute this can be switched over */
1015 	if( ( ldapMod[ 0 ] = copyAttribute( ldapInfo->nameObjectClass,
1016 										"certPerson", 0 ) ) == NULL )
1017 		return( CRYPT_ERROR_MEMORY );
1018 	if( ( ldapMod[ ldapModIndex++ ] = copyAttribute( ldapInfo->nameCert,
1019 										keyData, keyDataLength ) ) == NULL )
1020 		status = CRYPT_ERROR_MEMORY;
1021 
1022 	/* Set up the DN/identification information */
1023 	if( cryptStatusOK( status ) && *email && \
1024 		( ldapMod[ ldapModIndex++ ] = \
1025 				copyAttribute( ldapInfo->nameEmail, email, 0 ) ) == NULL )
1026 		status = CRYPT_ERROR_MEMORY;
1027 	if( cryptStatusOK( status ) && *CN && \
1028 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "CN", CN, 0 ) ) == NULL )
1029 		status = CRYPT_ERROR_MEMORY;
1030 	if( cryptStatusOK( status ) && *OU && \
1031 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "OU", OU, 0 ) ) == NULL )
1032 		status = CRYPT_ERROR_MEMORY;
1033 	if( cryptStatusOK( status ) && *O && \
1034 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "O", O, 0 ) ) == NULL )
1035 		status = CRYPT_ERROR_MEMORY;
1036 	if( cryptStatusOK( status ) && *L && \
1037 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "L", L, 0 ) ) == NULL )
1038 		status = CRYPT_ERROR_MEMORY;
1039 	if( cryptStatusOK( status ) && *SP && \
1040 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "SP", SP, 0 ) ) == NULL )
1041 		status = CRYPT_ERROR_MEMORY;
1042 	if( cryptStatusOK( status ) && *C && \
1043 		( ldapMod[ ldapModIndex++ ] = copyAttribute( "C", C, 0 ) ) == NULL )
1044 		status = CRYPT_ERROR_MEMORY;
1045 	ldapMod[ ldapModIndex ] = NULL;
1046 
1047 	/* Add the new attribute/entry */
1048 	if( cryptStatusOK( status ) )
1049 		{
1050 		int ldapStatus;
1051 
1052 		if( ( ldapStatus = ldap_add_s( ldapInfo->ld, dn,
1053 									   ldapMod ) ) != LDAP_SUCCESS )
1054 			{
1055 			getErrorInfo( keysetInfoPtr, ldapStatus );
1056 			status = mapLdapError( ldapStatus, CRYPT_ERROR_WRITE );
1057 			}
1058 		}
1059 
1060 	/* Clean up.  We do it the hard way rather than using
1061 	   ldap_mods_free() here partially because the ldapMod[] array
1062 	   isn't malloc()'d, but mostly because for the Netscape client
1063 	   library ldap_mods_free() causes some sort of memory corruption,
1064 	   possibly because it's trying to free the mod_values[] entries
1065 	   which are statically allocated, and for the MS client the
1066 	   function doesn't exist */
1067 	for( ldapModIndex = 0; ldapModIndex < MAX_LDAP_ATTRIBUTES && \
1068 						   ldapMod[ ldapModIndex ] != NULL;
1069 		 ldapModIndex++ )
1070 		{
1071 		if( ldapMod[ ldapModIndex ]->mod_op & LDAP_MOD_BVALUES )
1072 			clFree( "addCert", ldapMod[ ldapModIndex ]->mod_bvalues );
1073 		else
1074 			clFree( "addCert", ldapMod[ ldapModIndex ]->mod_values );
1075 		clFree( "addCert", ldapMod[ ldapModIndex ] );
1076 		}
1077 	if( ldapModIndex >= MAX_LDAP_ATTRIBUTES )
1078 		retIntError();
1079 	return( status );
1080 	}
1081 
1082 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setItemFunction(INOUT KEYSET_INFO * keysetInfoPtr,IN_HANDLE const CRYPT_HANDLE iCryptHandle,IN_ENUM (KEYMGMT_ITEM)const KEYMGMT_ITEM_TYPE itemType,STDC_UNUSED const char * password,STDC_UNUSED const int passwordLength,IN_FLAGS (KEYMGMT)const int flags)1083 static int setItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1084 							IN_HANDLE const CRYPT_HANDLE iCryptHandle,
1085 							IN_ENUM( KEYMGMT_ITEM ) \
1086 								const KEYMGMT_ITEM_TYPE itemType,
1087 							STDC_UNUSED const char *password,
1088 							STDC_UNUSED const int passwordLength,
1089 							IN_FLAGS( KEYMGMT ) const int flags )
1090 	{
1091 	BOOLEAN seenNonDuplicate = FALSE;
1092 	int type, iterationCount = 0, status;
1093 
1094 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1095 
1096 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1097 	REQUIRES( isHandleRangeValid( iCryptHandle ) );
1098 	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
1099 	REQUIRES( password == NULL && passwordLength == 0 );
1100 	REQUIRES( flags == KEYMGMT_FLAG_NONE );
1101 
1102 	/* Make sure we've been given a certificate or certificate chain */
1103 	status = krnlSendMessage( iCryptHandle, MESSAGE_GETATTRIBUTE, &type,
1104 							  CRYPT_CERTINFO_CERTTYPE );
1105 	if( cryptStatusError( status ) )
1106 		return( CRYPT_ARGERROR_NUM1 );
1107 	if( type != CRYPT_CERTTYPE_CERTIFICATE && \
1108 		type != CRYPT_CERTTYPE_CERTCHAIN )
1109 		return( CRYPT_ARGERROR_NUM1 );
1110 
1111 	/* Lock the certificate for our exclusive use (in case it's a
1112 	   certificate chain, we also select the first certificate in the
1113 	   chain), update the keyset with the certificate(s), and unlock it to
1114 	   allow others access */
1115 	krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
1116 					 MESSAGE_VALUE_CURSORFIRST,
1117 					 CRYPT_CERTINFO_CURRENT_CERTIFICATE );
1118 	status = krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
1119 							  MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
1120 	if( cryptStatusError( status ) )
1121 		return( status );
1122 	do
1123 		{
1124 		/* Add the certificate */
1125 		status = addCert( keysetInfoPtr, iCryptHandle );
1126 
1127 		/* A certificate being added may already be present, however we
1128 		   can't fail immediately because what's being added may be a chain
1129 		   containing further certificates so we keep track of whether we've
1130 		   successfully added at least one certificate and clear data
1131 		   duplicate errors */
1132 		if( status == CRYPT_OK )
1133 			seenNonDuplicate = TRUE;
1134 		else
1135 			{
1136 			if( status == CRYPT_ERROR_DUPLICATE )
1137 				status = CRYPT_OK;
1138 			}
1139 		}
1140 	while( cryptStatusOK( status ) && \
1141 		   krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
1142 							MESSAGE_VALUE_CURSORNEXT,
1143 							CRYPT_CERTINFO_CURRENT_CERTIFICATE ) == CRYPT_OK && \
1144 		   iterationCount++ < FAILSAFE_ITERATIONS_MED );
1145 	if( iterationCount >= FAILSAFE_ITERATIONS_MED )
1146 		retIntError();
1147 	krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
1148 					 MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
1149 	if( cryptStatusOK( status ) && !seenNonDuplicate )
1150 		{
1151 		/* We reached the end of the chain without finding anything we could
1152 		   add, return a data duplicate error */
1153 		status = CRYPT_ERROR_DUPLICATE;
1154 		}
1155 
1156 	return( status );
1157 	}
1158 
1159 /* Delete an entry from an LDAP directory */
1160 
1161 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
deleteItemFunction(INOUT KEYSET_INFO * keysetInfoPtr,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)1162 static int deleteItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1163 							   IN_ENUM( KEYMGMT_ITEM ) \
1164 								const KEYMGMT_ITEM_TYPE itemType,
1165 							   IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
1166 							   IN_BUFFER( keyIDlength ) const void *keyID,
1167 							   IN_LENGTH_KEYID const int keyIDlength )
1168 	{
1169 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
1170 	char dn[ MAX_DN_STRINGSIZE + 8 ];
1171 	int ldapStatus;
1172 
1173 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1174 	assert( isReadPtr( keyID, keyIDlength ) );
1175 
1176 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1177 	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
1178 	REQUIRES( keyIDtype == CRYPT_KEYID_NAME || keyIDtype == CRYPT_KEYID_URI );
1179 	REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
1180 			  keyIDlength < MAX_ATTRIBUTE_SIZE );
1181 
1182 	/* Convert the DN into a null-terminated form */
1183 	if( keyIDlength > MAX_DN_STRINGSIZE - 1 )
1184 		return( CRYPT_ARGERROR_STR1 );
1185 	memcpy( dn, keyID, keyIDlength );
1186 	dn[ keyIDlength ] = '\0';
1187 
1188 	/* Delete the entry */
1189 	if( ( ldapStatus = ldap_delete_s( ldapInfo->ld, dn ) ) != LDAP_SUCCESS )
1190 		{
1191 		getErrorInfo( keysetInfoPtr, ldapStatus );
1192 		return( mapLdapError( ldapStatus, CRYPT_ERROR_WRITE ) );
1193 		}
1194 
1195 	return( CRYPT_OK );
1196 	}
1197 
1198 #if 0	/* 5/7/10 getItemFunction() hasn't supported this functionality
1199 				  since 3.3.2, and it was removed there because the kernel
1200 				  had never allowed this type of access at all, which means
1201 				  that these functions could never have been called.  Since
1202 				  no-one had ever noticed this, there's no point in
1203 				  continuing to support them */
1204 
1205 /* Perform a getFirst/getNext query on the LDAP directory */
1206 
1207 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 6 ) ) \
1208 static int getFirstItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1209 								 OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
1210 								 STDC_UNUSED int *stateInfo,
1211 								 IN_ENUM( KEYMGMT_ITEM ) \
1212 									const KEYMGMT_ITEM_TYPE itemType,
1213 								 IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
1214 								 IN_BUFFER( keyIDlength ) const void *keyID,
1215 								 IN_LENGTH_KEYID const int keyIDlength,
1216 								 IN_FLAGS( KEYMGMT ) const int options )
1217 	{
1218 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1219 	assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
1220 	assert( isReadPtr( keyID, keyIDlength ) );
1221 
1222 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1223 	REQUIRES( stateInfo == NULL );
1224 	REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
1225 	REQUIRES( keyIDtype != CRYPT_KEYID_NONE );
1226 	REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
1227 			  keyIDlength < MAX_ATTRIBUTE_SIZE );
1228 	REQUIRES( options == KEYMGMT_FLAG_NONE );
1229 
1230 	return( getItemFunction( keysetInfoPtr, iCertificate,
1231 							 KEYMGMT_ITEM_PUBLICKEY, CRYPT_KEYID_NAME,
1232 							 keyID, keyIDlength, NULL, 0, 0 ) );
1233 	}
1234 
1235 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
1236 static int getNextItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1237 								OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCertificate,
1238 								STDC_UNUSED int *stateInfo,
1239 								IN_FLAGS( KEYMGMT ) const int options )
1240 	{
1241 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1242 	assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
1243 
1244 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1245 	REQUIRES( stateInfo == NULL );
1246 	REQUIRES( options == KEYMGMT_FLAG_NONE );
1247 
1248 	return( getItemFunction( keysetInfoPtr, iCertificate,
1249 							 KEYMGMT_ITEM_PUBLICKEY, CRYPT_KEYID_NONE,
1250 							 NULL, 0, NULL, 0, 0 ) );
1251 	}
1252 #endif /* 0 */
1253 
1254 /* Return status information for the keyset */
1255 
1256 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
isBusyFunction(INOUT KEYSET_INFO * keysetInfoPtr)1257 static BOOLEAN isBusyFunction( INOUT KEYSET_INFO *keysetInfoPtr )
1258 	{
1259 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1260 
1261 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1262 
1263 	return( FALSE );
1264 	}
1265 
1266 /* Get/set keyset attributes */
1267 
getAttributeDataPtr(KEYSET_INFO * keysetInfoPtr,const CRYPT_ATTRIBUTE_TYPE type)1268 static void *getAttributeDataPtr( KEYSET_INFO *keysetInfoPtr,
1269 								  const CRYPT_ATTRIBUTE_TYPE type )
1270 	{
1271 	LDAP_INFO *ldapInfo = keysetInfoPtr->keysetLDAP;
1272 
1273 	switch( type )
1274 		{
1275 		case CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS:
1276 			return( ldapInfo->nameObjectClass );
1277 
1278 		case CRYPT_OPTION_KEYS_LDAP_FILTER:
1279 			return( ldapInfo->nameFilter );
1280 
1281 		case CRYPT_OPTION_KEYS_LDAP_CACERTNAME:
1282 			return( ldapInfo->nameCACert );
1283 
1284 		case CRYPT_OPTION_KEYS_LDAP_CERTNAME:
1285 			return( ldapInfo->nameCert );
1286 
1287 		case CRYPT_OPTION_KEYS_LDAP_CRLNAME:
1288 			return( ldapInfo->nameCRL );
1289 
1290 		case CRYPT_OPTION_KEYS_LDAP_EMAILNAME:
1291 			return( ldapInfo->nameEmail );
1292 		}
1293 
1294 	return( NULL );
1295 	}
1296 
1297 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getAttributeFunction(INOUT KEYSET_INFO * keysetInfoPtr,INOUT void * data,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type)1298 static int getAttributeFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1299 								 INOUT void *data,
1300 								 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
1301 	{
1302 	const void *attributeDataPtr;
1303 
1304 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1305 
1306 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1307 
1308 	attributeDataPtr = getAttributeDataPtr( keysetInfoPtr, type );
1309 	if( attributeDataPtr == NULL )
1310 		return( CRYPT_ARGERROR_VALUE );
1311 	return( attributeCopy( data, attributeDataPtr,
1312 						   strlen( attributeDataPtr ) ) );
1313 	}
1314 
1315 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
setAttributeFunction(INOUT KEYSET_INFO * keysetInfoPtr,const void * data,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type)1316 static int setAttributeFunction( INOUT KEYSET_INFO *keysetInfoPtr,
1317 								 const void *data,
1318 								 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
1319 	{
1320 	const MESSAGE_DATA *msgData = ( MESSAGE_DATA * ) data;
1321 	BYTE *attributeDataPtr;
1322 
1323 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1324 
1325 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1326 
1327 	attributeDataPtr = getAttributeDataPtr( keysetInfoPtr, type );
1328 	if( attributeDataPtr == NULL )
1329 		return( CRYPT_ARGERROR_VALUE );
1330 	if( msgData->length < 1 || msgData->length > CRYPT_MAX_TEXTSIZE )
1331 		return( CRYPT_ARGERROR_STR1 );
1332 	memcpy( attributeDataPtr, msgData->data, msgData->length );
1333 	attributeDataPtr[ msgData->length ] = '\0';
1334 
1335 	return( CRYPT_OK );
1336 	}
1337 
1338 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setAccessMethodLDAP(INOUT KEYSET_INFO * keysetInfoPtr)1339 int setAccessMethodLDAP( INOUT KEYSET_INFO *keysetInfoPtr )
1340 	{
1341 	assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
1342 
1343 	REQUIRES( keysetInfoPtr->type == KEYSET_LDAP );
1344 
1345 #ifdef DYNAMIC_LOAD
1346 	/* Make sure that the LDAP driver is bound in */
1347 	if( hLDAP == NULL_INSTANCE )
1348 		return( CRYPT_ERROR_OPEN );
1349 #endif /* DYNAMIC_LOAD */
1350 
1351 	/* Set the access method pointers */
1352 	FNPTR_SET( keysetInfoPtr->initFunction, initFunction );
1353 	FNPTR_SET( keysetInfoPtr->shutdownFunction, shutdownFunction );
1354 	FNPTR_SET( keysetInfoPtr->getAttributeFunction, getAttributeFunction );
1355 	FNPTR_SET( keysetInfoPtr->setAttributeFunction, setAttributeFunction );
1356 	FNPTR_SET( keysetInfoPtr->getItemFunction, getItemFunction );
1357 	FNPTR_SET( keysetInfoPtr->setItemFunction, setItemFunction );
1358 	FNPTR_SET( keysetInfoPtr->deleteItemFunction, deleteItemFunction );
1359 	FNPTR_SET( keysetInfoPtr->isBusyFunction, isBusyFunction );
1360 
1361 	return( CRYPT_OK );
1362 	}
1363 #endif /* USE_LDAP */
1364