root_dse.c 11.3 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* root_dse.c - Provides the Root DSA-Specific Entry */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
4
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1999-2006 The OpenLDAP Foundation.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
6
7
 * All rights reserved.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
10
11
12
13
14
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
15
16
17
18
19
 */

#include "portable.h"

#include <stdio.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
20

Hallvard Furuseth's avatar
Hallvard Furuseth committed
21
22
#include <ac/string.h>

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
23
#include "slap.h"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
24
#include <ldif.h>
25
#include "lber_pvt.h"
26

27
#ifdef LDAP_SLAPI
28
#include "slapi/slapi.h"
29
30
#endif

31
static struct berval	builtin_supportedFeatures[] = {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
32
	BER_BVC(LDAP_FEATURE_MODIFY_INCREMENT),		/* Modify/increment */
33
	BER_BVC(LDAP_FEATURE_ALL_OP_ATTRS),		/* All Op Attrs (+) */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
34
35
	BER_BVC(LDAP_FEATURE_OBJECTCLASS_ATTRS),	/* OCs in Attrs List (@class) */
	BER_BVC(LDAP_FEATURE_ABSOLUTE_FILTERS),		/* (&) and (|) search filters */
36
37
	BER_BVC(LDAP_FEATURE_LANGUAGE_TAG_OPTIONS),	/* Language Tag Options */
	BER_BVC(LDAP_FEATURE_LANGUAGE_RANGE_OPTIONS),	/* Language Range Options */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
38
#ifdef LDAP_DEVEL
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
	BER_BVC(LDAP_FEATURE_SUBORDINATE_SCOPE),	/* "children" search scope */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
40
#endif
41
	BER_BVNULL
42
};
43
static struct berval	*supportedFeatures;
44

45
static Entry	*usr_attr = NULL;
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * allow modules to register functions that muck with the root DSE entry
 */

typedef struct entry_info_t {
	SLAP_ENTRY_INFO_FN	func;
	void			*arg;
	struct entry_info_t	*next;
} entry_info_t;

static entry_info_t *extra_info;

int
entry_info_register( SLAP_ENTRY_INFO_FN func, void *arg )
{
	entry_info_t	*ei = ch_calloc( 1, sizeof( entry_info_t ) );

	ei->func = func;
	ei->arg = arg;

	ei->next = extra_info;
	extra_info = ei;

	return 0;
}

int
entry_info_unregister( SLAP_ENTRY_INFO_FN func, void *arg )
{
	entry_info_t	**eip;

	for ( eip = &extra_info; *eip != NULL; eip = &(*eip)->next ) {
		if ( (*eip)->func == func && (*eip)->arg == arg ) {
			entry_info_t	*ei = *eip;

			*eip = ei->next;

			ch_free( ei );

			return 0;
		}
	}

	return -1;
}

void
entry_info_destroy( void )
{
	entry_info_t	**eip;

	for ( eip = &extra_info; *eip != NULL;  ) {
		entry_info_t	*ei = *eip;

		eip = &(*eip)->next;

		ch_free( ei );
	}
}

/*
 * Allow modules to register supported features
 */

111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
static int
supported_feature_init( void )
{
	int		i;

	if ( supportedFeatures != NULL ) {
		return 0;
	}

	for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ )
		;

	supportedFeatures = ch_calloc( sizeof( struct berval ), i + 1 );
	if ( supportedFeatures == NULL ) {
		return -1;
	}

	for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ ) {
		ber_dupbv( &supportedFeatures[ i ], &builtin_supportedFeatures[ i ] );
	}
	BER_BVZERO( &supportedFeatures[ i ] );

	return 0;
}

int
supported_feature_destroy( void )
{
	int		i;

	if ( supportedFeatures == NULL ) {
		return 0;
	}
	
	for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ ) {
		ch_free( supportedFeatures[ i ].bv_val );
	}

	ch_free( supportedFeatures );
	supportedFeatures = NULL;

	return 0;
}

int
supported_feature_load( struct berval *f )
{
	struct berval	*tmp;
	int		i;

	supported_feature_init();

	for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ )
		;

	tmp = ch_realloc( supportedFeatures, sizeof( struct berval ) * ( i + 2 ) );
	if ( tmp == NULL ) {
		return -1;
	}
	supportedFeatures = tmp;

	ber_dupbv( &supportedFeatures[ i ], f );
	BER_BVZERO( &supportedFeatures[ i + 1 ] );

	return 0;
}

