xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/oc.c (revision 93bf6008f8b7982c1d1a9486e4a4a0e687fe36eb)
1 /* oc.c - object class routines */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/oc.c,v 1.77.2.6 2008/04/14 22:08:32 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 #include "portable.h"
18 
19 #include <stdio.h>
20 
21 #include <ac/ctype.h>
22 #include <ac/string.h>
23 #include <ac/socket.h>
24 
25 #include "slap.h"
26 
27 int is_object_subclass(
28 	ObjectClass *sup,
29 	ObjectClass *sub )
30 {
31 	int i;
32 
33 	if( sub == NULL || sup == NULL ) return 0;
34 
35 #if 0
36 	Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n",
37 		sup->soc_oid, sub->soc_oid, sup == sub );
38 #endif
39 
40 	if ( sup == sub ) {
41 		return 1;
42 	}
43 
44 	if ( sub->soc_sups == NULL ) {
45 		return 0;
46 	}
47 
48 	for ( i = 0; sub->soc_sups[i] != NULL; i++ ) {
49 		if ( is_object_subclass( sup, sub->soc_sups[i] ) ) {
50 			return 1;
51 		}
52 	}
53 
54 	return 0;
55 }
56 
57 int is_entry_objectclass(
58 	Entry*	e,
59 	ObjectClass *oc,
60 	unsigned flags )
61 {
62 	/*
63 	 * set_flags should only be true if oc is one of operational
64 	 * object classes which we support objectClass flags for
65 	 * (e.g., referral, alias, ...).  See <slap.h>.
66 	 */
67 
68 	Attribute *attr;
69 	struct berval *bv;
70 
71 	assert( !( e == NULL || oc == NULL ) );
72 	assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK );
73 
74 	if ( e == NULL || oc == NULL ) {
75 		return 0;
76 	}
77 
78 	if ( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) )
79 	{
80 		/* flags are set, use them */
81 		return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
82 	}
83 
84 	/*
85 	 * find objectClass attribute
86 	 */
87 	attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass );
88 	if ( attr == NULL ) {
89 		/* no objectClass attribute */
90 		Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
91 			"no objectClass attribute\n",
92 			e->e_dn == NULL ? "" : e->e_dn,
93 			oc->soc_oclass.oc_oid, 0 );
94 
95 		return 0;
96 	}
97 
98 	for ( bv = attr->a_vals; bv->bv_val; bv++ ) {
99 		ObjectClass *objectClass = oc_bvfind( bv );
100 
101 		if ( objectClass == NULL ) {
102 			/* FIXME: is this acceptable? */
103 			continue;
104 		}
105 
106 		if ( !( flags & SLAP_OCF_SET_FLAGS ) ) {
107 			if ( objectClass == oc ) {
108 				return 1;
109 			}
110 
111 			if ( ( flags & SLAP_OCF_CHECK_SUP )
112 				&& is_object_subclass( oc, objectClass ) )
113 			{
114 				return 1;
115 			}
116 		}
117 
118 		e->e_ocflags |= objectClass->soc_flags;
119 	}
120 
121 	/* mark flags as set */
122 	e->e_ocflags |= SLAP_OC__END;
123 
124 	return ( e->e_ocflags & oc->soc_flags & SLAP_OC__MASK ) != 0;
125 }
126 
127 
128 struct oindexrec {
129 	struct berval oir_name;
130 	ObjectClass	*oir_oc;
131 };
132 
133 static Avlnode	*oc_index = NULL;
134 static Avlnode	*oc_cache = NULL;
135 static LDAP_STAILQ_HEAD(OCList, ObjectClass) oc_list
136 	= LDAP_STAILQ_HEAD_INITIALIZER(oc_list);
137 
138 ObjectClass *oc_sys_tail;
139 
140 static int
141 oc_index_cmp(
142 	const void *v_oir1,
143 	const void *v_oir2 )
144 {
145 	const struct oindexrec *oir1 = v_oir1, *oir2 = v_oir2;
146 	int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len;
147 	if (i) return i;
148 	return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
149 }
150 
151 static int
152 oc_index_name_cmp(
153 	const void *v_name,
154 	const void *v_oir )
155 {
156 	const struct berval    *name = v_name;
157 	const struct oindexrec *oir  = v_oir;
158 	int i = name->bv_len - oir->oir_name.bv_len;
159 	if (i) return i;
160 	return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
161 }
162 
163 ObjectClass *
164 oc_find( const char *ocname )
165 {
166 	struct berval bv;
167 
168 	bv.bv_val = (char *)ocname;
169 	bv.bv_len = strlen( ocname );
170 
171 	return( oc_bvfind( &bv ) );
172 }
173 
174 ObjectClass *
175 oc_bvfind( struct berval *ocname )
176 {
177 	struct oindexrec	*oir;
178 
179 	if ( oc_cache ) {
180 		oir = avl_find( oc_cache, ocname, oc_index_name_cmp );
181 		if ( oir ) return oir->oir_oc;
182 	}
183 	oir = avl_find( oc_index, ocname, oc_index_name_cmp );
184 
185 	if ( oir != NULL ) {
186 		if ( at_oc_cache ) {
187 			avl_insert( &oc_cache, (caddr_t) oir,
188 				oc_index_cmp, avl_dup_error );
189 		}
190 		return( oir->oir_oc );
191 	}
192 
193 	return( NULL );
194 }
195 
196 static LDAP_STAILQ_HEAD(OCUList, ObjectClass) oc_undef_list
197 	= LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list);
198 
199 ObjectClass *
200 oc_bvfind_undef( struct berval *ocname )
201 {
202 	ObjectClass	*oc = oc_bvfind( ocname );
203 
204 	if ( oc ) {
205 		return oc;
206 	}
207 
208 	LDAP_STAILQ_FOREACH( oc, &oc_undef_list, soc_next ) {
209 		int	d = oc->soc_cname.bv_len - ocname->bv_len;
210 
211 		if ( d ) {
212 			continue;
213 		}
214 
215 		if ( strcasecmp( oc->soc_cname.bv_val, ocname->bv_val ) == 0 ) {
216 			break;
217 		}
218 	}
219 
220 	if ( oc ) {
221 		return oc;
222 	}
223 
224 	oc = ch_malloc( sizeof( ObjectClass ) + ocname->bv_len + 1 );
225 	memset( oc, 0, sizeof( ObjectClass ) );
226 
227 	oc->soc_cname.bv_len = ocname->bv_len;
228 	oc->soc_cname.bv_val = (char *)&oc[ 1 ];
229 	AC_MEMCPY( oc->soc_cname.bv_val, ocname->bv_val, ocname->bv_len );
230 
231 	LDAP_STAILQ_NEXT( oc, soc_next ) = NULL;
232 	ldap_pvt_thread_mutex_lock( &oc_undef_mutex );
233 	LDAP_STAILQ_INSERT_HEAD( &oc_undef_list, oc, soc_next );
234 	ldap_pvt_thread_mutex_unlock( &oc_undef_mutex );
235 
236 	return oc;
237 }
238 
239 static int
240 oc_create_required(
241 	ObjectClass		*soc,
242 	char			**attrs,
243 	int			*op,
244 	const char		**err )
245 {
246 	char		**attrs1;
247 	AttributeType	*sat;
248 	AttributeType	**satp;
249 	int		i;
250 
251 	if ( attrs ) {
252 		attrs1 = attrs;
253 		while ( *attrs1 ) {
254 			sat = at_find(*attrs1);
255 			if ( !sat ) {
256 				*err = *attrs1;
257 				return SLAP_SCHERR_ATTR_NOT_FOUND;
258 			}
259 
260 			if( is_at_operational( sat )) (*op)++;
261 
262 			if ( at_find_in_list(sat, soc->soc_required) < 0) {
263 				if ( at_append_to_list(sat, &soc->soc_required) ) {
264 					*err = *attrs1;
265 					return SLAP_SCHERR_OUTOFMEM;
266 				}
267 			}
268 			attrs1++;
269 		}
270 		/* Now delete duplicates from the allowed list */
271 		for ( satp = soc->soc_required; *satp; satp++ ) {
272 			i = at_find_in_list(*satp, soc->soc_allowed);
273 			if ( i >= 0 ) {
274 				at_delete_from_list(i, &soc->soc_allowed);
275 			}
276 		}
277 	}
278 	return 0;
279 }
280 
281 static int
282 oc_create_allowed(
283     ObjectClass		*soc,
284     char		**attrs,
285 	int			*op,
286     const char		**err )
287 {
288 	char		**attrs1;
289 	AttributeType	*sat;
290 
291 	if ( attrs ) {
292 		attrs1 = attrs;
293 		while ( *attrs1 ) {
294 			sat = at_find(*attrs1);
295 			if ( !sat ) {
296 				*err = *attrs1;
297 				return SLAP_SCHERR_ATTR_NOT_FOUND;
298 			}
299 
300 			if( is_at_operational( sat )) (*op)++;
301 
302 			if ( at_find_in_list(sat, soc->soc_required) < 0 &&
303 			     at_find_in_list(sat, soc->soc_allowed) < 0 ) {
304 				if ( at_append_to_list(sat, &soc->soc_allowed) ) {
305 					*err = *attrs1;
306 					return SLAP_SCHERR_OUTOFMEM;
307 				}
308 			}
309 			attrs1++;
310 		}
311 	}
312 	return 0;
313 }
314 
315 static int
316 oc_add_sups(
317 	ObjectClass		*soc,
318 	char			**sups,
319 	int			*op,
320 	const char		**err )
321 {
322 	int		code;
323 	ObjectClass	*soc1;
324 	int		nsups;
325 	char	**sups1;
326 	int		add_sups = 0;
327 
328 	if ( sups ) {
329 		if ( !soc->soc_sups ) {
330 			/* We are at the first recursive level */
331 			add_sups = 1;
332 			nsups = 1;
333 			sups1 = sups;
334 			while ( *sups1 ) {
335 				nsups++;
336 				sups1++;
337 			}
338 			soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
339 					  sizeof(ObjectClass *));
340 		}
341 
342 		nsups = 0;
343 		sups1 = sups;
344 		while ( *sups1 ) {
345 			soc1 = oc_find(*sups1);
346 			if ( !soc1 ) {
347 				*err = *sups1;
348 				return SLAP_SCHERR_CLASS_NOT_FOUND;
349 			}
350 
351 			/* check object class usage
352 			 * abstract classes can only sup abstract classes
353 			 * structural classes can not sup auxiliary classes
354 			 * auxiliary classes can not sup structural classes
355 			 */
356 			if( soc->soc_kind != soc1->soc_kind
357 				&& soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
358 			{
359 				*err = *sups1;
360 				return SLAP_SCHERR_CLASS_BAD_SUP;
361 			}
362 
363 			if( soc1->soc_obsolete && !soc->soc_obsolete ) {
364 				*err = *sups1;
365 				return SLAP_SCHERR_CLASS_BAD_SUP;
366 			}
367 
368 			if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;
369 
370 			if ( add_sups ) {
371 				soc->soc_sups[nsups] = soc1;
372 			}
373 
374 			code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
375 			if ( code ) return code;
376 
377 			code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
378 			if ( code ) return code;
379 
380 			code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
381 			if ( code ) return code;
382 
383 			nsups++;
384 			sups1++;
385 		}
386 	}
387 
388 	return 0;
389 }
390 
391 static void
392 oc_delete_names( ObjectClass *oc )
393 {
394 	char			**names = oc->soc_names;
395 
396 	while (*names) {
397 		struct oindexrec	tmpoir, *oir;
398 
399 		ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
400 		tmpoir.oir_oc = oc;
401 		oir = (struct oindexrec *)avl_delete( &oc_index,
402 			(caddr_t)&tmpoir, oc_index_cmp );
403 		assert( oir != NULL );
404 		ldap_memfree( oir );
405 		names++;
406 	}
407 }
408 
409 /* Mark the ObjectClass as deleted, remove from list, and remove all its
410  * names from the AVL tree. Leave the OID in the tree.
411  */
412 void
413 oc_delete( ObjectClass *oc )
414 {
415 	oc->soc_flags |= SLAP_OC_DELETED;
416 
417 	LDAP_STAILQ_REMOVE(&oc_list, oc, ObjectClass, soc_next);
418 
419 	oc_delete_names( oc );
420 }
421 
422 static void
423 oc_clean( ObjectClass *o )
424 {
425 	if (o->soc_sups) {
426 		ldap_memfree(o->soc_sups);
427 		o->soc_sups = NULL;
428 	}
429 	if (o->soc_required) {
430 		ldap_memfree(o->soc_required);
431 		o->soc_required = NULL;
432 	}
433 	if (o->soc_allowed) {
434 		ldap_memfree(o->soc_allowed);
435 		o->soc_allowed = NULL;
436 	}
437 	if (o->soc_oidmacro) {
438 		ldap_memfree(o->soc_oidmacro);
439 		o->soc_oidmacro = NULL;
440 	}
441 }
442 
443 static void
444 oc_destroy_one( void *v )
445 {
446 	struct oindexrec *oir = v;
447 	ObjectClass *o = oir->oir_oc;
448 
449 	oc_clean( o );
450 	ldap_objectclass_free((LDAPObjectClass *)o);
451 	ldap_memfree(oir);
452 }
453 
454 void
455 oc_destroy( void )
456 {
457 	ObjectClass *o;
458 
459 	while( !LDAP_STAILQ_EMPTY(&oc_list) ) {
460 		o = LDAP_STAILQ_FIRST(&oc_list);
461 		LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next);
462 
463 		oc_delete_names( o );
464 	}
465 
466 	avl_free( oc_index, oc_destroy_one );
467 
468 	while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
469 		o = LDAP_STAILQ_FIRST(&oc_undef_list);
470 		LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
471 
472 		ch_free( (ObjectClass *)o );
473 	}
474 }
475 
476 int
477 oc_start( ObjectClass **oc )
478 {
479 	assert( oc != NULL );
480 
481 	*oc = LDAP_STAILQ_FIRST(&oc_list);
482 
483 	return (*oc != NULL);
484 }
485 
486 int
487 oc_next( ObjectClass **oc )
488 {
489 	assert( oc != NULL );
490 
491 #if 0	/* pedantic check: breaks when deleting an oc, don't use it. */
492 	{
493 		ObjectClass *tmp = NULL;
494 
495 		LDAP_STAILQ_FOREACH(tmp,&oc_list,soc_next) {
496 			if ( tmp == *oc ) {
497 				break;
498 			}
499 		}
500 
501 		assert( tmp != NULL );
502 	}
503 #endif
504 
505 	if ( *oc == NULL ) {
506 		return 0;
507 	}
508 
509 	*oc = LDAP_STAILQ_NEXT(*oc,soc_next);
510 
511 	return (*oc != NULL);
512 }
513 
514 /*
515  * check whether the two ObjectClasses actually __are__ identical,
516  * or rather inconsistent
517  */
518 static int
519 oc_check_dup(
520 	ObjectClass	*soc,
521 	ObjectClass	*new_soc )
522 {
523 	if ( new_soc->soc_oid != NULL ) {
524 		if ( soc->soc_oid == NULL ) {
525 			return SLAP_SCHERR_CLASS_INCONSISTENT;
526 		}
527 
528 		if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) {
529 			return SLAP_SCHERR_CLASS_INCONSISTENT;
530 		}
531 
532 	} else {
533 		if ( soc->soc_oid != NULL ) {
534 			return SLAP_SCHERR_CLASS_INCONSISTENT;
535 		}
536 	}
537 
538 	if ( new_soc->soc_names ) {
539 		int	i;
540 
541 		if ( soc->soc_names == NULL ) {
542 			return SLAP_SCHERR_CLASS_INCONSISTENT;
543 		}
544 
545 		for ( i = 0; new_soc->soc_names[ i ]; i++ ) {
546 			if ( soc->soc_names[ i ] == NULL ) {
547 				return SLAP_SCHERR_CLASS_INCONSISTENT;
548 			}
549 
550 			if ( strcasecmp( soc->soc_names[ i ],
551 					new_soc->soc_names[ i ] ) != 0 )
552 			{
553 				return SLAP_SCHERR_CLASS_INCONSISTENT;
554 			}
555 		}
556 	} else {
557 		if ( soc->soc_names != NULL ) {
558 			return SLAP_SCHERR_CLASS_INCONSISTENT;
559 		}
560 	}
561 
562 	return SLAP_SCHERR_CLASS_DUP;
563 }
564 
565 static struct oindexrec *oir_old;
566 
567 static int
568 oc_dup_error( void *left, void *right )
569 {
570 	oir_old = left;
571 	return -1;
572 }
573 
574 static int
575 oc_insert(
576     ObjectClass		**roc,
577 	ObjectClass		*prev,
578     const char		**err )
579 {
580 	struct oindexrec	*oir;
581 	char			**names;
582 	ObjectClass		*soc = *roc;
583 
584 	if ( soc->soc_oid ) {
585 		oir = (struct oindexrec *)
586 			ch_calloc( 1, sizeof(struct oindexrec) );
587 		ber_str2bv( soc->soc_oid, 0, 0, &oir->oir_name );
588 		oir->oir_oc = soc;
589 		oir_old = NULL;
590 
591 		if ( avl_insert( &oc_index, (caddr_t) oir,
592 			oc_index_cmp, oc_dup_error ) )
593 		{
594 			ObjectClass	*old_soc;
595 			int		rc;
596 
597 			*err = soc->soc_oid;
598 
599 			assert( oir_old != NULL );
600 			old_soc = oir_old->oir_oc;
601 
602 			/* replacing a deleted definition? */
603 			if ( old_soc->soc_flags & SLAP_OC_DELETED ) {
604 				ObjectClass tmp;
605 
606 				/* Keep old oid, free new oid;
607 				 * Keep new everything else, free old
608 				 */
609 				tmp = *old_soc;
610 				*old_soc = *soc;
611 				old_soc->soc_oid = tmp.soc_oid;
612 				tmp.soc_oid = soc->soc_oid;
613 				*soc = tmp;
614 
615 				oc_clean( soc );
616 				oc_destroy_one( oir );
617 
618 				oir = oir_old;
619 				soc = old_soc;
620 				*roc = soc;
621 			} else {
622 				rc = oc_check_dup( old_soc, soc );
623 
624 				ldap_memfree( oir );
625 				return rc;
626 			}
627 		}
628 
629 		/* FIX: temporal consistency check */
630 		assert( oc_bvfind( &oir->oir_name ) != NULL );
631 	}
632 
633 	if ( (names = soc->soc_names) ) {
634 		while ( *names ) {
635 			oir = (struct oindexrec *)
636 				ch_calloc( 1, sizeof(struct oindexrec) );
637 			oir->oir_name.bv_val = *names;
638 			oir->oir_name.bv_len = strlen( *names );
639 			oir->oir_oc = soc;
640 
641 			assert( oir->oir_name.bv_val != NULL );
642 			assert( oir->oir_oc != NULL );
643 
644 			if ( avl_insert( &oc_index, (caddr_t) oir,
645 				oc_index_cmp, avl_dup_error ) )
646 			{
647 				ObjectClass	*old_soc;
648 				int		rc;
649 
650 				*err = *names;
651 
652 				old_soc = oc_bvfind( &oir->oir_name );
653 				assert( old_soc != NULL );
654 				rc = oc_check_dup( old_soc, soc );
655 
656 				ldap_memfree( oir );
657 
658 				while ( names > soc->soc_names ) {
659 					struct oindexrec	tmpoir;
660 
661 					names--;
662 					ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
663 					tmpoir.oir_oc = soc;
664 					oir = (struct oindexrec *)avl_delete( &oc_index,
665 						(caddr_t)&tmpoir, oc_index_cmp );
666 					assert( oir != NULL );
667 					ldap_memfree( oir );
668 				}
669 
670 				if ( soc->soc_oid ) {
671 					struct oindexrec	tmpoir;
672 
673 					ber_str2bv( soc->soc_oid, 0, 0, &tmpoir.oir_name );
674 					tmpoir.oir_oc = soc;
675 					oir = (struct oindexrec *)avl_delete( &oc_index,
676 						(caddr_t)&tmpoir, oc_index_cmp );
677 					assert( oir != NULL );
678 					ldap_memfree( oir );
679 				}
680 
681 				return rc;
682 			}
683 
684 			/* FIX: temporal consistency check */
685 			assert( oc_bvfind(&oir->oir_name) != NULL );
686 
687 			names++;
688 		}
689 	}
690 	if ( soc->soc_flags & SLAP_OC_HARDCODE ) {
691 		prev = oc_sys_tail;
692 		oc_sys_tail = soc;
693 	}
694 	if ( prev ) {
695 		LDAP_STAILQ_INSERT_AFTER( &oc_list, prev, soc, soc_next );
696 	} else {
697 		LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next );
698 	}
699 
700 	return 0;
701 }
702 
703 int
704 oc_add(
705     LDAPObjectClass	*oc,
706 	int user,
707 	ObjectClass		**rsoc,
708 	ObjectClass		*prev,
709     const char		**err )
710 {
711 	ObjectClass	*soc;
712 	int		code;
713 	int		op = 0;
714 	char	*oidm = NULL;
715 
716 	if ( oc->oc_names != NULL ) {
717 		int i;
718 
719 		for( i=0; oc->oc_names[i]; i++ ) {
720 			if( !slap_valid_descr( oc->oc_names[i] ) ) {
721 				return SLAP_SCHERR_BAD_DESCR;
722 			}
723 		}
724 	}
725 
726 	if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
727 		/* Expand OID macros */
728 		char *oid = oidm_find( oc->oc_oid );
729 		if ( !oid ) {
730 			*err = oc->oc_oid;
731 			return SLAP_SCHERR_OIDM;
732 		}
733 		if ( oid != oc->oc_oid ) {
734 			oidm = oc->oc_oid;
735 			oc->oc_oid = oid;
736 		}
737 	}
738 
739 	soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
740 	AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
741 
742 	soc->soc_oidmacro = oidm;
743 	if( oc->oc_names != NULL ) {
744 		soc->soc_cname.bv_val = soc->soc_names[0];
745 	} else {
746 		soc->soc_cname.bv_val = soc->soc_oid;
747 	}
748 	soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
749 
750 	if( soc->soc_sup_oids == NULL &&
751 		soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
752 	{
753 		/* structural object classes implicitly inherit from 'top' */
754 		static char *top_oids[] = { SLAPD_TOP_OID, NULL };
755 		code = oc_add_sups( soc, top_oids, &op, err );
756 	} else {
757 		code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
758 	}
759 
760 	if ( code != 0 ) {
761 		goto done;
762 	}
763 
764 	if ( user && op ) {
765 		code = SLAP_SCHERR_CLASS_BAD_SUP;
766 		goto done;
767 	}
768 
769 	code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
770 	if ( code != 0 ) {
771 		goto done;
772 	}
773 
774 	code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
775 	if ( code != 0 ) {
776 		goto done;
777 	}
778 
779 	if ( user && op ) {
780 		code = SLAP_SCHERR_CLASS_BAD_USAGE;
781 		goto done;
782 	}
783 
784 	if ( !user ) {
785 		soc->soc_flags |= SLAP_OC_HARDCODE;
786 	}
787 
788 	code = oc_insert(&soc,prev,err);
789 done:;
790 	if ( code != 0 ) {
791 		if ( soc->soc_sups ) {
792 			ch_free( soc->soc_sups );
793 		}
794 
795 		if ( soc->soc_required ) {
796 			ch_free( soc->soc_required );
797 		}
798 
799 		if ( soc->soc_allowed ) {
800 			ch_free( soc->soc_allowed );
801 		}
802 
803 		ch_free( soc );
804 
805 	} else if ( rsoc ) {
806 		*rsoc = soc;
807 	}
808 	return code;
809 }
810 
811 void
812 oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys )
813 {
814 	ObjectClass *oc;
815 	int i, num;
816 	struct berval bv, *bva = NULL, idx;
817 	char ibuf[32];
818 
819 	if ( !start )
820 		start = LDAP_STAILQ_FIRST( &oc_list );
821 
822 	/* count the result size */
823 	i = 0;
824 	for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
825 		if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
826 		i++;
827 		if ( oc == end ) break;
828 	}
829 	if (!i) return;
830 
831 	num = i;
832 	bva = ch_malloc( (num+1) * sizeof(struct berval) );
833 	BER_BVZERO( bva );
834 	idx.bv_val = ibuf;
835 	if ( sys ) {
836 		idx.bv_len = 0;
837 		ibuf[0] = '\0';
838 	}
839 	i = 0;
840 	for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
841 		LDAPObjectClass loc, *locp;
842 		if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
843 		if ( oc->soc_oidmacro ) {
844 			loc = oc->soc_oclass;
845 			loc.oc_oid = oc->soc_oidmacro;
846 			locp = &loc;
847 		} else {
848 			locp = &oc->soc_oclass;
849 		}
850 		if ( ldap_objectclass2bv( locp, &bv ) == NULL ) {
851 			ber_bvarray_free( bva );
852 		}
853 		if ( !sys ) {
854 			idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
855 		}
856 		bva[i].bv_len = idx.bv_len + bv.bv_len;
857 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
858 		strcpy( bva[i].bv_val, ibuf );
859 		strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
860 		i++;
861 		bva[i].bv_val = NULL;
862 		ldap_memfree( bv.bv_val );
863 		if ( oc == end ) break;
864 	}
865 	*res = bva;
866 }
867 
868 int
869 oc_schema_info( Entry *e )
870 {
871 	AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
872 	ObjectClass	*oc;
873 	struct berval	val;
874 	struct berval	nval;
875 
876 	LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) {
877 		if( oc->soc_flags & SLAP_OC_HIDE ) continue;
878 
879 		if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
880 			return -1;
881 		}
882 
883 		nval = oc->soc_cname;
884 
885 #if 0
886 		Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
887 	       (long) val.bv_len, val.bv_val, nval.bv_val );
888 #endif
889 
890 		if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
891 			return -1;
892 		}
893 		ldap_memfree( val.bv_val );
894 	}
895 	return 0;
896 }
897 
898 int
899 register_oc( const char *def, ObjectClass **soc, int dupok )
900 {
901 	LDAPObjectClass *oc;
902 	int code;
903 	const char *err;
904 
905 	oc = ldap_str2objectclass( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
906 	if ( !oc ) {
907 		Debug( LDAP_DEBUG_ANY,
908 			"register_oc: objectclass \"%s\": %s, %s\n",
909 			def, ldap_scherr2str(code), err );
910 		return code;
911 	}
912 	code = oc_add(oc,0,NULL,NULL,&err);
913 	if ( code && ( code != SLAP_SCHERR_CLASS_DUP || !dupok )) {
914 		Debug( LDAP_DEBUG_ANY,
915 			"register_oc: objectclass \"%s\": %s, %s\n",
916 			def, scherr2str(code), err );
917 		ldap_objectclass_free(oc);
918 		return code;
919 	}
920 	if ( soc )
921 		*soc = oc_find(oc->oc_names[0]);
922 	if ( code ) {
923 		ldap_objectclass_free(oc);
924 	} else {
925 		ldap_memfree(oc);
926 	}
927 	return 0;
928 }
929