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