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