oc.c 10.3 KB
Newer Older
1
2
3
/* oc.c - object class routines */
/* $OpenLDAP$ */
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */

#include "portable.h"

#include <stdio.h>

#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"
#include "ldap_pvt.h"

19
int is_object_subclass(
20
21
	ObjectClass *sup,
	ObjectClass *sub )
22
23
24
{
	int i;

25
26
	if( sub == NULL || sup == NULL ) return 0;

27
#if 1
Julius Enarusai's avatar
   
Julius Enarusai committed
28
29
30
31
32
#ifdef NEW_LOGGING
	LDAP_LOG ( OPERATION, ARGS, 
		"is_object_subclass(%s,%s) %d\n",
		sup->soc_oid, sub->soc_oid, sup == sub );
#else
33
	Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n",
34
		sup->soc_oid, sub->soc_oid, sup == sub );
Julius Enarusai's avatar
   
Julius Enarusai committed
35
#endif
36
37
#endif

38
39
40
41
	if( sup == sub ) {
		return 1;
	}

42
	if( sub->soc_sups == NULL ) {
43
44
45
		return 0;
	}

46
47
	for( i=0; sub->soc_sups[i] != NULL; i++ ) {
		if( is_object_subclass( sup, sub->soc_sups[i] ) ) {
48
49
50
51
52
53
54
			return 1;
		}
	}

	return 0;
}

55
56
int is_entry_objectclass(
	Entry*	e,
57
58
	ObjectClass *oc,
	int set_flags )
59
60
{
	Attribute *attr;
61
	struct berval *bv;
62
	AttributeDescription *objectClass = slap_schema.si_ad_objectClass;
63
	assert(!( e == NULL || oc == NULL ));
Kurt Zeilenga's avatar
Kurt Zeilenga committed
64

65
	if( e == NULL || oc == NULL ) {
66
		return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
67
	}
68

69
	if( set_flags && ( e->e_ocflags & SLAP_OC__END )) {
70
		return (e->e_ocflags & oc->soc_flags) ? 1 : 0;
71
72
	}

73
74
75
	/*
	 * find objectClass attribute
	 */
76
	attr = attr_find(e->e_attrs, objectClass);
77
78
79

	if( attr == NULL ) {
		/* no objectClass attribute */
80
#ifdef NEW_LOGGING
Julius Enarusai's avatar
   
Julius Enarusai committed
81
82
83
84
		LDAP_LOG( OPERATION, ERR, 
			"is_entry_objectclass: dn(%s), oid (%s), no objectClass "
			"attribute.\n", e->e_dn == NULL ? "" : e->e_dn,
			oc->soc_oclass.oc_oid, 0 );
85
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
86
87
		Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
			"no objectClass attribute\n",
88
89
			e->e_dn == NULL ? "" : e->e_dn,
			oc->soc_oclass.oc_oid, 0 );
90
91
#endif

92
93
94
		return 0;
	}

95
96
	for( bv=attr->a_vals; bv->bv_val; bv++ ) {
		ObjectClass *objectClass = oc_bvfind( bv );
97

98
		if ( objectClass == oc && !set_flags ) {
99
100
			return 1;
		}
101
102
103
104
		
		if ( objectClass != NULL ) {
			e->e_ocflags |= objectClass->soc_flags;
		}
105
106
	}
	e->e_ocflags |= SLAP_OC__END;	/* We've finished this */
107

108
	return (e->e_ocflags & oc->soc_flags);
109
110
111
112
}


struct oindexrec {
Howard Chu's avatar
Howard Chu committed
113
	struct berval	oir_name;
114
115
116
117
118
119
120
121
122
	ObjectClass	*oir_oc;
};

static Avlnode	*oc_index = NULL;
static ObjectClass *oc_list = NULL;

static int
oc_index_cmp(
    struct oindexrec	*oir1,
123
    struct oindexrec	*oir2 )
