]> git.sur5r.net Git - openldap/blob - servers/slapd/oc.c
fix controls propagation (ITS#3813)
[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 #include "ldap_pvt.h"
27
28 int is_object_subclass(
29         ObjectClass *sup,
30         ObjectClass *sub )
31 {
32         int i;
33
34         if( sub == NULL || sup == NULL ) return 0;
35
36 #if 0
37 #ifdef NEW_LOGGING
38         LDAP_LOG ( OPERATION, ARGS, 
39                 "is_object_subclass(%s,%s) %d\n",
40                 sup->soc_oid, sub->soc_oid, sup == sub );
41 #else
42         Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n",
43                 sup->soc_oid, sub->soc_oid, sup == sub );
44 #endif
45 #endif
46
47         if( sup == sub ) {
48                 return 1;
49         }
50
51         if( sub->soc_sups == NULL ) {
52                 return 0;
53         }
54
55         for( i=0; sub->soc_sups[i] != NULL; i++ ) {
56                 if( is_object_subclass( sup, sub->soc_sups[i] ) ) {
57                         return 1;
58                 }
59         }
60
61         return 0;
62 }
63
64 int is_entry_objectclass(
65         Entry*  e,
66         ObjectClass *oc,
67         int set_flags )
68 {
69         /*
70          * set_flags should only be true if oc is one of operational
71          * object classes which we support objectClass flags for
72          * (e.g., referral, alias, ...).  See <slap.h>.
73          */
74
75         Attribute *attr;
76         struct berval *bv;
77         AttributeDescription *objectClass = slap_schema.si_ad_objectClass;
78
79         assert(!( e == NULL || oc == NULL ));
80
81         if( e == NULL || oc == NULL ) {
82                 return 0;
83         }
84
85         if( set_flags && ( e->e_ocflags & SLAP_OC__END )) {
86                 /* flags are set, use them */
87                 return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
88         }
89
90         /*
91          * find objectClass attribute
92          */
93         attr = attr_find(e->e_attrs, objectClass);
94         if( attr == NULL ) {
95                 /* no objectClass attribute */
96 #ifdef NEW_LOGGING
97                 LDAP_LOG( OPERATION, ERR, 
98                         "is_entry_objectclass: dn(%s), oid (%s), no objectClass "
99                         "attribute.\n", e->e_dn == NULL ? "" : e->e_dn,
100                         oc->soc_oclass.oc_oid, 0 );
101 #else
102                 Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
103                         "no objectClass attribute\n",
104                         e->e_dn == NULL ? "" : e->e_dn,
105                         oc->soc_oclass.oc_oid, 0 );
106 #endif
107
108                 return 0;
109         }
110
111         for( bv=attr->a_vals; bv->bv_val; bv++ ) {
112                 ObjectClass *objectClass = oc_bvfind( bv );
113
114                 if ( !set_flags && objectClass == oc ) {
115                         return 1;
116                 }
117                 
118                 if ( objectClass != NULL ) {
119                         e->e_ocflags |= objectClass->soc_flags;
120                 }
121         }
122
123         /* mark flags as set */
124         e->e_ocflags |= SLAP_OC__END;
125
126         return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0;
127 }
128
129
130 struct oindexrec {
131         struct berval oir_name;
132         ObjectClass     *oir_oc;
133 };
134
135 static Avlnode  *oc_index = NULL;
136 static LDAP_SLIST_HEAD(OCList, slap_object_class) oc_list
137         = LDAP_SLIST_HEAD_INITIALIZER(&oc_list);
138
139 static int
140 oc_index_cmp(
141         const void *v_oir1,
142         const void *v_oir2 )
143 {
144         const struct oindexrec *oir1 = v_oir1, *oir2 = v_oir2;
145         int i = oir1->oir_name.bv_len - oir2->oir_name.bv_len;
146         if (i) return i;
147         return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
148 }
149
150 static int
151 oc_index_name_cmp(
152         const void *v_name,
153         const void *v_oir )
154 {
155         const struct berval    *name = v_name;
156         const struct oindexrec *oir  = v_oir;
157         int i = name->bv_len - oir->oir_name.bv_len;
158         if (i) return i;
159         return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
160 }
161
162 ObjectClass *
163 oc_find( const char *ocname )
164 {
165         struct berval bv;
166
167         bv.bv_val = (char *)ocname;
168         bv.bv_len = strlen( ocname );
169
170         return( oc_bvfind( &bv ) );
171 }
172
173 ObjectClass *
174 oc_bvfind( struct berval *ocname )
175 {
176         struct oindexrec        *oir;
177
178         oir = avl_find( oc_index, ocname, oc_index_name_cmp );
179
180         if ( oir != NULL ) {
181                 return( oir->oir_oc );
182         }
183
184         return( NULL );
185 }
186
187 static int
188 oc_create_required(
189     ObjectClass         *soc,
190     char                **attrs,
191         int                     *op,
192     const char          **err )
193 {
194         char            **attrs1;
195         AttributeType   *sat;
196         AttributeType   **satp;
197         int             i;
198
199         if ( attrs ) {
200                 attrs1 = attrs;
201                 while ( *attrs1 ) {
202                         sat = at_find(*attrs1);
203                         if ( !sat ) {
204                                 *err = *attrs1;
205                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
206                         }
207
208                         if( is_at_operational( sat )) (*op)++;
209
210                         if ( at_find_in_list(sat, soc->soc_required) < 0) {
211                                 if ( at_append_to_list(sat, &soc->soc_required) ) {
212                                         *err = *attrs1;
213                                         return SLAP_SCHERR_OUTOFMEM;
214                                 }
215                         }
216                         attrs1++;
217                 }
218                 /* Now delete duplicates from the allowed list */
219                 for ( satp = soc->soc_required; *satp; satp++ ) {
220                         i = at_find_in_list(*satp,soc->soc_allowed);
221                         if ( i >= 0 ) {
222                                 at_delete_from_list(i, &soc->soc_allowed);
223                         }
224                 }
225         }
226         return 0;
227 }
228
229 static int
230 oc_create_allowed(
231     ObjectClass         *soc,
232     char                **attrs,
233         int                     *op,
234     const char          **err )
235 {
236         char            **attrs1;
237         AttributeType   *sat;
238
239         if ( attrs ) {
240                 attrs1 = attrs;
241                 while ( *attrs1 ) {
242                         sat = at_find(*attrs1);
243                         if ( !sat ) {
244                                 *err = *attrs1;
245                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
246                         }
247
248                         if( is_at_operational( sat )) (*op)++;
249
250                         if ( at_find_in_list(sat, soc->soc_required) < 0 &&
251                              at_find_in_list(sat, soc->soc_allowed) < 0 ) {
252                                 if ( at_append_to_list(sat, &soc->soc_allowed) ) {
253                                         *err = *attrs1;
254                                         return SLAP_SCHERR_OUTOFMEM;
255                                 }
256                         }
257                         attrs1++;
258                 }
259         }
260         return 0;
261 }
262
263 static int
264 oc_add_sups(
265     ObjectClass         *soc,
266     char                        **sups,
267         int                     *op,
268     const char          **err )
269 {
270         int             code;
271         ObjectClass     *soc1;
272         int             nsups;
273         char    **sups1;
274         int             add_sups = 0;
275
276         if ( sups ) {
277                 if ( !soc->soc_sups ) {
278                         /* We are at the first recursive level */
279                         add_sups = 1;
280                         nsups = 1;
281                         sups1 = sups;
282                         while ( *sups1 ) {
283                                 nsups++;
284                                 sups1++;
285                         }
286                         soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
287                                           sizeof(ObjectClass *));
288                 }
289
290                 nsups = 0;
291                 sups1 = sups;
292                 while ( *sups1 ) {
293                         soc1 = oc_find(*sups1);
294                         if ( !soc1 ) {
295                                 *err = *sups1;
296                                 return SLAP_SCHERR_CLASS_NOT_FOUND;
297                         }
298
299                         /* check object class usage
300                          * abstract classes can only sup abstract classes 
301                          * structural classes can not sup auxiliary classes
302                          * auxiliary classes can not sup structural classes
303                          */
304                         if( soc->soc_kind != soc1->soc_kind
305                                 && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
306                         {
307                                 *err = *sups1;
308                                 return SLAP_SCHERR_CLASS_BAD_SUP;
309                         }
310
311                         if( soc1->soc_obsolete && !soc->soc_obsolete ) {
312                                 *err = *sups1;
313                                 return SLAP_SCHERR_CLASS_BAD_SUP;
314                         }
315
316                         if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;
317
318                         if ( add_sups ) {
319                                 soc->soc_sups[nsups] = soc1;
320                         }
321
322                         code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
323                         if ( code ) return code;
324
325                         code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
326                         if ( code ) return code;
327
328                         code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
329                         if ( code ) return code;
330
331                         nsups++;
332                         sups1++;
333                 }
334         }
335
336         return 0;
337 }
338
339 void
340 oc_destroy( void )
341 {
342         ObjectClass *o;
343
344         avl_free(oc_index, ldap_memfree);
345         while( !LDAP_SLIST_EMPTY(&oc_list) ) {
346                 o = LDAP_SLIST_FIRST(&oc_list);
347                 LDAP_SLIST_REMOVE_HEAD(&oc_list, soc_next);
348
349                 if (o->soc_sups) ldap_memfree(o->soc_sups);
350                 if (o->soc_required) ldap_memfree(o->soc_required);
351                 if (o->soc_allowed) ldap_memfree(o->soc_allowed);
352                 ldap_objectclass_free((LDAPObjectClass *)o);
353         }
354 }
355
356 static int
357 oc_insert(
358     ObjectClass         *soc,
359     const char          **err )
360 {
361         struct oindexrec        *oir;
362         char                    **names;
363
364         LDAP_SLIST_NEXT( soc, soc_next ) = NULL;
365         LDAP_SLIST_INSERT_HEAD( &oc_list, soc, soc_next );
366
367         if ( soc->soc_oid ) {
368                 oir = (struct oindexrec *)
369                         ch_calloc( 1, sizeof(struct oindexrec) );
370                 oir->oir_name.bv_val = soc->soc_oid;
371                 oir->oir_name.bv_len = strlen( soc->soc_oid );
372                 oir->oir_oc = soc;
373
374                 assert( oir->oir_name.bv_val );
375                 assert( oir->oir_oc );
376
377                 if ( avl_insert( &oc_index, (caddr_t) oir,
378                         oc_index_cmp, avl_dup_error ) )
379                 {
380                         *err = soc->soc_oid;
381                         ldap_memfree(oir);
382                         return SLAP_SCHERR_CLASS_DUP;
383                 }
384
385                 /* FIX: temporal consistency check */
386                 assert( oc_bvfind(&oir->oir_name) != NULL );
387         }
388
389         if ( (names = soc->soc_names) ) {
390                 while ( *names ) {
391                         oir = (struct oindexrec *)
392                                 ch_calloc( 1, sizeof(struct oindexrec) );
393                         oir->oir_name.bv_val = *names;
394                         oir->oir_name.bv_len = strlen( *names );
395                         oir->oir_oc = soc;
396
397                         assert( oir->oir_name.bv_val );
398                         assert( oir->oir_oc );
399
400                         if ( avl_insert( &oc_index, (caddr_t) oir,
401                                 oc_index_cmp, avl_dup_error ) )
402                         {
403                                 *err = *names;
404                                 ldap_memfree(oir);
405                                 return SLAP_SCHERR_CLASS_DUP;
406                         }
407
408                         /* FIX: temporal consistency check */
409                         assert( oc_bvfind(&oir->oir_name) != NULL );
410
411                         names++;
412                 }
413         }
414
415         return 0;
416 }
417
418 int
419 oc_add(
420     LDAPObjectClass     *oc,
421         int user,
422     const char          **err )
423 {
424         ObjectClass     *soc;
425         int             code;
426         int             op = 0;
427
428         if ( oc->oc_names != NULL ) {
429                 int i;
430
431                 for( i=0; oc->oc_names[i]; i++ ) {
432                         if( !slap_valid_descr( oc->oc_names[i] ) ) {
433                                 return SLAP_SCHERR_BAD_DESCR;
434                         }
435                 }
436         }
437
438         if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
439                 /* Expand OID macros */
440                 char *oid = oidm_find( oc->oc_oid );
441                 if ( !oid ) {
442                         *err = oc->oc_oid;
443                         return SLAP_SCHERR_OIDM;
444                 }
445                 if ( oid != oc->oc_oid ) {
446                         ldap_memfree( oc->oc_oid );
447                         oc->oc_oid = oid;
448                 }
449         }
450
451         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
452         AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
453
454         if( oc->oc_names != NULL ) {
455                 soc->soc_cname.bv_val = soc->soc_names[0];
456         } else {
457                 soc->soc_cname.bv_val = soc->soc_oid;
458         }
459         soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
460
461         if( soc->soc_sup_oids == NULL &&
462                 soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
463         {
464                 /* structural object classes implicitly inherit from 'top' */
465                 static char *top_oids[] = { SLAPD_TOP_OID, NULL };
466                 code = oc_add_sups( soc, top_oids, &op, err );
467         } else {
468                 code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
469         }
470
471         if ( code != 0 ) return code;
472         if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP;
473
474         code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
475         if ( code != 0 ) return code;
476
477         code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
478         if ( code != 0 ) return code;
479
480         if( user && op ) return SLAP_SCHERR_CLASS_BAD_USAGE;
481
482         code = oc_insert(soc,err);
483         return code;
484 }
485
486 int
487 oc_schema_info( Entry *e )
488 {
489         AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
490         ObjectClass     *oc;
491         struct berval   val;
492         struct berval   nval;
493
494         LDAP_SLIST_FOREACH( oc, &oc_list, soc_next ) {
495                 if( oc->soc_flags & SLAP_OC_HIDE ) continue;
496
497                 if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
498                         return -1;
499                 }
500
501                 nval = oc->soc_cname;
502
503 #if 0
504                 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s (%s)\n",
505                (long) val.bv_len, val.bv_val, nval.bv_val );
506 #endif
507
508                 if( attr_merge_one( e, ad_objectClasses, &val, &nval ) ) {
509                         return -1;
510                 }
511                 ldap_memfree( val.bv_val );
512         }
513         return 0;
514 }