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