]> git.sur5r.net Git - openldap/blob - servers/slapd/oc.c
Sync with HEAD
[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                 if (o->soc_oidmacro) ldap_memfree(o->soc_oidmacro);
389                 ldap_objectclass_free((LDAPObjectClass *)o);
390         }
391         
392         while( !LDAP_STAILQ_EMPTY(&oc_undef_list) ) {
393                 o = LDAP_STAILQ_FIRST(&oc_undef_list);
394                 LDAP_STAILQ_REMOVE_HEAD(&oc_undef_list, soc_next);
395
396                 ch_free( (ObjectClass *)o );
397         }
398 }
399
400 /*
401  * check whether the two ObjectClasses actually __are__ identical,
402  * or rather inconsistent
403  */
404 static int
405 oc_check_dup(
406         ObjectClass     *soc,
407         ObjectClass     *new_soc )
408 {
409         if ( new_soc->soc_oid != NULL ) {
410                 if ( soc->soc_oid == NULL ) {
411                         return SLAP_SCHERR_CLASS_INCONSISTENT;
412                 }
413
414                 if ( strcmp( soc->soc_oid, new_soc->soc_oid ) != 0 ) {
415                         return SLAP_SCHERR_CLASS_INCONSISTENT;
416                 }
417
418         } else {
419                 if ( soc->soc_oid != NULL ) {
420                         return SLAP_SCHERR_CLASS_INCONSISTENT;
421                 }
422         }
423
424         if ( new_soc->soc_names ) {
425                 int     i;
426
427                 if ( soc->soc_names == NULL ) {
428                         return SLAP_SCHERR_CLASS_INCONSISTENT;
429                 }
430
431                 for ( i = 0; new_soc->soc_names[ i ]; i++ ) {
432                         if ( soc->soc_names[ i ] == NULL ) {
433                                 return SLAP_SCHERR_CLASS_INCONSISTENT;
434                         }
435                         
436                         if ( strcasecmp( soc->soc_names[ i ],
437                                         new_soc->soc_names[ i ] ) != 0 )
438                         {
439                                 return SLAP_SCHERR_CLASS_INCONSISTENT;
440                         }
441                 }
442         } else {
443                 if ( soc->soc_names != NULL ) {
444                         return SLAP_SCHERR_CLASS_INCONSISTENT;
445                 }
446         }
447
448         return SLAP_SCHERR_CLASS_DUP;
449 }
450
451 static int
452 oc_insert(
453     ObjectClass         *soc,
454     const char          **err )
455 {
456         struct oindexrec        *oir;
457         char                    **names;
458
459         if ( soc->soc_oid ) {
460                 oir = (struct oindexrec *)
461                         ch_calloc( 1, sizeof(struct oindexrec) );
462                 oir->oir_name.bv_val = soc->soc_oid;
463                 oir->oir_name.bv_len = strlen( soc->soc_oid );
464                 oir->oir_oc = soc;
465
466                 assert( oir->oir_name.bv_val != NULL );
467                 assert( oir->oir_oc != NULL );
468
469                 if ( avl_insert( &oc_index, (caddr_t) oir,
470                         oc_index_cmp, avl_dup_error ) )
471                 {
472                         ObjectClass     *old_soc;
473                         int             rc;
474
475                         *err = soc->soc_oid;
476
477                         old_soc = oc_bvfind( &oir->oir_name );
478                         assert( old_soc != NULL );
479                         rc = oc_check_dup( old_soc, soc );
480
481                         ldap_memfree( oir );
482                         return rc;
483                 }
484
485                 /* FIX: temporal consistency check */
486                 assert( oc_bvfind( &oir->oir_name ) != NULL );
487         }
488
489         if ( (names = soc->soc_names) ) {
490                 while ( *names ) {
491                         oir = (struct oindexrec *)
492                                 ch_calloc( 1, sizeof(struct oindexrec) );
493                         oir->oir_name.bv_val = *names;
494                         oir->oir_name.bv_len = strlen( *names );
495                         oir->oir_oc = soc;
496
497                         assert( oir->oir_name.bv_val != NULL );
498                         assert( oir->oir_oc != NULL );
499
500                         if ( avl_insert( &oc_index, (caddr_t) oir,
501                                 oc_index_cmp, avl_dup_error ) )
502                         {
503                                 ObjectClass     *old_soc;
504                                 int             rc;
505
506                                 *err = *names;
507
508                                 old_soc = oc_bvfind( &oir->oir_name );
509                                 assert( old_soc != NULL );
510                                 rc = oc_check_dup( old_soc, soc );
511
512                                 ldap_memfree( oir );
513                                 return rc;
514                         }
515
516                         /* FIX: temporal consistency check */
517                         assert( oc_bvfind(&oir->oir_name) != NULL );
518
519                         names++;
520                 }
521         }
522         LDAP_STAILQ_INSERT_TAIL( &oc_list, soc, soc_next );
523
524         return 0;
525 }
526
527 int
528 oc_add(
529     LDAPObjectClass     *oc,
530         int user,
531         ObjectClass             **rsoc,
532     const char          **err )
533 {
534         ObjectClass     *soc;
535         int             code;
536         int             op = 0;
537         char    *oidm = NULL;
538
539         if ( oc->oc_names != NULL ) {
540                 int i;
541
542                 for( i=0; oc->oc_names[i]; i++ ) {
543                         if( !slap_valid_descr( oc->oc_names[i] ) ) {
544                                 return SLAP_SCHERR_BAD_DESCR;
545                         }
546                 }
547         }
548
549         if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
550                 /* Expand OID macros */
551                 char *oid = oidm_find( oc->oc_oid );
552                 if ( !oid ) {
553                         *err = oc->oc_oid;
554                         return SLAP_SCHERR_OIDM;
555                 }
556                 if ( oid != oc->oc_oid ) {
557                         oidm = oc->oc_oid;
558                         oc->oc_oid = oid;
559                 }
560         }
561
562         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
563         AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
564
565         soc->soc_oidmacro = oidm;
566         if( oc->oc_names != NULL ) {
567                 soc->soc_cname.bv_val = soc->soc_names[0];
568         } else {
569                 soc->soc_cname.bv_val = soc->soc_oid;
570         }
571         soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
572
573         if( soc->soc_sup_oids == NULL &&
574                 soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
575         {
576                 /* structural object classes implicitly inherit from 'top' */
577                 static char *top_oids[] = { SLAPD_TOP_OID, NULL };
578                 code = oc_add_sups( soc, top_oids, &op, err );
579         } else {
580                 code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
581         }
582
583         if ( code != 0 ) return code;
584         if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP;
585
586         code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
587         if ( code != 0 ) return code;
588
589         code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
590         if ( code != 0 ) return code;
591
592         if( user && op ) return SLAP_SCHERR_CLASS_BAD_USAGE;
593
594         if( !user ) soc->soc_flags |= SLAP_OC_HARDCODE;
595
596         code = oc_insert(soc,err);
597         if ( code == 0 && rsoc )
598                 *rsoc = soc;
599         return code;
600 }
601
602 void
603 oc_unparse( BerVarray *res, ObjectClass *start, ObjectClass *end, int sys )
604 {
605         ObjectClass *oc;
606         int i, num;
607         struct berval bv, *bva = NULL, idx;
608         char ibuf[32];
609
610         if ( !start )
611                 start = LDAP_STAILQ_FIRST( &oc_list );
612
613         /* count the result size */
614         i = 0;
615         for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
616                 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) continue;
617                 i++;
618                 if ( oc == end ) break;
619         }
620         if (!i) return;
621
622         num = i;
623         bva = ch_malloc( (num+1) * sizeof(struct berval) );
624         BER_BVZERO( bva );
625         idx.bv_val = ibuf;
626         if ( sys ) {
627                 idx.bv_len = 0;
628                 ibuf[0] = '\0';
629         }
630         i = 0;
631         for ( oc=start; oc; oc=LDAP_STAILQ_NEXT(oc, soc_next)) {
632                 LDAPObjectClass loc, *locp;
633                 if ( sys && !(oc->soc_flags & SLAP_OC_HARDCODE)) continue;
634                 if ( oc->soc_oidmacro ) {
635                         loc = oc->soc_oclass;
636                         loc.oc_oid = oc->soc_oidmacro;
637                         locp = &loc;
638                 } else {
639                         locp = &oc->soc_oclass;
640                 }
641                 if ( ldap_objectclass2bv( locp, &bv ) == NULL ) {
642                         ber_bvarray_free( bva );
643                 }
644                 if ( !sys ) {
645                         idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
646                 }
647                 bva[i].bv_len = idx.bv_len + bv.bv_len;
648                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
649                 strcpy( bva[i].bv_val, ibuf );
650                 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
651                 i++;
652                 bva[i].bv_val = NULL;
653                 ldap_memfree( bv.bv_val );
654                 if ( oc == end ) break;
655         }
656         *res = bva;
657 }
658
659 int
660 oc_schema_info( Entry *e )
661 {
662         AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
663         ObjectClass     *oc;
664         struct berval   val;
665         struct berval   nval;
666
667         LDAP_STAILQ_FOREACH( oc, &oc_list, soc_next ) {
668                 if( oc->soc_flags & SLAP_OC_HIDE ) continue;
669
670                 if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
671                         return -1;
672                 }
673
674                 nval = oc->soc_cname;
675
676 #if 0
677                 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
678                (long) val.bv_len, val.bv_val, nval.bv_val );
679 #endif
680
681                 if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
682                         return -1;
683                 }
684                 ldap_memfree( val.bv_val );
685         }
686         return 0;
687 }