1 /*	$NetBSD: root_dse.c,v 1.1.1.3 2010/12/12 15:22:38 adam Exp $	*/
2 
3 /* root_dse.c - Provides the Root DSA-Specific Entry */
4 /* OpenLDAP: pkg/ldap/servers/slapd/root_dse.c,v 1.113.2.12 2010/04/13 20:23:18 kurt Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2010 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/string.h>
24 
25 #include "slap.h"
26 #include <ldif.h>
27 #include "lber_pvt.h"
28 
29 #ifdef LDAP_SLAPI
30 #include "slapi/slapi.h"
31 #endif
32 
33 static struct berval	builtin_supportedFeatures[] = {
34 	BER_BVC(LDAP_FEATURE_MODIFY_INCREMENT),		/* Modify/increment */
35 	BER_BVC(LDAP_FEATURE_ALL_OP_ATTRS),		/* All Op Attrs (+) */
36 	BER_BVC(LDAP_FEATURE_OBJECTCLASS_ATTRS),	/* OCs in Attrs List (@class) */
37 	BER_BVC(LDAP_FEATURE_ABSOLUTE_FILTERS),		/* (&) and (|) search filters */
38 	BER_BVC(LDAP_FEATURE_LANGUAGE_TAG_OPTIONS),	/* Language Tag Options */
39 	BER_BVC(LDAP_FEATURE_LANGUAGE_RANGE_OPTIONS),	/* Language Range Options */
40 #ifdef LDAP_DEVEL
41 	BER_BVC(LDAP_FEATURE_SUBORDINATE_SCOPE),	/* "children" search scope */
42 #endif
43 	BER_BVNULL
44 };
45 static struct berval	*supportedFeatures;
46 
47 static Entry	*usr_attr = NULL;
48 
49 /*
50  * allow modules to register functions that muck with the root DSE entry
51  */
52 
53 typedef struct entry_info_t {
54 	SLAP_ENTRY_INFO_FN	func;
55 	void			*arg;
56 	struct entry_info_t	*next;
57 } entry_info_t;
58 
59 static entry_info_t *extra_info;
60 
61 int
62 entry_info_register( SLAP_ENTRY_INFO_FN func, void *arg )
63 {
64 	entry_info_t	*ei = ch_calloc( 1, sizeof( entry_info_t ) );
65 
66 	ei->func = func;
67 	ei->arg = arg;
68 
69 	ei->next = extra_info;
70 	extra_info = ei;
71 
72 	return 0;
73 }
74 
75 int
76 entry_info_unregister( SLAP_ENTRY_INFO_FN func, void *arg )
77 {
78 	entry_info_t	**eip;
79 
80 	for ( eip = &extra_info; *eip != NULL; eip = &(*eip)->next ) {
81 		if ( (*eip)->func == func && (*eip)->arg == arg ) {
82 			entry_info_t	*ei = *eip;
83 
84 			*eip = ei->next;
85 
86 			ch_free( ei );
87 
88 			return 0;
89 		}
90 	}
91 
92 	return -1;
93 }
94 
95 void
96 entry_info_destroy( void )
97 {
98 	entry_info_t	**eip;
99 
100 	for ( eip = &extra_info; *eip != NULL;  ) {
101 		entry_info_t	*ei = *eip;
102 
103 		eip = &(*eip)->next;
104 
105 		ch_free( ei );
106 	}
107 }
108 
109 /*
110  * Allow modules to register supported features
111  */
112 
113 static int
114 supported_feature_init( void )
115 {
116 	int		i;
117 
118 	if ( supportedFeatures != NULL ) {
119 		return 0;
120 	}
121 
122 	for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ )
123 		;
124 
125 	supportedFeatures = ch_calloc( sizeof( struct berval ), i + 1 );
126 	if ( supportedFeatures == NULL ) {
127 		return -1;
128 	}
129 
130 	for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ ) {
131 		ber_dupbv( &supportedFeatures[ i ], &builtin_supportedFeatures[ i ] );
132 	}
133 	BER_BVZERO( &supportedFeatures[ i ] );
134 
135 	return 0;
136 }
137 
138 int
139 supported_feature_destroy( void )
140 {
141 	int		i;
142 
143 	if ( supportedFeatures == NULL ) {
144 		return 0;
145 	}
146 
147 	for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ ) {
148 		ch_free( supportedFeatures[ i ].bv_val );
149 	}
150 
151 	ch_free( supportedFeatures );
152 	supportedFeatures = NULL;
153 
154 	return 0;
155 }
156 
157 int
158 supported_feature_load( struct berval *f )
159 {
160 	struct berval	*tmp;
161 	int		i;
162 
163 	supported_feature_init();
164 
165 	for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ )
166 		;
167 
168 	tmp = ch_realloc( supportedFeatures, sizeof( struct berval ) * ( i + 2 ) );
169 	if ( tmp == NULL ) {
170 		return -1;
171 	}
172 	supportedFeatures = tmp;
173 
174 	ber_dupbv( &supportedFeatures[ i ], f );
175 	BER_BVZERO( &supportedFeatures[ i + 1 ] );
176 
177 	return 0;
178 }
179 
180 int
181 root_dse_info(
182 	Connection *conn,
183 	Entry **entry,
184 	const char **text )
185 {
186 	Entry		*e;
187 	struct berval val;
188 #ifdef LDAP_SLAPI
189 	struct berval *bv;
190 #endif
191 	int		i, j;
192 	char ** supportedSASLMechanisms;
193 	BackendDB *be;
194 
195 	AttributeDescription *ad_structuralObjectClass
196 		= slap_schema.si_ad_structuralObjectClass;
197 	AttributeDescription *ad_objectClass
198 		= slap_schema.si_ad_objectClass;
199 	AttributeDescription *ad_namingContexts
200 		= slap_schema.si_ad_namingContexts;
201 #ifdef LDAP_SLAPI
202 	AttributeDescription *ad_supportedExtension
203 		= slap_schema.si_ad_supportedExtension;
204 #endif
205 	AttributeDescription *ad_supportedLDAPVersion
206 		= slap_schema.si_ad_supportedLDAPVersion;
207 	AttributeDescription *ad_supportedSASLMechanisms
208 		= slap_schema.si_ad_supportedSASLMechanisms;
209 	AttributeDescription *ad_supportedFeatures
210 		= slap_schema.si_ad_supportedFeatures;
211 	AttributeDescription *ad_monitorContext
212 		= slap_schema.si_ad_monitorContext;
213 	AttributeDescription *ad_configContext
214 		= slap_schema.si_ad_configContext;
215 	AttributeDescription *ad_ref
216 		= slap_schema.si_ad_ref;
217 
218 	e = entry_alloc();
219 	if( e == NULL ) {
220 		Debug( LDAP_DEBUG_ANY,
221 			"root_dse_info: entry_alloc failed", 0, 0, 0 );
222 		return LDAP_OTHER;
223 	}
224 
225 	e->e_attrs = NULL;
226 	e->e_name.bv_val = ch_strdup( LDAP_ROOT_DSE );
227 	e->e_name.bv_len = sizeof( LDAP_ROOT_DSE )-1;
228 	e->e_nname.bv_val = ch_strdup( LDAP_ROOT_DSE );
229 	e->e_nname.bv_len = sizeof( LDAP_ROOT_DSE )-1;
230 
231 	/* the DN is an empty string so no pretty/normalization is needed */
232 	assert( !e->e_name.bv_len );
233 	assert( !e->e_nname.bv_len );
234 
235 	e->e_private = NULL;
236 
237 	/* FIXME: is this really needed? */
238 	BER_BVSTR( &val, "top" );
239 	if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) {
240 fail:
241 		entry_free( e );
242 		return LDAP_OTHER;
243 	}
244 
245 	BER_BVSTR( &val, "OpenLDAProotDSE" );
246 	if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) {
247 		goto fail;
248 	}
249 	if( attr_merge_one( e, ad_structuralObjectClass, &val, NULL ) ) {
250 		goto fail;
251 	}
252 
253 	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
254 		if ( be->be_suffix == NULL
255 				|| be->be_nsuffix == NULL ) {
256 			/* no suffix! */
257 			continue;
258 		}
259 		if ( SLAP_MONITOR( be )) {
260 			if( attr_merge_one( e, ad_monitorContext,
261 					&be->be_suffix[0],
262 					&be->be_nsuffix[0] ) )
263 			{
264 				goto fail;
265 			}
266 			continue;
267 		}
268 		if ( SLAP_CONFIG( be )) {
269 			if( attr_merge_one( e, ad_configContext,
270 					&be->be_suffix[0],
271 					& be->be_nsuffix[0] ) )
272 			{
273 				goto fail;
274 			}
275 			continue;
276 		}
277 		if ( SLAP_GLUE_SUBORDINATE( be ) && !SLAP_GLUE_ADVERTISE( be ) ) {
278 			continue;
279 		}
280 		for ( j = 0; be->be_suffix[j].bv_val != NULL; j++ ) {
281 			if( attr_merge_one( e, ad_namingContexts,
282 					&be->be_suffix[j], NULL ) )
283 			{
284 				goto fail;
285 			}
286 		}
287 	}
288 
289 	/* altServer unsupported */
290 
291 	/* supportedControl */
292 	if ( controls_root_dse_info( e ) != 0 ) {
293 		goto fail;
294 	}
295 
296 	/* supportedExtension */
297 	if ( exop_root_dse_info( e ) != 0 ) {
298 		goto fail;
299 	}
300 
301 #ifdef LDAP_SLAPI
302 	/* netscape supportedExtension */
303 	for ( i = 0; (bv = slapi_int_get_supported_extop(i)) != NULL; i++ ) {
304 		if( attr_merge_one( e, ad_supportedExtension, bv, NULL ) ) {
305 			goto fail;
306 		}
307 	}
308 #endif /* LDAP_SLAPI */
309 
310 	/* supportedFeatures */
311 	if ( supportedFeatures == NULL ) {
312 		supported_feature_init();
313 	}
314 
315 	if( attr_merge( e, ad_supportedFeatures, supportedFeatures, NULL ) ) {
316 		goto fail;
317 	}
318 
319 	/* supportedLDAPVersion */
320 		/* don't publish version 2 as we don't really support it
321 		 * (even when configured to accept version 2 Bind requests)
322 		 * and the value would never be used by true LDAPv2 (or LDAPv3)
323 		 * clients.
324 		 */
325 	for ( i=LDAP_VERSION3; i<=LDAP_VERSION_MAX; i++ ) {
326 		char buf[sizeof("255")];
327 		snprintf(buf, sizeof buf, "%d", i);
328 		val.bv_val = buf;
329 		val.bv_len = strlen( val.bv_val );
330 		if( attr_merge_one( e, ad_supportedLDAPVersion, &val, NULL ) ) {
331 			goto fail;
332 		}
333 	}
334 
335 	/* supportedSASLMechanism */
336 	supportedSASLMechanisms = slap_sasl_mechs( conn );
337 
338 	if( supportedSASLMechanisms != NULL ) {
339 		for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) {
340 			val.bv_val = supportedSASLMechanisms[i];
341 			val.bv_len = strlen( val.bv_val );
342 			if( attr_merge_one( e, ad_supportedSASLMechanisms, &val, NULL ) ) {
343 				ldap_charray_free( supportedSASLMechanisms );
344 				goto fail;
345 			}
346 		}
347 		ldap_charray_free( supportedSASLMechanisms );
348 	}
349 
350 	if ( default_referral != NULL ) {
351 		if( attr_merge( e, ad_ref, default_referral, NULL /* FIXME */ ) ) {
352 			goto fail;
353 		}
354 	}
355 
356 	if( usr_attr != NULL) {
357 		Attribute *a;
358 		for( a = usr_attr->e_attrs; a != NULL; a = a->a_next ) {
359 			if( attr_merge( e, a->a_desc, a->a_vals,
360 				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
361 			{
362 				goto fail;
363 			}
364 		}
365 	}
366 
367 	if ( extra_info ) {
368 		entry_info_t	*ei = extra_info;
369 
370 		for ( ; ei; ei = ei->next ) {
371 			ei->func( ei->arg, e );
372 		}
373 	}
374 
375 	*entry = e;
376 	return LDAP_SUCCESS;
377 }
378 
379 int
380 root_dse_init( void )
381 {
382 	return 0;
383 }
384 
385 int
386 root_dse_destroy( void )
387 {
388 	if ( usr_attr ) {
389 		entry_free( usr_attr );
390 		usr_attr = NULL;
391 	}
392 
393 	return 0;
394 }
395 
396 /*
397  * Read the entries specified in fname and merge the attributes
398  * to the user defined rootDSE. Note thaat if we find any errors
399  * what so ever, we will discard the entire entries, print an
400  * error message and return.
401  */
402 int
403 root_dse_read_file( const char *fname )
404 {
405 	struct LDIFFP	*fp;
406 	int rc = 0, lineno = 0, lmax = 0, ldifrc;
407 	char	*buf = NULL;
408 
409 	if ( (fp = ldif_open( fname, "r" )) == NULL ) {
410 		Debug( LDAP_DEBUG_ANY,
411 			"root_dse_read_file: could not open rootdse attr file \"%s\" - absolute path?\n",
412 			fname, 0, 0 );
413 		perror( fname );
414 		return EXIT_FAILURE;
415 	}
416 
417 	usr_attr = entry_alloc();
418 	if( usr_attr == NULL ) {
419 		Debug( LDAP_DEBUG_ANY,
420 			"root_dse_read_file: entry_alloc failed", 0, 0, 0 );
421 		ldif_close( fp );
422 		return LDAP_OTHER;
423 	}
424 	usr_attr->e_attrs = NULL;
425 
426 	while(( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) {
427 		Entry *e = str2entry( buf );
428 		Attribute *a;
429 
430 		if( e == NULL ) {
431 			Debug( LDAP_DEBUG_ANY, "root_dse_read_file: "
432 				"could not parse entry (file=\"%s\" line=%d)\n",
433 				fname, lineno, 0 );
434 			rc = LDAP_OTHER;
435 			break;
436 		}
437 
438 		/* make sure the DN is the empty DN */
439 		if( e->e_nname.bv_len ) {
440 			Debug( LDAP_DEBUG_ANY,
441 				"root_dse_read_file: invalid rootDSE "
442 				"- dn=\"%s\" (file=\"%s\" line=%d)\n",
443 				e->e_dn, fname, lineno );
444 			entry_free( e );
445 			rc = LDAP_OTHER;
446 			break;
447 		}
448 
449 		/*
450 		 * we found a valid entry, so walk thru all the attributes in the
451 		 * entry, and add each attribute type and description to the
452 		 * usr_attr entry
453 		 */
454 
455 		for(a = e->e_attrs; a != NULL; a = a->a_next) {
456 			if( attr_merge( usr_attr, a->a_desc, a->a_vals,
457 				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
458 			{
459 				rc = LDAP_OTHER;
460 				break;
461 			}
462 		}
463 
464 		entry_free( e );
465 		if (rc) break;
466 	}
467 
468 	if ( ldifrc < 0 )
469 		rc = LDAP_OTHER;
470 
471 	if (rc) {
472 		entry_free( usr_attr );
473 		usr_attr = NULL;
474 	}
475 
476 	ch_free( buf );
477 
478 	ldif_close( fp );
479 
480 	Debug(LDAP_DEBUG_CONFIG, "rootDSE file=\"%s\" read.\n", fname, 0, 0);
481 	return rc;
482 }
483 
484 int
485 slap_discover_feature(
486 	slap_bindconf	*sb,
487 	const char	*attr,
488 	const char	*val )
489 {
490 	LDAP		*ld = NULL;
491 	LDAPMessage	*res = NULL, *entry;
492 	int		rc, i;
493 	struct berval	bv_val,
494 			**values = NULL;
495 	char		*attrs[ 2 ] = { NULL, NULL };
496 
497 	rc = slap_client_connect( &ld, sb );
498 	if ( rc != LDAP_SUCCESS ) {
499 		goto done;
500 	}
501 
502 	attrs[ 0 ] = (char *) attr;
503 	rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectClass=*)",
504 			attrs, 0, NULL, NULL, NULL, 0, &res );
505 	if ( rc != LDAP_SUCCESS ) {
506 		goto done;
507 	}
508 
509 	entry = ldap_first_entry( ld, res );
510 	if ( entry == NULL ) {
511 		goto done;
512 	}
513 
514 	values = ldap_get_values_len( ld, entry, attrs[ 0 ] );
515 	if ( values == NULL ) {
516 		rc = LDAP_NO_SUCH_ATTRIBUTE;
517 		goto done;
518 	}
519 
520 	ber_str2bv( val, 0, 0, &bv_val );
521 	for ( i = 0; values[ i ] != NULL; i++ ) {
522 		if ( bvmatch( &bv_val, values[ i ] ) ) {
523 			rc = LDAP_COMPARE_TRUE;
524 			goto done;
525 		}
526 	}
527 
528 	rc = LDAP_COMPARE_FALSE;
529 
530 done:;
531 	if ( values != NULL ) {
532 		ldap_value_free_len( values );
533 	}
534 
535 	if ( res != NULL ) {
536 		ldap_msgfree( res );
537 	}
538 
539 	ldap_unbind_ext( ld, NULL, NULL );
540 
541 	return rc;
542 }
543 
544