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