124
{
Howard Chu's avatar
Howard Chu committed
125
126
127
128
	int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len;
	if (i)
		return i;
	return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
129
130
}

131
132
static int
oc_index_name_cmp(
Howard Chu's avatar
Howard Chu committed
133
    struct berval	*name,
134
    struct oindexrec	*oir )
135
{
Howard Chu's avatar
Howard Chu committed
136
137
138
139
	int i = name->bv_len - oir->oir_name.bv_len;
	if (i)
		return i;
	return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
140
141
142
143
144
}

ObjectClass *
oc_find( const char *ocname )
{
Howard Chu's avatar
Howard Chu committed
145
	struct berval bv;
146

Howard Chu's avatar
Howard Chu committed
147
148
	bv.bv_val = (char *)ocname;
	bv.bv_len = strlen( ocname );
149

Howard Chu's avatar
Howard Chu committed
150
	return( oc_bvfind( &bv ) );
151
152
}

153
154
155
156
157
158
ObjectClass *
oc_bvfind( struct berval *ocname )
{
	struct oindexrec	*oir;

	oir = (struct oindexrec *) avl_find( oc_index, ocname,
Howard Chu's avatar
Howard Chu committed
159
            (AVL_CMP) oc_index_name_cmp );
160
161
162
163
164
165
166
167

	if ( oir != NULL ) {
		return( oir->oir_oc );
	}

	return( NULL );
}

168
169
170
171
static int
oc_create_required(
    ObjectClass		*soc,
    char		**attrs,
172
	int			*op,
173
    const char		**err )
174
175
176
177
178
179
180
181
182
183
184
185
186
187
{
	char		**attrs1;
	AttributeType	*sat;
	AttributeType	**satp;
	int		i;

	if ( attrs ) {
		attrs1 = attrs;
		while ( *attrs1 ) {
			sat = at_find(*attrs1);
			if ( !sat ) {
				*err = *attrs1;
				return SLAP_SCHERR_ATTR_NOT_FOUND;
			}
188
189
190

			if( is_at_operational( sat )) (*op)++;

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
			if ( at_find_in_list(sat, soc->soc_required) < 0) {
				if ( at_append_to_list(sat, &soc->soc_required) ) {
					*err = *attrs1;
					return SLAP_SCHERR_OUTOFMEM;
				}
			}
			attrs1++;
		}
		/* Now delete duplicates from the allowed list */
		for ( satp = soc->soc_required; *satp; satp++ ) {
			i = at_find_in_list(*satp,soc->soc_allowed);
			if ( i >= 0 ) {
				at_delete_from_list(i, &soc->soc_allowed);
			}
		}
	}
	return 0;
}

static int
oc_create_allowed(
    ObjectClass		*soc,
    char		**attrs,
214
	int			*op,
215
    const char		**err )
216
217
218
219
220
221
222
223
224
225
226
227
{
	char		**attrs1;
	AttributeType	*sat;

	if ( attrs ) {
		attrs1 = attrs;
		while ( *attrs1 ) {
			sat = at_find(*attrs1);
			if ( !sat ) {
				*err = *attrs1;
				return SLAP_SCHERR_ATTR_NOT_FOUND;
			}
228
229
230

			if( is_at_operational( sat )) (*op)++;

231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
			if ( at_find_in_list(sat, soc->soc_required) < 0 &&
			     at_find_in_list(sat, soc->soc_allowed) < 0 ) {
				if ( at_append_to_list(sat, &soc->soc_allowed) ) {
					*err = *attrs1;
					return SLAP_SCHERR_OUTOFMEM;
				}
			}
			attrs1++;
		}
	}
	return 0;
}

static int
oc_add_sups(
    ObjectClass		*soc,
247
    char			**sups,
248
	int			*op,
249
    const char		**err )
