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