]> git.sur5r.net Git - openldap/blob - servers/slapd/oc.c
now I remember why I introduced the 'has_ldapinfo_dn_ru' flag
[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-2004 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 1
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)
147                 return i;
148         return strcasecmp( oir1->oir_name.bv_val, oir2->oir_name.bv_val );
149 }
150
151 static int
152 oc_index_name_cmp(
153         const void *v_name,
154         const void *v_oir )
155 {
156         const struct berval    *name = v_name;
157         const struct oindexrec *oir  = v_oir;
158         int i = name->bv_len - oir->oir_name.bv_len;
159         if (i)
160                 return i;
161         return strncasecmp( name->bv_val, oir->oir_name.bv_val, name->bv_len );
162 }
163
164 ObjectClass *
165 oc_find( const char *ocname )
166 {
167         struct berval bv;
168
169         bv.bv_val = (char *)ocname;
170         bv.bv_len = strlen( ocname );
171
172         return( oc_bvfind( &bv ) );
173 }
174
175 ObjectClass *
176 oc_bvfind( struct berval *ocname )
177 {
178         struct oindexrec        *oir;
179
180         oir = avl_find( oc_index, ocname, oc_index_name_cmp );
181
182         if ( oir != NULL ) {
183                 return( oir->oir_oc );
184         }
185
186         return( NULL );
187 }
188
189 static int
190 oc_create_required(
191     ObjectClass         *soc,
192     char                **attrs,
193         int                     *op,
194     const char          **err )
195 {
196         char            **attrs1;
197         AttributeType   *sat;
198         AttributeType   **satp;
199         int             i;
200
201         if ( attrs ) {
202                 attrs1 = attrs;
203                 while ( *attrs1 ) {
204                         sat = at_find(*attrs1);
205                         if ( !sat ) {
206                                 *err = *attrs1;
207                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
208                         }
209
210                         if( is_at_operational( sat )) (*op)++;
211
212                         if ( at_find_in_list(sat, soc->soc_required) < 0) {
213                                 if ( at_append_to_list(sat, &soc->soc_required) ) {
214                                         *err = *attrs1;
215                                         return SLAP_SCHERR_OUTOFMEM;
216                                 }
217                         }
218                         attrs1++;
219                 }
220                 /* Now delete duplicates from the allowed list */
221                 for ( satp = soc->soc_required; *satp; satp++ ) {
222                         i = at_find_in_list(*satp,soc->soc_allowed);
223                         if ( i >= 0 ) {
224                                 at_delete_from_list(i, &soc->soc_allowed);
225                         }
226                 }
227         }
228         return 0;
229 }
230
231 static int
232 oc_create_allowed(
233     ObjectClass         *soc,
234     char                **attrs,
235         int                     *op,
236     const char          **err )
237 {
238         char            **attrs1;
239         AttributeType   *sat;
240
241         if ( attrs ) {
242                 attrs1 = attrs;
243                 while ( *attrs1 ) {
244                         sat = at_find(*attrs1);
245                         if ( !sat ) {
246                                 *err = *attrs1;
247                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
248                         }
249
250                         if( is_at_operational( sat )) (*op)++;
251
252                         if ( at_find_in_list(sat, soc->soc_required) < 0 &&
253                              at_find_in_list(sat, soc->soc_allowed) < 0 ) {
254                                 if ( at_append_to_list(sat, &soc->soc_allowed) ) {
255                                         *err = *attrs1;
256                                         return SLAP_SCHERR_OUTOFMEM;
257                                 }
258                         }
259                         attrs1++;
260                 }
261         }
262         return 0;
263 }
264
265 static int
266 oc_add_sups(
267     ObjectClass         *soc,
268     char                        **sups,
269         int                     *op,
270     const char          **err )
271 {
272         int             code;
273         ObjectClass     *soc1;
274         int             nsups;
275         char    **sups1;
276         int             add_sups = 0;
277
278         if ( sups ) {
279                 if ( !soc->soc_sups ) {
280                         /* We are at the first recursive level */
281                         add_sups = 1;
282                         nsups = 1;
283                         sups1 = sups;
284                         while ( *sups1 ) {
285                                 nsups++;
286                                 sups1++;
287                         }
288                         soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
289                                           sizeof(ObjectClass *));
290                 }
291
292                 nsups = 0;
293                 sups1 = sups;
294                 while ( *sups1 ) {
295                         soc1 = oc_find(*sups1);
296                         if ( !soc1 ) {
297                                 *err = *sups1;
298                                 return SLAP_SCHERR_CLASS_NOT_FOUND;
299                         }
300
301                         /* check object class usage
302                          * abstract classes can only sup abstract classes 
303                          * structural classes can not sup auxiliary classes
304                          * auxiliary classes can not sup structural classes
305                          */
306                         if( soc->soc_kind != soc1->soc_kind
307                                 && soc1->soc_kind != LDAP_SCHEMA_ABSTRACT )
308                         {
309                                 *err = *sups1;
310                                 return SLAP_SCHERR_CLASS_BAD_SUP;
311                         }
312
313                         if( soc1->soc_obsolete && !soc->soc_obsolete ) {
314                                 *err = *sups1;
315                                 return SLAP_SCHERR_CLASS_BAD_SUP;
316                         }
317
318                         if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++;
319
320                         if ( add_sups ) {
321                                 soc->soc_sups[nsups] = soc1;
322                         }
323
324                         code = oc_add_sups( soc, soc1->soc_sup_oids, op, err );
325                         if ( code ) return code;
326
327                         code = oc_create_required( soc, soc1->soc_at_oids_must, op, err );
328                         if ( code ) return code;
329
330                         code = oc_create_allowed( soc, soc1->soc_at_oids_may, op, err );
331                         if ( code ) return code;
332
333                         nsups++;
334                         sups1++;
335                 }
336         }
337
338         return 0;
339 }
340
341 void
342 oc_destroy( void )
343 {
344         ObjectClass *o;
345
346         avl_free(oc_index, ldap_memfree);
347         while( !LDAP_SLIST_EMPTY(&oc_list) ) {
348                 o = LDAP_SLIST_FIRST(&oc_list);
349                 LDAP_SLIST_REMOVE_HEAD(&oc_list, soc_next);
350
351                 if (o->soc_sups) ldap_memfree(o->soc_sups);
352                 if (o->soc_required) ldap_memfree(o->soc_required);
353                 if (o->soc_allowed) ldap_memfree(o->soc_allowed);
354                 ldap_objectclass_free((LDAPObjectClass *)o);
355         }
356 }
357
358 static int
359 oc_insert(
360     ObjectClass         *soc,
361     const char          **err
362 )
363 {
364         struct oindexrec        *oir;
365         char                    **names;
366
367         LDAP_SLIST_NEXT( soc, soc_next ) = NULL;
368         LDAP_SLIST_INSERT_HEAD( &oc_list, soc, soc_next );
369
370         if ( soc->soc_oid ) {
371                 oir = (struct oindexrec *)
372                         ch_calloc( 1, sizeof(struct oindexrec) );
373                 oir->oir_name.bv_val = soc->soc_oid;
374                 oir->oir_name.bv_len = strlen( soc->soc_oid );
375                 oir->oir_oc = soc;
376
377                 assert( oir->oir_name.bv_val );
378                 assert( oir->oir_oc );
379
380                 if ( avl_insert( &oc_index, (caddr_t) oir,
381                                  oc_index_cmp, avl_dup_error ) )
382                 {
383                         *err = soc->soc_oid;
384                         ldap_memfree(oir);
385                         return SLAP_SCHERR_CLASS_DUP;
386                 }
387
388                 /* FIX: temporal consistency check */
389                 assert( oc_bvfind(&oir->oir_name) != NULL );
390         }
391
392         if ( (names = soc->soc_names) ) {
393                 while ( *names ) {
394                         oir = (struct oindexrec *)
395                                 ch_calloc( 1, sizeof(struct oindexrec) );
396                         oir->oir_name.bv_val = *names;
397                         oir->oir_name.bv_len = strlen( *names );
398                         oir->oir_oc = soc;
399
400                         assert( oir->oir_name.bv_val );
401                         assert( oir->oir_oc );
402
403                         if ( avl_insert( &oc_index, (caddr_t) oir,
404                                          oc_index_cmp, avl_dup_error ) )
405                         {
406                                 *err = *names;
407                                 ldap_memfree(oir);
408                                 return SLAP_SCHERR_CLASS_DUP;
409                         }
410
411                         /* FIX: temporal consistency check */
412                         assert( oc_bvfind(&oir->oir_name) != NULL );
413
414                         names++;
415                 }
416         }
417
418         return 0;
419 }
420
421 int
422 oc_add(
423     LDAPObjectClass     *oc,
424         int user,
425     const char          **err
426 )
427 {
428         ObjectClass     *soc;
429         int             code;
430         int             op = 0;
431
432         if ( oc->oc_names != NULL ) {
433                 int i;
434
435                 for( i=0; oc->oc_names[i]; i++ ) {
436                         if( !slap_valid_descr( oc->oc_names[i] ) ) {
437                                 return SLAP_SCHERR_BAD_DESCR;
438                         }
439                 }
440         }
441
442         if ( !OID_LEADCHAR( oc->oc_oid[0] )) {
443                 /* Expand OID macros */
444                 char *oid = oidm_find( oc->oc_oid );
445                 if ( !oid ) {
446                         *err = oc->oc_oid;
447                         return SLAP_SCHERR_OIDM;
448                 }
449                 if ( oid != oc->oc_oid ) {
450                         ldap_memfree( oc->oc_oid );
451                         oc->oc_oid = oid;
452                 }
453         }
454
455         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
456         AC_MEMCPY( &soc->soc_oclass, oc, sizeof(LDAPObjectClass) );
457
458         if( oc->oc_names != NULL ) {
459                 soc->soc_cname.bv_val = soc->soc_names[0];
460         } else {
461                 soc->soc_cname.bv_val = soc->soc_oid;
462         }
463         soc->soc_cname.bv_len = strlen( soc->soc_cname.bv_val );
464
465         if( soc->soc_sup_oids == NULL &&
466                 soc->soc_kind == LDAP_SCHEMA_STRUCTURAL )
467         {
468                 /* structural object classes implicitly inherit from 'top' */
469                 static char *top_oids[] = { SLAPD_TOP_OID, NULL };
470                 code = oc_add_sups( soc, top_oids, &op, err );
471         } else {
472                 code = oc_add_sups( soc, soc->soc_sup_oids, &op, err );
473         }
474
475         if ( code != 0 ) return code;
476
477         code = oc_create_required( soc, soc->soc_at_oids_must, &op, err );
478         if ( code != 0 ) return code;
479
480         code = oc_create_allowed( soc, soc->soc_at_oids_may, &op, err );
481         if ( code != 0 ) return code;
482
483         if( user && op ) return SLAP_SCHERR_CLASS_BAD_SUP;
484
485         code = oc_insert(soc,err);
486         return code;
487 }
488
489 int
490 oc_schema_info( Entry *e )
491 {
492         AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
493         ObjectClass     *oc;
494         struct berval   val;
495         struct berval   nval;
496
497         LDAP_SLIST_FOREACH( oc, &oc_list, soc_next ) {
498                 if( oc->soc_flags & SLAP_OC_HIDE ) continue;
499
500                 if ( ldap_objectclass2bv( &oc->soc_oclass, &val ) == NULL ) {
501                         return -1;
502                 }
503
504 #if 0
505                 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
506                (long) val.bv_len, val.bv_val, 0 );
507 #endif
508                 nval.bv_val = oc->soc_oid;
509                 nval.bv_len = strlen(oc->soc_oid);
510
511                 if( attr_merge_one( e, ad_objectClasses, &val, &nval ) )
512                 {
513                         return -1;
514                 }
515                 ldap_memfree( val.bv_val );
516         }
517         return 0;
518 }