178
int
179
180
181
182
root_dse_info(
	Connection *conn,
	Entry **entry,
	const char **text )
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
183
184
{
	Entry		*e;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
185
186
187
188
	struct berval val;
#ifdef LDAP_SLAPI
	struct berval *bv;
#endif
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
189
	int		i, j;
190
	char ** supportedSASLMechanisms;
191
	BackendDB *be;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
192

193
194
195
196
197
198
	AttributeDescription *ad_structuralObjectClass
		= slap_schema.si_ad_structuralObjectClass;
	AttributeDescription *ad_objectClass
		= slap_schema.si_ad_objectClass;
	AttributeDescription *ad_namingContexts
		= slap_schema.si_ad_namingContexts;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
199
#ifdef LDAP_SLAPI
200
201
	AttributeDescription *ad_supportedExtension
		= slap_schema.si_ad_supportedExtension;
Hallvard Furuseth's avatar
Hallvard Furuseth committed
202
#endif
203
204
205
206
207
208
	AttributeDescription *ad_supportedLDAPVersion
		= slap_schema.si_ad_supportedLDAPVersion;
	AttributeDescription *ad_supportedSASLMechanisms
		= slap_schema.si_ad_supportedSASLMechanisms;
	AttributeDescription *ad_supportedFeatures
		= slap_schema.si_ad_supportedFeatures;
209
210
	AttributeDescription *ad_monitorContext
		= slap_schema.si_ad_monitorContext;
211
212
	AttributeDescription *ad_configContext
		= slap_schema.si_ad_configContext;
213
214
	AttributeDescription *ad_ref
		= slap_schema.si_ad_ref;
215

216
	e = entry_alloc();
Julius Enarusai's avatar
   
Julius Enarusai committed
217
218
	if( e == NULL ) {
		Debug( LDAP_DEBUG_ANY,
219
			"root_dse_info: entry_alloc failed", 0, 0, 0 );
Julius Enarusai's avatar
   
Julius Enarusai committed
220
221
		return LDAP_OTHER;
	}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
222
223

	e->e_attrs = NULL;
224
225
226
227
228
229
230
231
232
	e->e_name.bv_val = ch_strdup( LDAP_ROOT_DSE );
	e->e_name.bv_len = sizeof( LDAP_ROOT_DSE )-1;
	e->e_nname.bv_val = ch_strdup( LDAP_ROOT_DSE );
	e->e_nname.bv_len = sizeof( LDAP_ROOT_DSE )-1;

	/* the DN is an empty string so no pretty/normalization is needed */
	assert( !e->e_name.bv_len );
	assert( !e->e_nname.bv_len );

Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
233
234
	e->e_private = NULL;

235
	/* FIXME: is this really needed? */
236
237
	BER_BVSTR( &val, "top" );
	if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
238
239
fail:
		entry_free( e );
Julius Enarusai's avatar
   
Julius Enarusai committed
240
		return LDAP_OTHER;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
241
	}
242

243
244
	BER_BVSTR( &val, "OpenLDAProotDSE" );
	if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
245
		goto fail;
246
	}
247
	if( attr_merge_one( e, ad_structuralObjectClass, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
248
		goto fail;
249
	}
250

251
252
253
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( be->be_suffix == NULL
				|| be->be_nsuffix == NULL ) {
254
255
256
			/* no suffix! */
			continue;
		}
257
		if ( SLAP_MONITOR( be )) {
258
259
260
261
			if( attr_merge_one( e, ad_monitorContext,
					&be->be_suffix[0],
					&be->be_nsuffix[0] ) )
			{
Howard Chu's avatar
Howard Chu committed
262
				goto fail;
263
264
265
			}
			continue;
		}
266
		if ( SLAP_CONFIG( be )) {
267
268
269
270
			if( attr_merge_one( e, ad_configContext,
					&be->be_suffix[0],
					& be->be_nsuffix[0] ) )
			{
Howard Chu's avatar
Howard Chu committed
271
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
			}
273
274
			continue;
		}
275
		if ( SLAP_GLUE_SUBORDINATE( be ) && !SLAP_GLUE_ADVERTISE( be ) ) {
276
			continue;
277
		}
278
		for ( j = 0; be->be_suffix[j].bv_val != NULL; j++ ) {
279
280
281
282
			if( attr_merge_one( e, ad_namingContexts,
					&be->be_suffix[j],
					&be->be_nsuffix[0] ) )
			{
Howard Chu's avatar
Howard Chu committed
283
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
284
			}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
285
286
287
288
289
		}
	}

	/* altServer unsupported */

