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