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