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