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