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