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