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