290
	/* supportedControl */
291
	if ( controls_root_dse_info( e ) != 0 ) {
Howard Chu's avatar
Howard Chu committed
292
		goto fail;
293
294
295
	}

	/* supportedExtension */
296
	if ( exop_root_dse_info( e ) != 0 ) {
Howard Chu's avatar
Howard Chu committed
297
		goto fail;
298
299
	}

300
#ifdef LDAP_SLAPI
301
	/* netscape supportedExtension */
Luke Howard's avatar
Luke Howard committed
302
	for ( i = 0; (bv = slapi_int_get_supported_extop(i)) != NULL; i++ ) {
303
		if( attr_merge_one( e, ad_supportedExtension, bv, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
304
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
305
		}
306
	}
307
#endif /* LDAP_SLAPI */
308

309
	/* supportedFeatures */
310
311
312
313
	if ( supportedFeatures == NULL ) {
		supported_feature_init();
	}

314
	if( attr_merge( e, ad_supportedFeatures, supportedFeatures, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
315
		goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
316
	}
317

318
	/* supportedLDAPVersion */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
320
321
322
323
324
		/* don't publish version 2 as we don't really support it
		 * (even when configured to accept version 2 Bind requests)
		 * and the value would never be used by true LDAPv2 (or LDAPv3)
		 * clients.
		 */
	for ( i=LDAP_VERSION3; i<=LDAP_VERSION_MAX; i++ ) {
325
		char buf[sizeof("255")];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
326
		snprintf(buf, sizeof buf, "%d", i);
327
328
		val.bv_val = buf;
		val.bv_len = strlen( val.bv_val );
Howard Chu's avatar
Howard Chu committed
329
		if( attr_merge_one( e, ad_supportedLDAPVersion, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
330
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
331
		}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
332
	}
333
334

	/* supportedSASLMechanism */
335
336
	supportedSASLMechanisms = slap_sasl_mechs( conn );

337
338
	if( supportedSASLMechanisms != NULL ) {
		for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) {
339
340
			val.bv_val = supportedSASLMechanisms[i];
			val.bv_len = strlen( val.bv_val );
Howard Chu's avatar
Howard Chu committed
341
			if( attr_merge_one( e, ad_supportedSASLMechanisms, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
342
343
				ldap_charray_free( supportedSASLMechanisms );
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
344
			}
345
		}
346
		ldap_charray_free( supportedSASLMechanisms );
347
348
	}

349
350
	if ( default_referral != NULL ) {
		if( attr_merge( e, ad_ref, default_referral, NULL /* FIXME */ ) ) {
Howard Chu's avatar
Howard Chu committed
351
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
352
		}
353
	}
354

355
	if( usr_attr != NULL) {
Kurt Zeilenga's avatar
Cleanup    
Kurt Zeilenga committed
356
357
		Attribute *a;
		for( a = usr_attr->e_attrs; a != NULL; a = a->a_next ) {
358
			if( attr_merge( e, a->a_desc, a->a_vals,
359
				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360
			{
Howard Chu's avatar
Howard Chu committed
361
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
362
			}
363
364
365
		}
	}

366
367
368
369
370
371
372
373
	if ( extra_info ) {
		entry_info_t	*ei = extra_info;

		for ( ; ei; ei = ei->next ) {
			ei->func( ei->arg, e );
		}
	}

374
375
	*entry = e;
	return LDAP_SUCCESS;
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
376
377
}

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
int
root_dse_init( void )
{
	return 0;
}

int
root_dse_destroy( void )
{
	if ( usr_attr ) {
		entry_free( usr_attr );
		usr_attr = NULL;
	}

	return 0;
}

395
396
397
398
399
400
/*
 * Read the entries specified in fname and merge the attributes
 * to the user defined rootDSE. Note thaat if we find any errors
 * what so ever, we will discard the entire entries, print an
 * error message and return.
 */
401
402
int
root_dse_read_file( const char *fname )
403
{
404
	struct LDIFFP	*fp;
405
406
407
	int rc = 0, lineno = 0, lmax = 0;
	char	*buf = NULL;

408
	if ( (fp = ldif_open( fname, "r" )) == NULL ) {
409
		Debug( LDAP_DEBUG_ANY,
410
			"root_dse_read_file: could not open rootdse attr file \"%s\" - absolute path?\n",
411
412
413
414
415
			fname, 0, 0 );
		perror( fname );
		return EXIT_FAILURE;
	}

416
	usr_attr = entry_alloc();
Julius Enarusai's avatar
   
Julius Enarusai committed
417
418
	if( usr_attr == NULL ) {
		Debug( LDAP_DEBUG_ANY,
419
			"root_dse_read_file: entry_alloc failed", 0, 0, 0 );
420
		ldif_close( fp );
Julius Enarusai's avatar
   
Julius Enarusai committed
421
422
		return LDAP_OTHER;
	}
423
424
425
426
	usr_attr->e_attrs = NULL;

	while( ldif_read_record( fp, &lineno, &buf, &lmax ) ) {
		Entry *e = str2entry( buf );
Kurt Zeilenga's avatar
Cleanup    
Kurt Zeilenga committed
427
		Attribute *a;
428
429

		if( e == NULL ) {
430
431
432
			Debug( LDAP_DEBUG_ANY, "root_dse_read_file: "
				"could not parse entry (file=\"%s\" line=%d)\n",
				fname, lineno, 0 );
433
434
			rc = EXIT_FAILURE;
			break;
435
436
		}

437
438
		/* make sure the DN is the empty DN */
		if( e->e_nname.bv_len ) {
439
440
441
442
			Debug( LDAP_DEBUG_ANY,
				"root_dse_read_file: invalid rootDSE "
				"- dn=\"%s\" (file=\"%s\" line=%d)\n",
				e->e_dn, fname, lineno );
443
			entry_free( e );
444
445
			rc = EXIT_FAILURE;
			break;
446
447
448
449
450
451
452
453
454
		}

		/*
		 * we found a valid entry, so walk thru all the attributes in the
		 * entry, and add each attribute type and description to the
		 * usr_attr entry
		 */

		for(a = e->e_attrs; a != NULL; a = a->a_next) {
455
			if( attr_merge( usr_attr, a->a_desc, a->a_vals,
456
				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
457
			{
458
459
				rc = LDAP_OTHER;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
			}
461
462
463
		}

		entry_free( e );
464
465
466
467
468
469
		if (rc) break;
	}

	if (rc) {
		entry_free( usr_attr );
		usr_attr = NULL;
470
471
472
473
	}

	ch_free( buf );

474
	ldif_close( fp );
475

476
	Debug(LDAP_DEBUG_CONFIG, "rootDSE file=\"%s\" read.\n", fname, 0, 0);
477
478
	return rc;
}
479
480
481

int
slap_discover_feature(
482
	slap_bindconf	*sb,
483
484
485
	const char	*attr,
	const char	*val )
{
486
	LDAP		*ld = NULL;
487
488
	LDAPMessage	*res = NULL, *entry;
	int		rc, i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
489
	struct berval	bv_val,
490
491
492
			**values = NULL;
	char		*attrs[ 2 ] = { NULL, NULL };

493
	rc = slap_client_connect( &ld, sb );
494
495
496
497
	if ( rc != LDAP_SUCCESS ) {
		goto done;
	}

498
	attrs[ 0 ] = (char *) attr;
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
	rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectClass=*)",
			attrs, 0, NULL, NULL, NULL, 0, &res );
	if ( rc != LDAP_SUCCESS ) {
		goto done;
	}

	entry = ldap_first_entry( ld, res );
	if ( entry == NULL ) {
		goto done;
	}

	values = ldap_get_values_len( ld, entry, attrs[ 0 ] );
	if ( values == NULL ) {
		rc = LDAP_NO_SUCH_ATTRIBUTE;
		goto done;
	}

516
	ber_str2bv( val, 0, 0, &bv_val );
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	for ( i = 0; values[ i ] != NULL; i++ ) {
		if ( bvmatch( &bv_val, values[ i ] ) ) {
			rc = LDAP_COMPARE_TRUE;
			goto done;
		}
	}

	rc = LDAP_COMPARE_FALSE;

done:;
	if ( values != NULL ) {
		ldap_value_free_len( values );
	}

	if ( res != NULL ) {
		ldap_msgfree( res );
	}

	ldap_unbind_ext( ld, NULL, NULL );

	return rc;
}