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