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