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