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