xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/oc.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: oc.c,v 1.1.1.4 2014/05/28 09:58:47 tron Exp $	*/
2 
3 /* oc.c - object class routines */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 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 	if (!names) return;
406 
407 	while (*names) {
408 		struct oindexrec	tmpoir, *oir;
409 
410 		ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
411 		tmpoir.oir_oc = oc;
412 		oir = (struct oindexrec *)avl_delete( &oc_index,
413 			(caddr_t)&tmpoir, oc_index_cmp );
414 		assert( oir != NULL );
415 		ldap_memfree( oir );
416 		names++;
417 	}
418 }
419 
420 /* Mark the ObjectClass as deleted, remove from list, and remove all its
421  * names from the AVL tree. Leave the OID in the tree.
422  */
423 void
424 oc_delete( ObjectClass *oc )
425 {
426 	oc->soc_flags |= SLAP_OC_DELETED;
427 
428 	LDAP_STAILQ_REMOVE(&oc_list, oc, ObjectClass, soc_next);
429 
430 	oc_delete_names( oc );
431 }
432 
433 static void
434 oc_clean( ObjectClass *o )
435 {
436 	if (o->soc_sups) {
437 		ldap_memfree(o->soc_sups);
438 		o->soc_sups = NULL;
439 	}
440 	if (o->soc_required) {
441 		ldap_memfree(o->soc_required);
442 		o->soc_required = NULL;
443 	}
444 	if (o->soc_allowed) {
445 		ldap_memfree(o->soc_allowed);
446 		o->soc_allowed = NULL;
447 	}
448 	if (o->soc_oidmacro) {
449 		ldap_memfree(o->soc_oidmacro);
450 		o->soc_oidmacro = NULL;
451 	}
452 }
453 
454 static void
455 oc_destroy_one( void *v )
456 {
457 	struct oindexrec *oir = v;
458 	ObjectClass *o = oir->oir_oc;
459 
460 	oc_clean( o );
461 	ldap_objectclass_free((LDAPObjectClass *)o);
462 	ldap_memfree(oir);
463 }
464 
465 void
466 oc_destroy( void )
467 {
468 	ObjectClass *o;
469 
470 	while( !LDAP_STAILQ_EMPTY(&oc_list) ) {
471 		o = LDAP_STAILQ_FIRST(&oc_list);
472 		LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next);
473 
474 		oc_delete_names( o );
475 	}
476 
477 	avl_free( oc_index, oc_destroy_one );
478 
479 	while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
480 		o = LDAP_STAILQ_FIRST(&oc_undef_list);
481 		LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
482 
483 		ch_free( (ObjectClass *)o );
484 	}
485 }
486 
487 int
488 oc_start( ObjectClass **oc )
489 {
490 	assert( oc != NULL );
491 
492 	*oc = LDAP_STAILQ_FIRST(&oc_list);
493 
494 	return (*oc != NULL);
495 }
496 
497 int
498 oc_next( ObjectClass **oc )
499 {
500 	assert( oc != NULL );
501 
502 #if 0	/* pedantic check: breaks when deleting an oc, don't use it. */
503 	{
504 		ObjectClass *tmp = NULL;
505 
506 		LDAP_STAILQ_FOREACH(tmp,&oc_list,soc_next) {
507 			if ( tmp == *oc ) {
508 				break;
509 			}
510 		}
511 
512 		assert( tmp != NULL );
513 	}
514 #endif
515 
516 	if ( *oc == NULL ) {
517 		return 0;
518 	}
519 
520 	*oc = LDAP_STAILQ_NEXT(*oc,soc_next);
521 
522 	return (*oc != NULL);
523 }
524 
525 /*
526  * check whether the two ObjectClasses actually __are__ identical,
527  * or rather inconsistent
528  */
529 static int
530 oc_check_dup(
531 	ObjectClass	*soc,
532 	ObjectClass	*new_soc )
533 {
534 	if ( new_soc->soc_oid != NULL ) {
535 		if ( soc->soc_oid == NULL ) {
536 			return SLAP_SCHERR_CLASS_INCONSISTENT;
537 		}
538 
539 		if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) {
540 			return SLAP_SCHERR_CLASS_INCONSISTENT;
541 		}
542 
543 	} else {
544 		if ( soc->soc_oid != NULL ) {
545 			return SLAP_SCHERR_CLASS_INCONSISTENT;
546 		}
547 	}
548 
549 	if ( new_soc->soc_names ) {
550 		int	i;
551 
552 		if ( soc->soc_names == NULL ) {
553 			return SLAP_SCHERR_CLASS_INCONSISTENT;
554 		}
555 
556 		for ( i = 0; new_soc->soc_names[ i ]; i++ ) {
557 			if ( soc->soc_names[ i ] == NULL ) {
558 				return SLAP_SCHERR_CLASS_INCONSISTENT;
559 			}
560 
561 			if ( strcasecmp( soc->soc_names[ i ],
562 					new_soc->soc_names[ i ] ) != 0 )
563 			{
564 				return SLAP_SCHERR_CLASS_INCONSISTENT;
565 			}
566 		}
567 	} else {
568 		if ( soc->soc_names != NULL ) {
569 			return SLAP_SCHERR_CLASS_INCONSISTENT;
570 		}
571 	}
572 
573 	return SLAP_SCHERR_CLASS_DUP;
574 }
575 
576 static struct oindexrec *oir_old;
577 
578 static int
579 oc_dup_error( void *left, void *right )
580 {
581 	oir_old = left;
582 	return -1;
583 }
584 
585 static int
586 oc_insert(
587     ObjectClass		**roc,
588 	ObjectClass		*prev,
589     const char		**err )
590 {
591 	struct oindexrec	*oir;
592 	char			**names;
593 	ObjectClass		*soc = *roc;
594 
595 	if ( soc->soc_oid ) {
596 		oir = (struct oindexrec *)
597 			ch_calloc( 1, sizeof(struct oindexrec) );
598 		ber_str2bv( soc->soc_oid, 0, 0, &oir->oir_name );
599 		oir->oir_oc = soc;
600 		oir_old = NULL;
601 
602 		if ( avl_insert( &oc_index, (caddr_t) oir,
603 			oc_index_cmp, oc_dup_error ) )
604 		{
605 			ObjectClass	*old_soc;
606 			int		rc;
607 
608 			*err = soc->soc_oid;
609 
610 			assert( oir_old != NULL );
611 			old_soc = oir_old->oir_oc;
612 
613 			/* replacing a deleted definition? */
614 			if ( old_soc->soc_flags & SLAP_OC_DELETED ) {
615 				ObjectClass tmp;
616 
617 				/* Keep old oid, free new oid;
618 				 * Keep new everything else, free old
619 				 */
620 				tmp = *old_soc;
621 				*old_soc = *soc;
622 				old_soc->soc_oid = tmp.soc_oid;
623 				tmp.soc_oid = soc->soc_oid;
624 				*soc = tmp;
625 
626 				oc_clean( soc );
627 				oc_destroy_one( oir );
628 
629 				oir = oir_old;
630 				soc = old_soc;
631 				*roc = soc;
632 			} else {
633 				rc = oc_check_dup( old_soc, soc );
634 
635 				ldap_memfree( oir );
636 				return rc;
637 			}
638 		}
639 
640 		/* FIX: temporal consistency check */
641 		assert( oc_bvfind( &oir->oir_name ) != NULL );
642 	}
643 
644 	assert( soc != NULL );
645 
646 	if ( (names = soc->soc_names) ) {
647 		while ( *names ) {
648 			oir = (struct oindexrec *)
649 				ch_calloc( 1, sizeof(struct oindexrec) );
650 			oir->oir_name.bv_val = *names;
651 			oir->oir_name.bv_len = strlen( *names );
652 			oir->oir_oc = soc;
653 
654 			if ( avl_insert( &oc_index, (caddr_t) oir,
655 				oc_index_cmp, avl_dup_error ) )
656 			{
657 				ObjectClass	*old_soc;
658 				int		rc;
659 
660 				*err = *names;
661 
662 				old_soc = oc_bvfind( &oir->oir_name );
663 				assert( old_soc != NULL );
664 				rc = oc_check_dup( old_soc, soc );
665 
666 				ldap_memfree( oir );
667 
668 				while ( names > soc->soc_names ) {
669 					struct oindexrec	tmpoir;
670 
671 					names--;
672 					ber_str2bv( *names, 0, 0, &tmpoir.oir_name );
673 					tmpoir.oir_oc = soc;
674 					oir = (struct oindexrec *)avl_delete( &oc_index,
675 						(caddr_t)&tmpoir, oc_index_cmp );
676 					assert( oir != NULL );
677 					ldap_memfree( oir );
678 				}
679 
680 				if ( soc->soc_oid ) {
681 					struct oindexrec	tmpoir;
682 
683 					ber_str2bv( soc->soc_oid, 0, 0, &tmpoir.oir_name );
684 					tmpoir.oir_oc = soc;
685 					oir = (struct oindexrec *)avl_delete( &oc_index,
686 						(caddr_t)&tmpoir, oc_index_cmp );
687 					assert( oir != NULL );
688 					ldap_memfree( oir );
689 				}
690 
691 				return rc;
692 			}
693 
694 			/* FIX: temporal consistency check */
695 			assert( oc_bvfind(&oir->oir_name) != NULL );
696 
697 			names++;
698 		}
699 	}
700 	if ( soc->soc_flags & SLAP_OC_HARDCODE ) {
701 		prev = oc_sys_tail;
702 		oc_sys_tail = soc;
703 	}
704 	if ( prev ) {
705 		LDAP_STAILQ_INSERT_AFTER( &oc_list, prev, soc, soc_next );
706 	} else {
707 		LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next );
708 	}
709 
710 	return 0;
711 }
712 
713 int
714 oc_add(
715     LDAPObjectClass	*oc,
716 	int user,
717 	ObjectClass		**rsoc,
718 	ObjectClass		*prev,
719     const char		**err )
720 {
721 	ObjectClass	*soc;
722 	int		code;
723 	int		op = 0;
724 	char	*oidm = NULL;
725 
726 	if ( oc->oc_names != NULL ) {
727 		int i;
728 
729 		for( i=0; oc->oc_names[i]; i++ ) {
730 			if( !slap_valid_descr( oc->oc_names[i] ) ) {
731 				return SLAP_SCHERR_BAD_DESCR;
732 			}
733 		}
734 	}
735 
736 	if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
737 		/* Expand OID macros */
738 		char *oid = oidm_find( oc->oc_oid );
739 		if ( !oid ) {
740 			*err = oc->oc_oid;
741 			return SLAP_SCHERR_OIDM;
742 		}
743 		if ( oid != oc->oc_oid ) {
744 			oidm = oc->oc_oid;
745 			oc->oc_oid = oid;
746 		}
747 	}
748 
749 	soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
750 	AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
751 
752 	soc->soc_oidmacro = oidm;
753 	if( oc->oc_names != NULL ) {
754 		soc->soc_cname.bv_val = soc->soc_names[0];
755 	} else {
756 		soc->soc_cname.bv_val = soc->soc_oid;
757 	}
758 	soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
759 
760 	if( soc->soc_sup_oids == NULL &&
761 		soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
762 	{
763 		/* structural object classes implicitly inherit from 'top' */
764 		static char *top_oids[] = { SLAPD_TOP_OID, NULL };
765 		code = oc_add_sups( soc, top_oids, &op, err );
766 	} else {
767 		code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
768 	}
769 
770 	if ( code != 0 ) {
771 		goto done;
772 	}
773 
774 	if ( user && op ) {
775 		code = SLAP_SCHERR_CLASS_BAD_SUP;
776 		goto done;
777 	}
778 
779 	code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
780 	if ( code != 0 ) {
781 		goto done;
782 	}
783 
784 	code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
785 	if ( code != 0 ) {
786 		goto done;
787 	}
788 
789 	if ( user && op ) {
790 		code = SLAP_SCHERR_CLASS_BAD_USAGE;
791 		goto done;
792 	}
793 
794 	if ( !user ) {
795 		soc->soc_flags |= SLAP_OC_HARDCODE;
796 	}
797 
798 	code = oc_insert(&soc,prev,err);
799 done:;
800 	if ( code != 0 ) {
801 		if ( soc->soc_sups ) {
802 			ch_free( soc->soc_sups );
803 		}
804 
805 		if ( soc->soc_required ) {
806 			ch_free( soc->soc_required );
807 		}
808 
809 		if ( soc->soc_allowed ) {
810 			ch_free( soc->soc_allowed );
811 		}
812 
813 		if ( soc->soc_oidmacro ) {
814 			ch_free( soc->soc_oidmacro );
815 		}
816 
817 		ch_free( soc );
818 
819 	} else if ( rsoc ) {
820 		*rsoc = soc;
821 	}
822 	return code;
823 }
824 
825 void
826 oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys )
827 {
828 	ObjectClass *oc;
829 	int i, num;
830 	struct berval bv, *bva = NULL, idx;
831 	char ibuf[32];
832 
833 	if ( !start )
834 		start = LDAP_STAILQ_FIRST( &oc_list );
835 
836 	/* count the result size */
837 	i = 0;
838 	for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
839 		if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
840 		i++;
841 		if ( oc == end ) break;
842 	}
843 	if (!i) return;
844 
845 	num = i;
846 	bva = ch_malloc( (num+1) * sizeof(struct berval) );
847 	BER_BVZERO( bva );
848 	idx.bv_val = ibuf;
849 	if ( sys ) {
850 		idx.bv_len = 0;
851 		ibuf[0] = '\0';
852 	}
853 	i = 0;
854 	for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
855 		LDAPObjectClass loc, *locp;
856 		if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) break;
857 		if ( oc->soc_oidmacro ) {
858 			loc = oc->soc_oclass;
859 			loc.oc_oid = oc->soc_oidmacro;
860 			locp = &loc;
861 		} else {
862 			locp = &oc->soc_oclass;
863 		}
864 		if ( ldap_objectclass2bv( locp, &bv ) == NULL ) {
865 			ber_bvarray_free( bva );
866 		}
867 		if ( !sys ) {
868 			idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
869 		}
870 		bva[i].bv_len = idx.bv_len + bv.bv_len;
871 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
872 		strcpy( bva[i].bv_val, ibuf );
873 		strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
874 		i++;
875 		bva[i].bv_val = NULL;
876 		ldap_memfree( bv.bv_val );
877 		if ( oc == end ) break;
878 	}
879 	*res = bva;
880 }
881 
882 int
883 oc_schema_info( Entry *e )
884 {
885 	AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
886 	ObjectClass	*oc;
887 	struct berval	val;
888 	struct berval	nval;
889 
890 	LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) {
891 		if( oc->soc_flags & SLAP_OC_HIDE ) continue;
892 
893 		if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
894 			return -1;
895 		}
896 
897 		nval = oc->soc_cname;
898 
899 #if 0
900 		Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
901 	       (long) val.bv_len, val.bv_val, nval.bv_val );
902 #endif
903 
904 		if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
905 			return -1;
906 		}
907 		ldap_memfree( val.bv_val );
908 	}
909 	return 0;
910 }
911 
912 int
913 register_oc( const char *def, ObjectClass **soc, int dupok )
914 {
915 	LDAPObjectClass *oc;
916 	int code;
917 	const char *err;
918 
919 	oc = ldap_str2objectclass( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
920 	if ( !oc ) {
921 		Debug( LDAP_DEBUG_ANY,
922 			"register_oc: objectclass \"%s\": %s, %s\n",
923 			def, ldap_scherr2str(code), err );
924 		return code;
925 	}
926 	code = oc_add(oc,0,NULL,NULL,&err);
927 	if ( code && ( code != SLAP_SCHERR_CLASS_DUP || !dupok )) {
928 		Debug( LDAP_DEBUG_ANY,
929 			"register_oc: objectclass \"%s\": %s, %s\n",
930 			def, scherr2str(code), err );
931 		ldap_objectclass_free(oc);
932 		return code;
933 	}
934 	if ( soc )
935 		*soc = oc_find(oc->oc_names[0]);
936 	if ( code ) {
937 		ldap_objectclass_free(oc);
938 	} else {
939 		ldap_memfree(oc);
940 	}
941 	return 0;
942 }
943