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