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