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