xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/root_dse.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: root_dse.c,v 1.1.1.4 2014/05/28 09:58:47 tron Exp $	*/
2 
3 /* root_dse.c - Provides the Root DSA-Specific Entry */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1999-2014 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, lmax = 0, ldifrc;
407 	unsigned long lineno = 0;
408 	char	*buf = NULL;
409 
410 	if ( (fp = ldif_open( fname, "r" )) == NULL ) {
411 		Debug( LDAP_DEBUG_ANY,
412 			"root_dse_read_file: could not open rootdse attr file \"%s\" - absolute path?\n",
413 			fname, 0, 0 );
414 		perror( fname );
415 		return EXIT_FAILURE;
416 	}
417 
418 	usr_attr = entry_alloc();
419 	if( usr_attr == NULL ) {
420 		Debug( LDAP_DEBUG_ANY,
421 			"root_dse_read_file: entry_alloc failed", 0, 0, 0 );
422 		ldif_close( fp );
423 		return LDAP_OTHER;
424 	}
425 	usr_attr->e_attrs = NULL;
426 
427 	while(( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) {
428 		Entry *e = str2entry( buf );
429 		Attribute *a;
430 
431 		if( e == NULL ) {
432 			Debug( LDAP_DEBUG_ANY, "root_dse_read_file: "
433 				"could not parse entry (file=\"%s\" line=%lu)\n",
434 				fname, lineno, 0 );
435 			rc = LDAP_OTHER;
436 			break;
437 		}
438 
439 		/* make sure the DN is the empty DN */
440 		if( e->e_nname.bv_len ) {
441 			Debug( LDAP_DEBUG_ANY,
442 				"root_dse_read_file: invalid rootDSE "
443 				"- dn=\"%s\" (file=\"%s\" line=%lu)\n",
444 				e->e_dn, fname, lineno );
445 			entry_free( e );
446 			rc = LDAP_OTHER;
447 			break;
448 		}
449 
450 		/*
451 		 * we found a valid entry, so walk thru all the attributes in the
452 		 * entry, and add each attribute type and description to the
453 		 * usr_attr entry
454 		 */
455 
456 		for(a = e->e_attrs; a != NULL; a = a->a_next) {
457 			if( attr_merge( usr_attr, a->a_desc, a->a_vals,
458 				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
459 			{
460 				rc = LDAP_OTHER;
461 				break;
462 			}
463 		}
464 
465 		entry_free( e );
466 		if (rc) break;
467 	}
468 
469 	if ( ldifrc < 0 )
470 		rc = LDAP_OTHER;
471 
472 	if (rc) {
473 		entry_free( usr_attr );
474 		usr_attr = NULL;
475 	}
476 
477 	ch_free( buf );
478 
479 	ldif_close( fp );
480 
481 	Debug(LDAP_DEBUG_CONFIG, "rootDSE file=\"%s\" read.\n", fname, 0, 0);
482 	return rc;
483 }
484 
485 int
486 slap_discover_feature(
487 	slap_bindconf	*sb,
488 	const char	*attr,
489 	const char	*val )
490 {
491 	LDAP		*ld = NULL;
492 	LDAPMessage	*res = NULL, *entry;
493 	int		rc, i;
494 	struct berval	bv_val,
495 			**values = NULL;
496 	char		*attrs[ 2 ] = { NULL, NULL };
497 
498 	rc = slap_client_connect( &ld, sb );
499 	if ( rc != LDAP_SUCCESS ) {
500 		goto done;
501 	}
502 
503 	attrs[ 0 ] = (char *) attr;
504 	rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectClass=*)",
505 			attrs, 0, NULL, NULL, NULL, 0, &res );
506 	if ( rc != LDAP_SUCCESS ) {
507 		goto done;
508 	}
509 
510 	entry = ldap_first_entry( ld, res );
511 	if ( entry == NULL ) {
512 		goto done;
513 	}
514 
515 	values = ldap_get_values_len( ld, entry, attrs[ 0 ] );
516 	if ( values == NULL ) {
517 		rc = LDAP_NO_SUCH_ATTRIBUTE;
518 		goto done;
519 	}
520 
521 	ber_str2bv( val, 0, 0, &bv_val );
522 	for ( i = 0; values[ i ] != NULL; i++ ) {
523 		if ( bvmatch( &bv_val, values[ i ] ) ) {
524 			rc = LDAP_COMPARE_TRUE;
525 			goto done;
526 		}
527 	}
528 
529 	rc = LDAP_COMPARE_FALSE;
530 
531 done:;
532 	if ( values != NULL ) {
533 		ldap_value_free_len( values );
534 	}
535 
536 	if ( res != NULL ) {
537 		ldap_msgfree( res );
538 	}
539 
540 	ldap_unbind_ext( ld, NULL, NULL );
541 
542 	return rc;
543 }
544 
545