]> git.sur5r.net Git - openldap/blob - servers/slapd/oc.c
Updated for schemas.
[openldap] / servers / slapd / oc.c
1 /* oc.c - object class routines */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 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 *sub,
21         ObjectClass *sup )
22 {
23         int i;
24
25         if( sup == sub ) {
26                 return 1;
27         }
28
29         if( sup->soc_sups == NULL ) {
30                 return 0;
31         }
32
33         for( i=0; sup->soc_sups[i] != NULL; i++ ) {
34                 if( is_object_subclass( sup->soc_sups[i], sup ) ) {
35                         return 1;
36                 }
37         }
38
39         return 0;
40 }
41
42 int is_entry_objectclass(
43         Entry*  e,
44 #ifdef SLAPD_SCHEMA_NOT_COMPAT
45         ObjectClass *oc
46 #else
47         const char*     oc
48 #endif
49 )
50 {
51         Attribute *attr;
52 #ifdef SLAPD_SCHEMA_NOT_COMPAT
53         int i;
54         AttributeDescription *objectClass = slap_schema.si_ad_objectClass;
55         assert(!( e == NULL || oc == NULL ));
56 #else
57         struct berval bv;
58         static const char *objectClass = "objectclass";
59         assert(!( e == NULL || oc == NULL || *oc == '\0' ));
60 #endif
61
62         if( e == NULL || oc == NULL
63 #ifndef SLAPD_SCHEMA_NOT_COMPAT
64                 || *oc == '\0'
65 #endif
66         ) {
67                 return 0;
68         }
69
70         /*
71          * find objectClass attribute
72          */
73         attr = attr_find(e->e_attrs, objectClass);
74
75         if( attr == NULL ) {
76                 /* no objectClass attribute */
77                 Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") "
78                         "no objectClass attribute\n",
79                         e->e_dn == NULL ? "" : e->e_dn, oc, 0 );
80
81                 return 0;
82         }
83
84 #ifdef SLAPD_SCHEMA_NOT_COMPAT
85         for( i=0; attr->a_vals[i]; i++ ) {
86                 ObjectClass *objectClass = oc_find( attr->a_vals[i]->bv_val );
87
88                 if( objectClass == oc ) {
89                         return 1;
90                 }
91         }
92
93         return 0;
94
95 #else
96         bv.bv_val = (char *) oc;
97         bv.bv_len = strlen( bv.bv_val );
98
99         if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
100                 /* entry is not of this objectclass */
101                 return 0;
102         }
103
104         return 1;
105 #endif
106 }
107
108
109 #ifndef SLAPD_SCHEMA_NOT_COMPAT
110         /* these shouldn't be hardcoded */
111
112 static char *oc_op_usermod_attrs[] = {
113         /*
114          * these are operational attributes which are
115          * not defined as NO-USER_MODIFICATION and
116          * which slapd supports modification of.
117          *
118          * Currently none.
119          * Likely candidate, "OpenLDAPaci"
120          */
121         NULL
122 };
123
124 static char *oc_op_attrs[] = {
125         /*
126          * these are operational attributes 
127          * most could be user modifiable
128          */
129         "objectClasses",
130         "attributeTypes",
131         "matchingRules",
132         "matchingRuleUse",
133         "dITStructureRules",
134         "dITContentRules",
135         "nameForms",
136         "ldapSyntaxes",
137         "namingContexts",
138         "supportedExtension",
139         "supportedControl",
140         "supportedSASLMechanisms",
141         "supportedLDAPversion",
142         "subschemaSubentry",            /* NO USER MOD */
143         NULL
144
145 };
146
147 /* this list should be extensible  */
148 static char *oc_op_no_usermod_attrs[] = {
149         /*
150          * Operational and 'no user modification' attributes
151          * which are STORED in the directory server.
152          */
153
154         /* RFC2252, 3.2.1 */
155         "creatorsName",
156         "createTimestamp",
157         "modifiersName",
158         "modifyTimestamp",
159
160         NULL
161 };
162
163
164 /*
165  * check to see if attribute is 'operational' or not.
166  */
167 int
168 oc_check_op_attr( const char *type )
169 {
170 #ifndef SLAPD_SCHEMA_NOT_COMPAT
171         return charray_inlist( oc_op_attrs, type )
172                 || charray_inlist( oc_op_usermod_attrs, type )
173                 || charray_inlist( oc_op_no_usermod_attrs, type );
174 #else
175         AttributeType *at = at_find( type );
176
177         if( at == NULL ) return 0;
178
179         return at->sat_usage != LDAP_SCHEMA_USER_APPLICATIONS;
180 #endif
181 }
182
183 /*
184  * check to see if attribute can be user modified or not.
185  */
186 int
187 oc_check_op_usermod_attr( const char *type )
188 {
189 #ifndef SLAPD_SCHEMA_NOT_COMPAT
190         return charray_inlist( oc_op_usermod_attrs, type );
191 #else
192         /* not (yet) in schema */
193         return 0;
194 #endif
195 }
196
197 /*
198  * check to see if attribute is 'no user modification' or not.
199  */
200 int
201 oc_check_op_no_usermod_attr( const char *type )
202 {
203 #ifndef SLAPD_SCHEMA_NOT_COMPAT
204         return charray_inlist( oc_op_no_usermod_attrs, type );
205 #else
206         AttributeType *at = at_find( type );
207
208         if( at == NULL ) return 0;
209
210         return at->sat_no_user_mod;
211 #endif
212 }
213 #endif
214
215
216 struct oindexrec {
217         char            *oir_name;
218         ObjectClass     *oir_oc;
219 };
220
221 static Avlnode  *oc_index = NULL;
222 static ObjectClass *oc_list = NULL;
223
224 static int
225 oc_index_cmp(
226     struct oindexrec    *oir1,
227     struct oindexrec    *oir2
228 )
229 {
230         assert( oir1->oir_name );
231         assert( oir1->oir_oc );
232         assert( oir2->oir_name );
233         assert( oir2->oir_oc );
234
235         return (strcasecmp( oir1->oir_name, oir2->oir_name ));
236 }
237
238 static int
239 oc_index_name_cmp(
240     char                *name,
241     struct oindexrec    *oir
242 )
243 {
244         assert( oir->oir_name );
245         assert( oir->oir_oc );
246
247         return (strcasecmp( name, oir->oir_name ));
248 }
249
250 ObjectClass *
251 oc_find( const char *ocname )
252 {
253         struct oindexrec        *oir;
254
255         oir = (struct oindexrec *) avl_find( oc_index, ocname,
256             (AVL_CMP) oc_index_name_cmp );
257
258         if ( oir != NULL ) {
259                 assert( oir->oir_name );
260                 assert( oir->oir_oc );
261
262                 return( oir->oir_oc );
263         }
264
265         return( NULL );
266 }
267
268 static int
269 oc_create_required(
270     ObjectClass         *soc,
271     char                **attrs,
272     const char          **err
273 )
274 {
275         char            **attrs1;
276         AttributeType   *sat;
277         AttributeType   **satp;
278         int             i;
279
280         if ( attrs ) {
281                 attrs1 = attrs;
282                 while ( *attrs1 ) {
283                         sat = at_find(*attrs1);
284                         if ( !sat ) {
285                                 *err = *attrs1;
286                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
287                         }
288                         if ( at_find_in_list(sat, soc->soc_required) < 0) {
289                                 if ( at_append_to_list(sat, &soc->soc_required) ) {
290                                         *err = *attrs1;
291                                         return SLAP_SCHERR_OUTOFMEM;
292                                 }
293                         }
294                         attrs1++;
295                 }
296                 /* Now delete duplicates from the allowed list */
297                 for ( satp = soc->soc_required; *satp; satp++ ) {
298                         i = at_find_in_list(*satp,soc->soc_allowed);
299                         if ( i >= 0 ) {
300                                 at_delete_from_list(i, &soc->soc_allowed);
301                         }
302                 }
303         }
304         return 0;
305 }
306
307 static int
308 oc_create_allowed(
309     ObjectClass         *soc,
310     char                **attrs,
311     const char          **err
312 )
313 {
314         char            **attrs1;
315         AttributeType   *sat;
316
317         if ( attrs ) {
318                 attrs1 = attrs;
319                 while ( *attrs1 ) {
320                         sat = at_find(*attrs1);
321                         if ( !sat ) {
322                                 *err = *attrs1;
323                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
324                         }
325                         if ( at_find_in_list(sat, soc->soc_required) < 0 &&
326                              at_find_in_list(sat, soc->soc_allowed) < 0 ) {
327                                 if ( at_append_to_list(sat, &soc->soc_allowed) ) {
328                                         *err = *attrs1;
329                                         return SLAP_SCHERR_OUTOFMEM;
330                                 }
331                         }
332                         attrs1++;
333                 }
334         }
335         return 0;
336 }
337
338 static int
339 oc_add_sups(
340     ObjectClass         *soc,
341     char                **sups,
342     const char          **err
343 )
344 {
345         int             code;
346         ObjectClass     *soc1;
347         int             nsups;
348         char            **sups1;
349         int             add_sups = 0;
350
351         if ( sups ) {
352                 if ( !soc->soc_sups ) {
353                         /* We are at the first recursive level */
354                         add_sups = 1;
355                         nsups = 0;
356                         sups1 = sups;
357                         while ( *sups1 ) {
358                                 nsups++;
359                                 sups1++;
360                         }
361                         nsups++;
362                         soc->soc_sups = (ObjectClass **)ch_calloc(nsups,
363                                           sizeof(ObjectClass *));
364                 }
365                 nsups = 0;
366                 sups1 = sups;
367                 while ( *sups1 ) {
368                         soc1 = oc_find(*sups1);
369                         if ( !soc1 ) {
370                                 *err = *sups1;
371                                 return SLAP_SCHERR_CLASS_NOT_FOUND;
372                         }
373
374                         if ( add_sups )
375                                 soc->soc_sups[nsups] = soc1;
376
377                         code = oc_add_sups(soc,soc1->soc_sup_oids, err);
378                         if ( code )
379                                 return code;
380
381                         code = oc_create_required(soc,soc1->soc_at_oids_must,err);
382                         if ( code )
383                                 return code;
384                         code = oc_create_allowed(soc,soc1->soc_at_oids_may,err);
385                         if ( code )
386                                 return code;
387
388                         nsups++;
389                         sups1++;
390                 }
391         }
392         return 0;
393 }
394
395 static int
396 oc_insert(
397     ObjectClass         *soc,
398     const char          **err
399 )
400 {
401         ObjectClass     **ocp;
402         struct oindexrec        *oir;
403         char                    **names;
404
405         ocp = &oc_list;
406         while ( *ocp != NULL ) {
407                 ocp = &(*ocp)->soc_next;
408         }
409         *ocp = soc;
410
411         if ( soc->soc_oid ) {
412                 oir = (struct oindexrec *)
413                         ch_calloc( 1, sizeof(struct oindexrec) );
414                 oir->oir_name = soc->soc_oid;
415                 oir->oir_oc = soc;
416
417                 assert( oir->oir_name );
418                 assert( oir->oir_oc );
419
420                 if ( avl_insert( &oc_index, (caddr_t) oir,
421                                  (AVL_CMP) oc_index_cmp,
422                                  (AVL_DUP) avl_dup_error ) )
423                 {
424                         *err = soc->soc_oid;
425                         ldap_memfree(oir->oir_name);
426                         ldap_memfree(oir);
427                         return SLAP_SCHERR_DUP_CLASS;
428                 }
429
430                 /* FIX: temporal consistency check */
431                 assert( oc_find(oir->oir_name) != NULL );
432         }
433
434         if ( (names = soc->soc_names) ) {
435                 while ( *names ) {
436                         oir = (struct oindexrec *)
437                                 ch_calloc( 1, sizeof(struct oindexrec) );
438                         oir->oir_name = ch_strdup(*names);
439                         oir->oir_oc = soc;
440
441                         assert( oir->oir_name );
442                         assert( oir->oir_oc );
443
444                         if ( avl_insert( &oc_index, (caddr_t) oir,
445                                          (AVL_CMP) oc_index_cmp,
446                                          (AVL_DUP) avl_dup_error ) )
447                         {
448                                 *err = *names;
449                                 ldap_memfree(oir->oir_name);
450                                 ldap_memfree(oir);
451                                 return SLAP_SCHERR_DUP_CLASS;
452                         }
453
454                         /* FIX: temporal consistency check */
455                         assert( oc_find(oir->oir_name) != NULL );
456
457                         names++;
458                 }
459         }
460
461         return 0;
462 }
463
464 int
465 oc_add(
466     LDAP_OBJECT_CLASS   *oc,
467     const char          **err
468 )
469 {
470         ObjectClass     *soc;
471         int             code;
472
473         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
474         memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
475         if ( (code = oc_add_sups(soc,soc->soc_sup_oids,err)) != 0 )
476                 return code;
477         if ( (code = oc_create_required(soc,soc->soc_at_oids_must,err)) != 0 )
478                 return code;
479         if ( (code = oc_create_allowed(soc,soc->soc_at_oids_may,err)) != 0 )
480                 return code;
481         code = oc_insert(soc,err);
482         return code;
483 }
484
485 #ifdef LDAP_DEBUG
486
487 static void
488 oc_print( ObjectClass *oc )
489 {
490         int     i;
491         const char *mid;
492
493         printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
494         if ( oc->soc_required != NULL ) {
495                 mid = "\trequires ";
496                 for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
497                         printf( "%s%s", mid,
498                                 ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
499                 printf( "\n" );
500         }
501         if ( oc->soc_allowed != NULL ) {
502                 mid = "\tallows ";
503                 for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
504                         printf( "%s%s", mid,
505                                 ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
506                 printf( "\n" );
507         }
508 }
509
510 #endif
511
512
513 #if defined( SLAPD_SCHEMA_DN )
514
515 int
516 oc_schema_info( Entry *e )
517 {
518         struct berval   val;
519         struct berval   *vals[2];
520         ObjectClass     *oc;
521
522 #ifdef SLAPD_SCHEMA_NOT_COMPAT
523         AttributeDescription *ad_objectClasses = slap_schema.si_ad_objectClasses;
524 #else
525         char *ad_objectClasses = "objectClasses";
526 #endif
527
528         vals[0] = &val;
529         vals[1] = NULL;
530
531         for ( oc = oc_list; oc; oc = oc->soc_next ) {
532                 val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
533                 if ( val.bv_val == NULL ) {
534                         return -1;
535                 }
536                 val.bv_len = strlen( val.bv_val );
537 #if 0
538                 Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
539                (long) val.bv_len, val.bv_val, 0 );
540 #endif
541                 attr_merge( e, ad_objectClasses, vals );
542                 ldap_memfree( val.bv_val );
543         }
544         return 0;
545 }
546
547 #endif