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
29int 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
59int 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
133struct oindexrec {
134	struct berval oir_name;
135	ObjectClass	*oir_oc;
136};
137
138static Avlnode	*oc_index = NULL;
139static Avlnode	*oc_cache = NULL;
140static LDAP_STAILQ_HEAD(OCList, ObjectClass) oc_list
141	= LDAP_STAILQ_HEAD_INITIALIZER(oc_list);
142
143ObjectClass *oc_sys_tail;
144
145static int
146oc_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
156static int
157oc_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
168ObjectClass *
169oc_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
179ObjectClass *
180oc_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
201static LDAP_STAILQ_HEAD(OCUList, ObjectClass) oc_undef_list
202	= LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list);
203
204ObjectClass *
205oc_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
248static int
249oc_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
290static int
291oc_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
324static int
325oc_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
400static void
401oc_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 */
421void
422oc_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
431static void
432oc_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
452static void
453oc_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
463void
464oc_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
485int
486oc_start( ObjectClass **oc )
487{
488	assert( oc != NULL );
489
490	*oc = LDAP_STAILQ_FIRST(&oc_list);
491
492	return (*oc != NULL);
493}
494
495int
496oc_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 */
527static int
528oc_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
574static struct oindexrec *oir_old;
575
576static int
577oc_dup_error( void *left, void *right )
578{
579	oir_old = left;
580	return -1;
581}
582
583static int
584oc_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
712int
713oc_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);
798done:;
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
824void
825oc_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
881int
882oc_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
911int
912register_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