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