]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_check.c
Move experimental Back-BDB2 to Attic
[openldap] / servers / slapd / schema_check.c
1 /* schema_check.c - routines to enforce schema definitions */
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 #ifndef SLAPD_SCHEMA_NOT_COMPAT
20 static int              oc_check_allowed(char *type, struct berval **oclist);
21 #endif
22 static char *   oc_check_required(Entry *e, struct berval *ocname);
23
24 /*
25  * entry_schema_check - check that entry e conforms to the schema required
26  * by its object class(es).
27  *
28  * returns 0 if so, non-zero otherwise.
29  */
30
31 int
32 entry_schema_check( 
33         Entry *e, Attribute *oldattrs, const char** text )
34 {
35         Attribute       *a, *aoc;
36         ObjectClass *oc;
37         int             i;
38         int             ret;
39 #ifdef SLAPD_SCHEMA_NOT_COMPAT
40         AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
41 #else
42         static const char *ad_objectClass = "objectclass";
43 #endif
44         int extensible = 0;
45
46         if( !global_schemacheck ) return LDAP_SUCCESS;
47
48         /* find the object class attribute - could error out here */
49         if ( (aoc = attr_find( e->e_attrs, ad_objectClass )) == NULL ) {
50                 Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
51                     e->e_dn, 0, 0 );
52                 *text = "no objectclass attribute";
53                 return oldattrs != NULL
54                         ? LDAP_OBJECT_CLASS_VIOLATION
55                         : LDAP_NO_OBJECT_CLASS_MODS;
56         }
57
58         ret = LDAP_SUCCESS;
59
60         /* check that the entry has required attrs for each oc */
61         for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
62                 if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
63                         Debug( LDAP_DEBUG_ANY,
64                                 "entry_check_schema(%s): objectclass \"%s\" not defined\n",
65                                 e->e_dn, aoc->a_vals[i]->bv_val, 0 );
66
67                 } else {
68                         char *s = oc_check_required( e, aoc->a_vals[i] );
69
70                         if (s != NULL) {
71                                 Debug( LDAP_DEBUG_ANY,
72                                         "Entry (%s), oc \"%s\" requires attr \"%s\"\n",
73                                         e->e_dn, aoc->a_vals[i]->bv_val, s );
74                                 *text = "missing required attribute";
75                                 ret = LDAP_OBJECT_CLASS_VIOLATION;
76                                 break;
77                         }
78
79 #ifdef SLAPD_SCHEMA_NOT_COMPAT
80                         if( oc == slap_schema.si_oc_extensibleObject )
81 #else
82                         if( !strcmp( aoc->a_vals[i]->bv_val, "extensibleObject" ) == 0 )
83 #endif
84                         {
85                                 extensible=1;
86                         }
87
88                 }
89         }
90
91         if ( ret != LDAP_SUCCESS ) {
92             return ret;
93         }
94
95         if( extensible ) {
96                 return LDAP_SUCCESS;
97         }
98
99         /* check that each attr in the entry is allowed by some oc */
100         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
101 #ifdef SLAPD_SCHEMA_NOT_COMPAT
102                 ret = oc_check_allowed( a->a_desc->ad_type, aoc->a_vals );
103 #else
104                 ret = oc_check_allowed( a->a_type, aoc->a_vals );
105 #endif
106                 if ( ret != 0 ) {
107 #ifdef SLAPD_SCHEMA_NOT_COMPAT
108                         char *type = a->a_desc->ad_cname->bv_val;
109 #else
110                         char *type = a->a_type;
111 #endif
112                         Debug( LDAP_DEBUG_ANY,
113                             "Entry (%s), attr \"%s\" not allowed\n",
114                             e->e_dn, type, 0 );
115                         *text = "attribute not allowed";
116                         break;
117                 }
118         }
119
120         return( ret );
121 }
122
123 static char *
124 oc_check_required( Entry *e, struct berval *ocname )
125 {
126         ObjectClass     *oc;
127         AttributeType   *at;
128         int             i;
129         Attribute       *a;
130
131         Debug( LDAP_DEBUG_TRACE,
132                "oc_check_required entry (%s), objectclass \"%s\"\n",
133                e->e_dn, ocname->bv_val, 0 );
134
135         /* find global oc defn. it we don't know about it assume it's ok */
136         if ( (oc = oc_find( ocname->bv_val )) == NULL ) {
137                 return NULL;
138         }
139
140         /* check for empty oc_required */
141         if(oc->soc_required == NULL) {
142                 return NULL;
143         }
144
145         /* for each required attribute */
146         for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
147                 at = oc->soc_required[i];
148                 /* see if it's in the entry */
149                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
150 #ifdef SLAPD_SCHEMA_NOT_COMPAT
151                         if( a->a_desc->ad_type == at ) {
152                                 break;
153                         }
154 #else
155                         char            **pp;
156
157                         if ( at->sat_oid &&
158                              strcmp( a->a_type, at->sat_oid ) == 0 ) {
159                                 break;
160                         }
161                         pp = at->sat_names;
162                         if ( pp  == NULL ) {
163                                 /* Empty name list => not found */
164                                 a = NULL;
165                                 break;
166                         }
167                         while ( *pp ) {
168                                 if ( strcasecmp( a->a_type, *pp ) == 0 ) {
169                                         break;
170                                 }
171                                 pp++;
172                         }
173                         if ( *pp ) {
174                                 break;
175                         }
176 #endif
177                 }
178                 /* not there => schema violation */
179                 if ( a == NULL ) {
180 #ifdef SLAPD_SCHEMA_NOT_COMPAT
181                         return at->sat_cname;
182 #else
183                         if ( at->sat_names && at->sat_names[0] ) {
184                                 return at->sat_names[0];
185                         } else {
186                                 return at->sat_oid;
187                         }
188 #endif
189                 }
190         }
191
192         return( NULL );
193 }
194
195 #ifndef SLAPD_SCHEMA_NOT_COMPAT
196 static
197 #endif
198 int oc_check_allowed(
199 #ifdef SLAPD_SCHEMA_NOT_COMPAT
200         AttributeType *at,
201 #else
202         char *type,
203 #endif
204         struct berval **ocl )
205 {
206         ObjectClass     *oc;
207         int             i, j;
208
209 #ifdef SLAPD_SCHEMA_NOT_COMPAT
210         Debug( LDAP_DEBUG_TRACE,
211                 "oc_check_allowed type \"%s\"\n",
212                 at->sat_cname, 0, 0 );
213
214         /* always allow objectclass attribute */
215         if ( strcasecmp( at->sat_cname, "objectclass" ) == 0 ) {
216                 return LDAP_SUCCESS;
217         }
218
219 #else
220         AttributeType   *at;
221         char            **pp;
222         char            *p;
223         char            *t;
224
225         Debug( LDAP_DEBUG_TRACE,
226                "oc_check_allowed type \"%s\"\n", type, 0, 0 );
227
228         /* always allow objectclass attribute */
229         if ( strcasecmp( type, "objectclass" ) == 0 ) {
230                 return LDAP_SUCCESS;
231         }
232 #endif
233
234 #ifdef SLAPD_SCHEMA_NOT_COMPAT
235         /*
236          * All operational attributions are allowed by schema rules.
237          */
238         if( is_at_operational(at) ) {
239                 return LDAP_SUCCESS;
240         }
241 #else
242         /*
243          * The "type" we have received is actually an AttributeDescription.
244          * Let's find out the corresponding type.
245          */
246         p = strchr( type, ';' );
247         if ( p ) {
248                 t = ch_malloc( p-type+1 );
249                 strncpy( t, type, p-type );
250                 t[p-type] = '\0';
251                 Debug( LDAP_DEBUG_TRACE,
252                        "oc_check_allowed type \"%s\" from \"%s\"\n",
253                        t, type, 0 );
254
255         } else
256         {
257                 t = type;
258         }
259
260         /*
261          * All operational attributions are allowed by schema rules.
262          */
263         if ( oc_check_op_attr( t ) ) {
264                 return LDAP_SUCCESS;
265         }
266 #endif
267
268         /* check that the type appears as req or opt in at least one oc */
269         for ( i = 0; ocl[i] != NULL; i++ ) {
270                 /* if we know about the oc */
271                 if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
272                         /* does it require the type? */
273                         for ( j = 0; oc->soc_required != NULL && 
274                                 oc->soc_required[j] != NULL; j++ )
275                         {
276 #ifdef SLAPD_SCHEMA_NOT_COMPAT
277                                 if( at == oc->soc_required[j] ) {
278                                         return LDAP_SUCCESS;
279                                 }
280 #else
281                                 at = oc->soc_required[j];
282                                 if ( at->sat_oid &&
283                                      strcmp(at->sat_oid, t ) == 0 ) {
284                                         if ( t != type )
285                                                 ldap_memfree( t );
286                                         return LDAP_SUCCESS;
287                                 }
288                                 pp = at->sat_names;
289                                 if ( pp == NULL )
290                                         continue;
291                                 while ( *pp ) {
292                                         if ( strcasecmp( *pp, t ) == 0 ) {
293                                                 if ( t != type )
294                                                         ldap_memfree( t );
295                                                 return LDAP_SUCCESS;
296                                         }
297                                         pp++;
298                                 }
299 #endif
300                         }
301                         /* does it allow the type? */
302                         for ( j = 0; oc->soc_allowed != NULL && 
303                                 oc->soc_allowed[j] != NULL; j++ )
304                         {
305 #ifdef SLAPD_SCHEMA_NOT_COMPAT
306                                 if( at == oc->soc_allowed[j] ) {
307                                         return LDAP_SUCCESS;
308                                 }
309 #else
310                                 at = oc->soc_allowed[j];
311                                 if ( at->sat_oid &&
312                                      strcmp( at->sat_oid, t ) == 0 ) {
313                                         if ( t != type )
314                                                 ldap_memfree( t );
315                                         return LDAP_SUCCESS;
316                                 }
317                                 pp = at->sat_names;
318                                 if ( pp == NULL )
319                                         continue;
320                                 while ( *pp ) {
321                                         if ( strcasecmp( *pp, t ) == 0 ||
322                                              strcmp( *pp, "*" ) == 0 ) {
323                                                 if ( t != type )
324                                                         ldap_memfree( t );
325                                                 return LDAP_SUCCESS;
326                                         }
327                                         pp++;
328                                 }
329 #endif
330                         }
331                         /* maybe the next oc allows it */
332
333 #ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
334                 /* we don't know about the oc. assume it allows it */
335                 } else {
336                         if ( t != type )
337                                 ldap_memfree( t );
338                         return LDAP_SUCCESS;
339 #endif
340                 }
341         }
342
343 #ifndef SLAPD_SCHEMA_NOT_COMPAT
344         if ( t != type )
345                 ldap_memfree( t );
346 #endif
347
348         /* not allowed by any oc */
349         return LDAP_OBJECT_CLASS_VIOLATION;
350 }