250
251
252
253
{
	int		code;
	ObjectClass	*soc1;
	int		nsups;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
254
	char	**sups1;
255
256
257
258
259
260
	int		add_sups = 0;

	if ( sups ) {
		if ( !soc->soc_sups ) {
			/* We are at the first recursive level */
			add_sups = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
261
			nsups = 1;
262
263
264
265
266
			sups1 = sups;
			while ( *sups1 ) {
				nsups++;
				sups1++;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
267
268
			soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
					  sizeof(ObjectClass *));
269
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
270

271
272
273
274
275
276
277
278
279
		nsups = 0;
		sups1 = sups;
		while ( *sups1 ) {
			soc1 = oc_find(*sups1);
			if ( !soc1 ) {
				*err = *sups1;
				return SLAP_SCHERR_CLASS_NOT_FOUND;
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
280
281
282
283
284
285
286
287
288
289
290
291
			/* check object class usage
			 * abstract classes can only sup abstract classes 
			 * structural classes can not sup auxiliary classes
			 * auxiliary classes can not sup structural classes
			 */
			if( soc->soc_kind != soc1->soc_kind
				&& soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
			{
				*err = *sups1;
				return SLAP_SCHERR_CLASS_BAD_USAGE;
			}

292
293
294
			if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;

			if ( add_sups ) {
295
				soc->soc_sups[nsups] = soc1;
296
			}
297

298
			code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
299
300
			if ( code ) return code;

301
			code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
302
			if ( code ) return code;
303

304
			code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
305
			if ( code ) return code;
306
307
308
309
310

			nsups++;
			sups1++;
		}
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
311

312
313
314
	return 0;
}

315
316
317
318
319
320
321
322
323
void
oc_destroy( void )
{
	ObjectClass *o, *n;

	avl_free(oc_index, ldap_memfree);
	for (o=oc_list; o; o=n)
	{
		n = o->soc_next;
Howard Chu's avatar
Howard Chu committed
324
325
326
		if (o->soc_sups) ldap_memfree(o->soc_sups);
		if (o->soc_required) ldap_memfree(o->soc_required);
		if (o->soc_allowed) ldap_memfree(o->soc_allowed);
327
328
329
330
		ldap_objectclass_free((LDAPObjectClass *)o);
	}
}

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
static int
oc_insert(
    ObjectClass		*soc,
    const char		**err
)
{
	ObjectClass	**ocp;
	struct oindexrec	*oir;
	char			**names;

	ocp = &oc_list;
	while ( *ocp != NULL ) {
		ocp = &(*ocp)->soc_next;
	}
	*ocp = soc;

	if ( soc->soc_oid ) {
		oir = (struct oindexrec *)
			ch_calloc( 1, sizeof(struct oindexrec) );
Howard Chu's avatar
Howard Chu committed
350
351
		oir->oir_name.bv_val = soc->soc_oid;
		oir->oir_name.bv_len = strlen( soc->soc_oid );
352
		oir->oir_oc = soc;
353

Howard Chu's avatar
Howard Chu committed
354
		assert( oir->oir_name.bv_val );
355
356
		assert( oir->oir_oc );

357
358
		if ( avl_insert( &oc_index, (caddr_t) oir,
				 (AVL_CMP) oc_index_cmp,
359
360
				 (AVL_DUP) avl_dup_error ) )
		{
361
362
			*err = soc->soc_oid;
			ldap_memfree(oir);
363
			return SLAP_SCHERR_CLASS_DUP;
364
		}
365

366
		/* FIX: temporal consistency check */
Howard Chu's avatar
Howard Chu committed
367
		assert( oc_bvfind(&oir->oir_name) != NULL );
368
	}
369

370
371
372
373
	if ( (names = soc->soc_names) ) {
		while ( *names ) {
			oir = (struct oindexrec *)
				ch_calloc( 1, sizeof(struct oindexrec) );
Howard Chu's avatar
Howard Chu committed
374
375
			oir->oir_name.bv_val = *names;
			oir->oir_name.bv_len = strlen( *names );
376
			oir->oir_oc = soc;
377

Howard Chu's avatar
Howard Chu committed
378
			assert( oir->oir_name.bv_val );
379
380
			assert( oir->oir_oc );

381
382
			if ( avl_insert( &oc_index, (caddr_t) oir,
					 (AVL_CMP) oc_index_cmp,
383
384
					 (AVL_DUP) avl_dup_error ) )
			{
385
386
				*err = *names;
				ldap_memfree(oir);
387
				return SLAP_SCHERR_CLASS_DUP;
388
			}
389

390
			/* FIX: temporal consistency check */
Howard Chu's avatar
Howard Chu committed
391
			assert( oc_bvfind(&oir->oir_name) != NULL );
392

393
394
395
			names++;
		}
	}
396

397
398
399
400
401
	return 0;
}

int
oc_add(
402
    LDAPObjectClass	*oc,
403
	int user,
404
405
406
407
408
    const char		**err
)
{
	ObjectClass	*soc;
	int		code;
409
	int		op = 0;
410

Kurt Zeilenga's avatar
Kurt Zeilenga committed
411
412
413
414
415
416
417
418
419
420
	if ( oc->oc_names != NULL ) {
		int i;

		for( i=0; oc->oc_names[i]; i++ ) {
			if( !slap_valid_descr( oc->oc_names[i] ) ) {
				return SLAP_SCHERR_BAD_DESCR;
			}
		}
	}

421
422
423
424
425
426
427
428
429
430
431
432
433
	if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
		/* Expand OID macros */
		char *oid = oidm_find( oc->oc_oid );
		if ( !oid ) {
			*err = oc->oc_oid;
			return SLAP_SCHERR_OIDM;
		}
		if ( oid != oc->oc_oid ) {
			ldap_memfree( oc->oc_oid );
			oc->oc_oid = oid;
		}
	}

434
	soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
435
	AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
436

437
438
439
440
441
442
443
	if( oc->oc_names != NULL ) {
		soc->soc_cname.bv_val = soc->soc_names[0];
	} else {
		soc->soc_cname.bv_val = soc->soc_oid;
	}
	soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );

444
445
446
447
448
	if( soc->soc_sup_oids == NULL &&
		soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
	{
		/* structural object classes implicitly inherit from 'top' */
		static char *top_oids[] = { SLAPD_TOP_OID, NULL };
449
		code = oc_add_sups( soc, top_oids, &op, err );
450
	} else {
451
		code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
452
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
453

454
455
	if ( code != 0 ) return code;

456
	code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
457
458
	if ( code != 0 ) return code;

459
	code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
460
461
	if ( code != 0 ) return code;

462
	if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP;
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
	code = oc_insert(soc,err);
	return code;
}

#ifdef LDAP_DEBUG

static void
oc_print( ObjectClass *oc )
{
	int	i;
	const char *mid;

	printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
	if ( oc->soc_required != NULL ) {
		mid = "\trequires ";
		for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
			printf( "%s%s", mid,
			        ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
		printf( "\n" );
	}
	if ( oc->soc_allowed != NULL ) {
		mid = "\tallows ";
		for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
			printf( "%s%s", mid,
			        ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
		printf( "\n" );
	}
}

#endif


#if defined( SLAPD_SCHEMA_DN )

int
oc_schema_info( Entry *e )
{
501
	struct berval	vals[2];
502
503
	ObjectClass	*oc;

504
505
	AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;

506
	vals[1].bv_val = NULL;
507
508

	for ( oc = oc_list; oc; oc = oc->soc_next ) {
509
		if ( ldap_objectclass2bv( &oc->soc_oclass, vals ) == NULL ) {
510
511
			return -1;
		}
512
513
514

		if( oc->soc_flags & SLAP_OC_HIDE ) continue;

515
#if 0
516
		Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
517
	       (long) vals[0].bv_len, vals[0].bv_val, 0 );
518
#endif
519
		attr_merge( e, ad_objectClasses, vals );
520
		ldap_memfree( vals[0].bv_val );
521
522
523
524
525
	}
	return 0;
}

#endif