]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_check.c
SLP extension derived from patch provided by Caldera Systems.
[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 static char *   oc_check_required(Entry *e, struct berval *ocname);
20
21 /*
22  * entry_schema_check - check that entry e conforms to the schema required
23  * by its object class(es).
24  *
25  * returns 0 if so, non-zero otherwise.
26  */
27
28 int
29 entry_schema_check( 
30         Entry *e, Attribute *oldattrs, const char** text )
31 {
32         Attribute       *a, *aoc;
33         ObjectClass *oc;
34         int             i;
35         int             ret;
36         AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass;
37         int extensible = 0;
38
39         if( !global_schemacheck ) return LDAP_SUCCESS;
40
41         /* find the object class attribute - could error out here */
42         if ( (aoc = attr_find( e->e_attrs, ad_objectClass )) == NULL ) {
43 #ifdef NEW_LOGGING
44             LDAP_LOG(( "schema", LDAP_LEVEL_INFO,
45                        "entry_schema_check: No object class for entry (%s).\n", e->e_dn ));
46 #else
47                 Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
48                     e->e_dn, 0, 0 );
49 #endif
50
51                 *text = "no objectClass attribute";
52                 return LDAP_OBJECT_CLASS_VIOLATION;
53         }
54
55         ret = LDAP_SUCCESS;
56
57         /* check that the entry has required attrs for each oc */
58         for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
59                 if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
60 #ifdef NEW_LOGGING
61                     LDAP_LOG(( "schema", LDAP_LEVEL_INFO,
62                                "entry_schema_check: dn (%s), objectclass \"%s\" not recognized\n",
63                                e->e_dn, aoc->a_vals[i]->bv_val ));
64 #else
65                         Debug( LDAP_DEBUG_ANY,
66                                 "entry_check_schema(%s): objectclass \"%s\" not recognized\n",
67                                 e->e_dn, aoc->a_vals[i]->bv_val, 0 );
68 #endif
69
70                         *text = "unrecognized object class";
71                         return LDAP_OBJECT_CLASS_VIOLATION;
72
73                 } else {
74                         char *s = oc_check_required( e, aoc->a_vals[i] );
75
76                         if (s != NULL) {
77 #ifdef NEW_LOGGING
78                             LDAP_LOG(( "schema", LDAP_LEVEL_INFO,
79                                        "entry_schema_check: dn (%s) oc \"%s\" requires att \"%s\"\n",
80                                        e->e_dn, aoc->a_vals[i]->bv_val, s ));
81 #else
82                                 Debug( LDAP_DEBUG_ANY,
83                                         "Entry (%s), oc \"%s\" requires attr \"%s\"\n",
84                                         e->e_dn, aoc->a_vals[i]->bv_val, s );
85 #endif
86
87                                 *text = "missing required attribute";
88                                 return LDAP_OBJECT_CLASS_VIOLATION;
89                         }
90
91                         if( oc == slap_schema.si_oc_extensibleObject ) {
92                                 extensible=1;
93                         }
94
95                 }
96         }
97
98         if( extensible ) {
99                 return LDAP_SUCCESS;
100         }
101
102         /* check that each attr in the entry is allowed by some oc */
103         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
104                 ret = oc_check_allowed( a->a_desc->ad_type, aoc->a_vals );
105                 if ( ret != 0 ) {
106                         char *type = a->a_desc->ad_cname->bv_val;
107 #ifdef NEW_LOGGING
108                         LDAP_LOG(( "schema", LDAP_LEVEL_INFO,
109                                    "entry_schema_check: Entry (%s) attr \"%s\" not allowed.\n",
110                                    e->e_dn, type ));
111 #else
112                         Debug( LDAP_DEBUG_ANY,
113                             "Entry (%s), attr \"%s\" not allowed\n",
114                             e->e_dn, type, 0 );
115 #endif
116
117                         *text = "attribute not allowed";
118                         break;
119                 }
120         }
121
122         return( ret );
123 }
124
125 static char *
126 oc_check_required( Entry *e, struct berval *ocname )
127 {
128         ObjectClass     *oc;
129         AttributeType   *at;
130         int             i;
131         Attribute       *a;
132
133 #ifdef NEW_LOGGING
134         LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
135                    "oc_check_required: dn (%s), objectclass \"%s\"\n",
136                    e->e_dn, ocname->bv_val ));
137 #else
138         Debug( LDAP_DEBUG_TRACE,
139                "oc_check_required entry (%s), objectclass \"%s\"\n",
140                e->e_dn, ocname->bv_val, 0 );
141 #endif
142
143
144         /* find global oc defn. it we don't know about it assume it's ok */
145         if ( (oc = oc_find( ocname->bv_val )) == NULL ) {
146                 return NULL;
147         }
148
149         /* check for empty oc_required */
150         if(oc->soc_required == NULL) {
151                 return NULL;
152         }
153
154         /* for each required attribute */
155         for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
156                 at = oc->soc_required[i];
157                 /* see if it's in the entry */
158                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
159                         if( a->a_desc->ad_type == at ) {
160                                 break;
161                         }
162                 }
163                 /* not there => schema violation */
164                 if ( a == NULL ) {
165                         return at->sat_cname;
166                 }
167         }
168
169         return( NULL );
170 }
171
172 int oc_check_allowed(
173         AttributeType *at,
174         struct berval **ocl )
175 {
176         ObjectClass     *oc;
177         int             i, j;
178
179 #ifdef NEW_LOGGING
180         LDAP_LOG(( "schema", LDAP_LEVEL_ENTRY,
181                    "oc_check_allowed: type \"%s\"\n", at->sat_cname ));
182 #else
183         Debug( LDAP_DEBUG_TRACE,
184                 "oc_check_allowed type \"%s\"\n",
185                 at->sat_cname, 0, 0 );
186 #endif
187
188
189         /* always allow objectclass attribute */
190         if ( strcasecmp( at->sat_cname, "objectclass" ) == 0 ) {
191                 return LDAP_SUCCESS;
192         }
193
194
195         /*
196          * All operational attributions are allowed by schema rules.
197          */
198         if( is_at_operational(at) ) {
199                 return LDAP_SUCCESS;
200         }
201
202         /* check that the type appears as req or opt in at least one oc */
203         for ( i = 0; ocl[i] != NULL; i++ ) {
204                 /* if we know about the oc */
205                 if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
206                         /* does it require the type? */
207                         for ( j = 0; oc->soc_required != NULL && 
208                                 oc->soc_required[j] != NULL; j++ )
209                         {
210                                 if( at == oc->soc_required[j] ) {
211                                         return LDAP_SUCCESS;
212                                 }
213                         }
214                         /* does it allow the type? */
215                         for ( j = 0; oc->soc_allowed != NULL && 
216                                 oc->soc_allowed[j] != NULL; j++ )
217                         {
218                                 if( at == oc->soc_allowed[j] ) {
219                                         return LDAP_SUCCESS;
220                                 }
221                         }
222                         /* maybe the next oc allows it */
223
224 #ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
225                 /* we don't know about the oc. assume it allows it */
226                 } else {
227                         if ( t != type )
228                                 ldap_memfree( t );
229                         return LDAP_SUCCESS;
230 #endif
231                 }
232         }
233
234
235         /* not allowed by any oc */
236         return LDAP_OBJECT_CLASS_VIOLATION;
237 }