]> git.sur5r.net Git - openldap/blob - servers/slapd/oc.c
Silence "unused <something>" warnings
[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-2005 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         int set_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         AttributeDescription *objectClass = slap_schema.si_ad_objectClass;
71
72         assert(!( e == NULL || oc == NULL ));
73
74         if( e == NULL || oc == NULL ) {
75                 return 0;
76         }
77
78         if( set_flags && ( e->e_ocflags & SLAP_OC__END )) {
79                 /* flags are set, use them */
80                 return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
81         }
82
83         /*
84          * find objectClass attribute
85          */
86         attr = attr_find(e->e_attrs, objectClass);
87         if( attr == NULL ) {
88                 /* no objectClass attribute */
89                 Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
90                         "no objectClass attribute\n",
91                         e->e_dn == NULL ? "" : e->e_dn,
92                         oc->soc_oclass.oc_oid, 0 );
93
94                 return 0;
95         }
96
97         for( bv=attr->a_vals; bv->bv_val; bv++ ) {
98                 ObjectClass *objectClass = oc_bvfind( bv );
99
100                 if ( !set_flags && objectClass == oc ) {
101                         return 1;
102                 }
103                 
104                 if ( objectClass != NULL ) {
105                         e->e_ocflags |= objectClass->soc_flags;
106                 }
107         }
108
109         /* mark flags as set */
110         e->e_ocflags |= SLAP_OC__END;
111
112         return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
113 }
114
115
116 struct oindexrec {
117         struct berval oir_name;
118         ObjectClass     *oir_oc;
119 };
120
121 static Avlnode  *oc_index = NULL;
122 static Avlnode  *oc_cache = NULL;
123 static LDAP_STAILQ_HEAD(OCList, slap_object_class) oc_list
124         = LDAP_STAILQ_HEAD_INITIALIZER(oc_list);
125
126 static int
127 oc_index_cmp(
128         const void *v_oir1,
129         const void *v_oir2 )
130 {
131         const struct oindexrec *oir1 = v_oir1, *oir2 = v_oir2;
132         int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len;
133         if (i) return i;
134         return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
135 }
136
137 static int
138 oc_index_name_cmp(
139         const void *v_name,
140         const void *v_oir )
141 {
142         const struct berval    *name = v_name;
143         const struct oindexrec *oir  = v_oir;
144         int i = name->bv_len - oir->oir_name.bv_len;
145         if (i) return i;
146         return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
147 }
148
149 ObjectClass *
150 oc_find( const char *ocname )
151 {
152         struct berval bv;
153
154         bv.bv_val = (char *)ocname;
155         bv.bv_len = strlen( ocname );
156
157         return( oc_bvfind( &bv ) );
158 }
159
160 ObjectClass *
161 oc_bvfind( struct berval *ocname )
162 {
163         struct oindexrec        *oir;
164
165         if ( oc_cache ) {
166                 oir = avl_find( oc_cache, ocname, oc_index_name_cmp );
167                 if ( oir ) return oir->oir_oc;
168         }
169         oir = avl_find( oc_index, ocname, oc_index_name_cmp );
170
171         if ( oir != NULL ) {
172                 if ( at_oc_cache ) {
173                         avl_insert( &oc_cache, (caddr_t) oir,
174                                 oc_index_cmp, avl_dup_error );
175                 }
176                 return( oir->oir_oc );
177         }
178
179         return( NULL );
180 }
181
182 static LDAP_STAILQ_HEAD(OCUList, slap_object_class) oc_undef_list
183         = LDAP_STAILQ_HEAD_INITIALIZER(oc_undef_list);
184
185 ObjectClass *
186 oc_bvfind_undef( struct berval *ocname )
187 {
188         ObjectClass     *oc = oc_bvfind( ocname );
189
190         if ( oc ) {
191                 return oc;
192         }
193
194         LDAP_STAILQ_FOREACH( oc, &oc_undef_list, soc_next ) {
195                 int     d = oc->soc_cname.bv_len - ocname->bv_len;
196
197                 if ( d ) {
198                         continue;
199                 }
200
201                 if ( strcasecmp( oc->soc_cname.bv_val, ocname->bv_val ) == 0 ) {
202                         break;
203                 }
204         }
205         
206         if ( oc ) {
207                 return oc;
208         }
209         
210         oc = ch_malloc( sizeof( ObjectClass ) + ocname->bv_len + 1 );
211         memset( oc, 0, sizeof( ObjectClass ) );
212
213         oc->soc_cname.bv_len = ocname->bv_len;
214         oc->soc_cname.bv_val = (char *)&oc[ 1 ];
215         AC_MEMCPY( oc->soc_cname.bv_val, ocname->bv_val, ocname->bv_len );
216
217         LDAP_STAILQ_NEXT( oc, soc_next ) = NULL;
218         LDAP_STAILQ_INSERT_HEAD( &oc_undef_list, oc, soc_next );
219
220         return oc;
221 }
222
223 static int
224 oc_create_required(
225     ObjectClass         *soc,
226     char                **attrs,
227         int                     *op,
228     const char          **err )
229 {
230         char            **attrs1;
231         AttributeType   *sat;
232         AttributeType   **satp;
233         int             i;
234
235         if ( attrs ) {
236                 attrs1 = attrs;
237                 while ( *attrs1 ) {
238                         sat = at_find(*attrs1);
239                         if ( !sat ) {
240                                 *err = *attrs1;
241                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
242                         }
243
244                         if( is_at_operational( sat )) (*op)++;
245
246                         if ( at_find_in_list(sat, soc->soc_required) < 0) {
247                                 if ( at_append_to_list(sat, &soc->soc_required) ) {
248                                         *err = *attrs1;
249                                         return SLAP_SCHERR_OUTOFMEM;
250                                 }
251                         }
252                         attrs1++;
253                 }
254                 /* Now delete duplicates from the allowed list */
255                 for ( satp = soc->soc_required; *satp; satp++ ) {
256                         i = at_find_in_list(*satp,soc->soc_allowed);
257                         if ( i >= 0 ) {
258                                 at_delete_from_list(i, &soc->soc_allowed);
259                         }
260                 }
261         }
262         return 0;
263 }
264
265 static int
266 oc_create_allowed(
267     ObjectClass         *soc,
268     char                **attrs,
269         int                     *op,
270     const char          **err )
271 {
272         char            **attrs1;
273         AttributeType   *sat;
274
275         if ( attrs ) {
276                 attrs1 = attrs;
277                 while ( *attrs1 ) {
278                         sat = at_find(*attrs1);
279                         if ( !sat ) {
280                                 *err = *attrs1;
281                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
282                         }
283
284                         if( is_at_operational( sat )) (*op)++;
285
286                         if ( at_find_in_list(sat, soc->soc_required) < 0 &&
287                              at_find_in_list(sat, soc->soc_allowed) < 0 ) {
288                                 if ( at_append_to_list(sat, &soc->soc_allowed) ) {
289                                         *err = *attrs1;
290                                         return SLAP_SCHERR_OUTOFMEM;
291                                 }
292                         }
293                         attrs1++;
294                 }
295         }
296         return 0;
297 }
298
299 static int
300 oc_add_sups(
301     ObjectClass         *soc,
302     char                        **sups,
303         int                     *op,
304     const char          **err )
305 {
306         int             code;
307         ObjectClass     *soc1;
308         int             nsups;
309         char    **sups1;
310         int             add_sups = 0;
311
312         if ( sups ) {
313                 if ( !soc->soc_sups ) {
314                         /* We are at the first recursive level */
315                         add_sups = 1;
316                         nsups = 1;
317                         sups1 = sups;
318                         while ( *sups1 ) {
319                                 nsups++;
320                                 sups1++;
321                         }
322                         soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
323                                           sizeof(ObjectClass *));
324                 }
325
326                 nsups = 0;
327                 sups1 = sups;
328                 while ( *sups1 ) {
329                         soc1 = oc_find(*sups1);
330                         if ( !soc1 ) {
331                                 *err = *sups1;
332                                 return SLAP_SCHERR_CLASS_NOT_FOUND;
333                         }
334
335                         /* check object class usage
336                          * abstract classes can only sup abstract classes 
337                          * structural classes can not sup auxiliary classes
338                          * auxiliary classes can not sup structural classes
339                          */
340                         if( soc->soc_kind != soc1->soc_kind
341                                 && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
342                         {
343                                 *err = *sups1;
344                                 return SLAP_SCHERR_CLASS_BAD_SUP;
345                         }
346
347                         if( soc1->soc_obsolete && !soc->soc_obsolete ) {
348                                 *err = *sups1;
349                                 return SLAP_SCHERR_CLASS_BAD_SUP;
350                         }
351
352                         if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;
353
354                         if ( add_sups ) {
355                                 soc->soc_sups[nsups] = soc1;
356                         }
357
358                         code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
359                         if ( code ) return code;
360
361                         code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
362                         if ( code ) return code;
363
364                         code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
365                         if ( code ) return code;
366
367                         nsups++;
368                         sups1++;
369                 }
370         }
371
372         return 0;
373 }
374
375 void
376 oc_destroy( void )
377 {
378         ObjectClass *o;
379
380         avl_free(oc_index, ldap_memfree);
381         while( !LDAP_STAILQ_EMPTY(&oc_list) ) {
382                 o = LDAP_STAILQ_FIRST(&oc_list);
383                 LDAP_STAILQ_REMOVE_HEAD(&oc_list, soc_next);
384
385                 if (o->soc_sups) ldap_memfree(o->soc_sups);
386                 if (o->soc_required) ldap_memfree(o->soc_required);
387                 if (o->soc_allowed) ldap_memfree(o->soc_allowed);
388                 ldap_objectclass_free((LDAPObjectClass *)o);
389         }
390         
391         while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
392                 o = LDAP_STAILQ_FIRST(&oc_undef_list);
393                 LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
394
395                 ch_free( (ObjectClass *)o );
396         }
397 }
398
399 /*
400  * check whether the two ObjectClasses actually __are__ identical,
401  * or rather inconsistent
402  */
403 static int
404 oc_check_dup(
405         ObjectClass     *soc,
406         ObjectClass     *new_soc )
407 {
408         if ( new_soc->soc_oid != NULL ) {
409                 if ( soc->soc_oid == NULL ) {
410                         return SLAP_SCHERR_CLASS_INCONSISTENT;
411                 }
412
413                 if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) {
414                         return SLAP_SCHERR_CLASS_INCONSISTENT;
415                 }
416
417         } else {
418                 if ( soc->soc_oid != NULL ) {
419                         return SLAP_SCHERR_CLASS_INCONSISTENT;
420                 }
421         }
422
423         if ( new_soc->soc_names ) {
424                 int     i;
425
426                 if ( soc->soc_names == NULL ) {
427                         return SLAP_SCHERR_CLASS_INCONSISTENT;
428                 }
429
430                 for ( i = 0; new_soc->soc_names[ i ]; i++ ) {
431                         if ( soc->soc_names[ i ] == NULL ) {
432                                 return SLAP_SCHERR_CLASS_INCONSISTENT;
433                         }
434                         
435                         if ( strcasecmp( soc->soc_names[ i ],
436                                         new_soc->soc_names[ i ] ) != 0 )
437                         {
438                                 return SLAP_SCHERR_CLASS_INCONSISTENT;
439                         }
440                 }
441         } else {
442                 if ( soc->soc_names != NULL ) {
443                         return SLAP_SCHERR_CLASS_INCONSISTENT;
444                 }
445         }
446
447         return SLAP_SCHERR_CLASS_DUP;
448 }
449
450 static int
451 oc_insert(
452     ObjectClass         *soc,
453     const char          **err )
454 {
455         struct oindexrec        *oir;
456         char                    **names;
457
458         if ( soc->soc_oid ) {
459                 oir = (struct oindexrec *)
460                         ch_calloc( 1, sizeof(struct oindexrec) );
461                 oir->oir_name.bv_val = soc->soc_oid;
462                 oir->oir_name.bv_len = strlen( soc->soc_oid );
463                 oir->oir_oc = soc;
464
465                 assert( oir->oir_name.bv_val );
466                 assert( oir->oir_oc );
467
468                 if ( avl_insert( &oc_index, (caddr_t) oir,
469                         oc_index_cmp, avl_dup_error ) )
470                 {
471                         ObjectClass     *old_soc;
472                         int             rc;
473
474                         *err = soc->soc_oid;
475
476                         old_soc = oc_bvfind( &oir->oir_name );
477                         assert( old_soc != NULL );
478                         rc = oc_check_dup( old_soc, soc );
479
480                         ldap_memfree( oir );
481                         return rc;
482                 }
483
484                 /* FIX: temporal consistency check */
485                 assert( oc_bvfind( &oir->oir_name ) != NULL );
486         }
487
488         if ( (names = soc->soc_names) ) {
489                 while ( *names ) {
490                         oir = (struct oindexrec *)
491                                 ch_calloc( 1, sizeof(struct oindexrec) );
492                         oir->oir_name.bv_val = *names;
493                         oir->oir_name.bv_len = strlen( *names );
494                         oir->oir_oc = soc;
495
496                         assert( oir->oir_name.bv_val );
497                         assert( oir->oir_oc );
498
499                         if ( avl_insert( &oc_index, (caddr_t) oir,
500                                 oc_index_cmp, avl_dup_error ) )
501                         {
502                                 ObjectClass     *old_soc;
503                                 int             rc;
504
505                                 *err = *names;
506
507                                 old_soc = oc_bvfind( &oir->oir_name );
508                                 assert( old_soc != NULL );
509                                 rc = oc_check_dup( old_soc, soc );
510
511                                 ldap_memfree( oir );
512                                 return rc;
513                         }
514
515                         /* FIX: temporal consistency check */
516                         assert( oc_bvfind(&oir->oir_name) != NULL );
517
518                         names++;
519                 }
520         }
521         LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next );
522
523         return 0;
524 }
525
526 int
527 oc_add(
528     LDAPObjectClass     *oc,
529         int user,
530         ObjectClass             **rsoc,
531     const char          **err )
532 {
533         ObjectClass     *soc;
534         int             code;
535         int             op = 0;
536         char    *oidm = NULL;
537
538         if ( oc->oc_names != NULL ) {
539                 int i;
540
541                 for( i=0; oc->oc_names[i]; i++ ) {
542                         if( !slap_valid_descr( oc->oc_names[i] ) ) {
543                                 return SLAP_SCHERR_BAD_DESCR;
544                         }
545                 }
546         }
547
548         if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
549                 /* Expand OID macros */
550                 char *oid = oidm_find( oc->oc_oid );
551                 if ( !oid ) {
552                         *err = oc->oc_oid;
553                         return SLAP_SCHERR_OIDM;
554                 }
555                 if ( oid != oc->oc_oid ) {
556                         oidm = oc->oc_oid;
557                         oc->oc_oid = oid;
558                 }
559         }
560
561         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
562         AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
563
564         soc->soc_oidmacro = oidm;
565         if( oc->oc_names != NULL ) {
566                 soc->soc_cname.bv_val = soc->soc_names[0];
567         } else {
568                 soc->soc_cname.bv_val = soc->soc_oid;
569         }
570         soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
571
572         if( soc->soc_sup_oids == NULL &&
573                 soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
574         {
575                 /* structural object classes implicitly inherit from 'top' */
576                 static char *top_oids[] = { SLAPD_TOP_OID, NULL };
577                 code = oc_add_sups( soc, top_oids, &op, err );
578         } else {
579                 code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
580         }
581
582         if ( code != 0 ) return code;
583         if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP;
584
585         code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
586         if ( code != 0 ) return code;
587
588         code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
589         if ( code != 0 ) return code;
590
591         if( user && op ) return SLAP_SCHERR_CLASS_BAD_USAGE;
592
593         if( !user ) soc->soc_flags |= SLAP_OC_HARDCODE;
594
595         code = oc_insert(soc,err);
596         if ( code == 0 && rsoc )
597                 *rsoc = soc;
598         return code;
599 }
600
601 void
602 oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys )
603 {
604         ObjectClass *oc;
605         int i, num;
606         struct berval bv, *bva = NULL, idx;
607         char ibuf[32];
608
609         if ( !start )
610                 start = LDAP_STAILQ_FIRST( &oc_list );
611
612         /* count the result size */
613         i = 0;
614         for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
615                 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) continue;
616                 i++;
617                 if ( oc == end ) break;
618         }
619         if (!i) return;
620
621         num = i;
622         bva = ch_malloc( (num+1) * sizeof(struct berval) );
623         BER_BVZERO( bva );
624         idx.bv_val = ibuf;
625         if ( sys ) {
626                 idx.bv_len = 0;
627                 ibuf[0] = '\0';
628         }
629         i = 0;
630         for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
631                 LDAPObjectClass loc, *locp;
632                 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) continue;
633                 if ( oc->soc_oidmacro ) {
634                         loc = oc->soc_oclass;
635                         loc.oc_oid = oc->soc_oidmacro;
636                         locp = &loc;
637                 } else {
638                         locp = &oc->soc_oclass;
639                 }
640                 if ( ldap_objectclass2bv( locp, &bv ) == NULL ) {
641                         ber_bvarray_free( bva );
642                 }
643                 if ( !sys ) {
644                         idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
645                 }
646                 bva[i].bv_len = idx.bv_len + bv.bv_len;
647                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
648                 strcpy( bva[i].bv_val, ibuf );
649                 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
650                 i++;
651                 bva[i].bv_val = NULL;
652                 ldap_memfree( bv.bv_val );
653                 if ( oc == end ) break;
654         }
655         *res = bva;
656 }
657
658 int
659 oc_schema_info( Entry *e )
660 {
661         AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
662         ObjectClass     *oc;
663         struct berval   val;
664         struct berval   nval;
665
666         LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) {
667                 if( oc->soc_flags & SLAP_OC_HIDE ) continue;
668
669                 if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
670                         return -1;
671                 }
672
673                 nval = oc->soc_cname;
674
675 #if 0
676                 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
677                (long) val.bv_len, val.bv_val, nval.bv_val );
678 #endif
679
680                 if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
681                         return -1;
682                 }
683                 ldap_memfree( val.bv_val );
684         }
685         return 0;
686 }