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
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1999-2021 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 */
38
#ifdef LDAP_DEVEL
Kurt Zeilenga's avatar
Kurt Zeilenga committed
39
	BER_BVC(LDAP_FEATURE_SUBORDINATE_SCOPE),	/* "children" search scope */
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" );
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
258
259
		if ( SLAP_DBHIDDEN( be )) {
			continue;
		}
260
		if ( SLAP_MONITOR( be )) {
261
262
263
264
			if( attr_merge_one( e, ad_monitorContext,
					&be->be_suffix[0],
					&be->be_nsuffix[0] ) )
			{
Howard Chu's avatar
Howard Chu committed
265
				goto fail;
266
267
268
			}
			continue;
		}
269
		if ( SLAP_CONFIG( be )) {
270
271
272
273
			if( attr_merge_one( e, ad_configContext,
					&be->be_suffix[0],
					& be->be_nsuffix[0] ) )
			{
Howard Chu's avatar
Howard Chu committed
274
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
275
			}
276
277
			continue;
		}
278
		if ( SLAP_GLUE_SUBORDINATE( be ) && !SLAP_GLUE_ADVERTISE( be ) ) {
279
			continue;
280
		}
281
		for ( j = 0; be->be_suffix[j].bv_val != NULL; j++ ) {
282
			if( attr_merge_one( e, ad_namingContexts,
283
					&be->be_suffix[j], NULL ) )
284
			{
Howard Chu's avatar
Howard Chu committed
285
				goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
			}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
287
288
289
290
291
		}
	}

	/* altServer unsupported */

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

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

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

311
	/* supportedFeatures */
312
313
314
315
	if ( supportedFeatures == NULL ) {
		supported_feature_init();
	}

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

320
	/* supportedLDAPVersion */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
321
322
323
324
325
326
		/* 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++ ) {
327
		char buf[sizeof("255")];
Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
		snprintf(buf, sizeof buf, "%d", i);
329
330
		val.bv_val = buf;
		val.bv_len = strlen( val.bv_val );
Howard Chu's avatar
Howard Chu committed
331
		if( attr_merge_one( e, ad_supportedLDAPVersion, &val, NULL ) ) {
Howard Chu's avatar
Howard Chu committed
332
			goto fail;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
333
		}
Julio Sánchez Fernández's avatar
 
Julio Sánchez Fernández committed
334
	}
335
336

	/* supportedSASLMechanism */
337
338
	supportedSASLMechanisms = slap_sasl_mechs( conn );

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

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

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

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

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

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

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

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

	return 0;
}

397
398
399
400
401
402
/*
 * 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.
 */
403
404
int
root_dse_read_file( const char *fname )
405
{
406
	struct LDIFFP	*fp;
407
408
	int rc = 0, lmax = 0, ldifrc;
	unsigned long lineno = 0;
409
410
	char	*buf = NULL;

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

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

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

		if( e == NULL ) {
433
			Debug( LDAP_DEBUG_ANY, "root_dse_read_file: "
434
				"could not parse entry (file=\"%s\" line=%lu)\n",
435
				fname, lineno );
436
			rc = LDAP_OTHER;
437
			break;
438
439
		}

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

		/*
		 * 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) {
458
			if( attr_merge( usr_attr, a->a_desc, a->a_vals,
459
				(a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
460
			{
461
462
				rc = LDAP_OTHER;
				break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463
			}
464
465
466
		}

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

470
471
472
	if ( ldifrc < 0 )
		rc = LDAP_OTHER;

473
474
475
	if (rc) {
		entry_free( usr_attr );
		usr_attr = NULL;
476
477
478
479
	}

	ch_free( buf );

480
	ldif_close( fp );
481

482
	Debug(LDAP_DEBUG_CONFIG, "rootDSE file=\"%s\" read.\n", fname );
483
484
	return rc;
}
485
486
487

int
slap_discover_feature(
488
	slap_bindconf	*sb,
489
490
491
	const char	*attr,
	const char	*val )
{
492
	LDAP		*ld = NULL;
493
494
	LDAPMessage	*res = NULL, *entry;
	int		rc, i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
495
	struct berval	bv_val,
496
497
498
			**values = NULL;
	char		*attrs[ 2 ] = { NULL, NULL };

499
	rc = slap_client_connect( &ld, sb );
500
501
502
503
	if ( rc != LDAP_SUCCESS ) {
		goto done;
	}

504
	attrs[ 0 ] = (char *) attr;
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
	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;
	}

522
	ber_str2bv( val, 0, 0, &bv_val );
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
	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;
}