]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_check.c
29cb3d9e098e8efd750aaeeaf805361f82720320
[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                 Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
44                     e->e_dn, 0, 0 );
45                 *text = "no objectClass attribute";
46                 return LDAP_OBJECT_CLASS_VIOLATION;
47         }
48
49         ret = LDAP_SUCCESS;
50
51         /* check that the entry has required attrs for each oc */
52         for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
53                 if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
54                         Debug( LDAP_DEBUG_ANY,
55                                 "entry_check_schema(%s): objectclass \"%s\" not recognized\n",
56                                 e->e_dn, aoc->a_vals[i]->bv_val, 0 );
57                         *text = "unrecognized object class";
58                         return LDAP_OBJECT_CLASS_VIOLATION;
59
60                 } else {
61                         char *s = oc_check_required( e, aoc->a_vals[i] );
62
63                         if (s != NULL) {
64                                 Debug( LDAP_DEBUG_ANY,
65                                         "Entry (%s), oc \"%s\" requires attr \"%s\"\n",
66                                         e->e_dn, aoc->a_vals[i]->bv_val, s );
67                                 *text = "missing required attribute";
68                                 return LDAP_OBJECT_CLASS_VIOLATION;
69                         }
70
71                         if( oc == slap_schema.si_oc_extensibleObject ) {
72                                 extensible=1;
73                         }
74
75                 }
76         }
77
78         if( extensible ) {
79                 return LDAP_SUCCESS;
80         }
81
82         /* check that each attr in the entry is allowed by some oc */
83         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
84                 ret = oc_check_allowed( a->a_desc->ad_type, aoc->a_vals );
85                 if ( ret != 0 ) {
86                         char *type = a->a_desc->ad_cname->bv_val;
87                         Debug( LDAP_DEBUG_ANY,
88                             "Entry (%s), attr \"%s\" not allowed\n",
89                             e->e_dn, type, 0 );
90                         *text = "attribute not allowed";
91                         break;
92                 }
93         }
94
95         return( ret );
96 }
97
98 static char *
99 oc_check_required( Entry *e, struct berval *ocname )
100 {
101         ObjectClass     *oc;
102         AttributeType   *at;
103         int             i;
104         Attribute       *a;
105
106         Debug( LDAP_DEBUG_TRACE,
107                "oc_check_required entry (%s), objectclass \"%s\"\n",
108                e->e_dn, ocname->bv_val, 0 );
109
110         /* find global oc defn. it we don't know about it assume it's ok */
111         if ( (oc = oc_find( ocname->bv_val )) == NULL ) {
112                 return NULL;
113         }
114
115         /* check for empty oc_required */
116         if(oc->soc_required == NULL) {
117                 return NULL;
118         }
119
120         /* for each required attribute */
121         for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
122                 at = oc->soc_required[i];
123                 /* see if it's in the entry */
124                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
125                         if( a->a_desc->ad_type == at ) {
126                                 break;
127                         }
128                 }
129                 /* not there => schema violation */
130                 if ( a == NULL ) {
131                         return at->sat_cname;
132                 }
133         }
134
135         return( NULL );
136 }
137
138 int oc_check_allowed(
139         AttributeType *at,
140         struct berval **ocl )
141 {
142         ObjectClass     *oc;
143         int             i, j;
144
145         Debug( LDAP_DEBUG_TRACE,
146                 "oc_check_allowed type \"%s\"\n",
147                 at->sat_cname, 0, 0 );
148
149         /* always allow objectclass attribute */
150         if ( strcasecmp( at->sat_cname, "objectclass" ) == 0 ) {
151                 return LDAP_SUCCESS;
152         }
153
154
155         /*
156          * All operational attributions are allowed by schema rules.
157          */
158         if( is_at_operational(at) ) {
159                 return LDAP_SUCCESS;
160         }
161
162         /* check that the type appears as req or opt in at least one oc */
163         for ( i = 0; ocl[i] != NULL; i++ ) {
164                 /* if we know about the oc */
165                 if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
166                         /* does it require the type? */
167                         for ( j = 0; oc->soc_required != NULL && 
168                                 oc->soc_required[j] != NULL; j++ )
169                         {
170                                 if( at == oc->soc_required[j] ) {
171                                         return LDAP_SUCCESS;
172                                 }
173                         }
174                         /* does it allow the type? */
175                         for ( j = 0; oc->soc_allowed != NULL && 
176                                 oc->soc_allowed[j] != NULL; j++ )
177                         {
178                                 if( at == oc->soc_allowed[j] ) {
179                                         return LDAP_SUCCESS;
180                                 }
181                         }
182                         /* maybe the next oc allows it */
183
184 #ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
185                 /* we don't know about the oc. assume it allows it */
186                 } else {
187                         if ( t != type )
188                                 ldap_memfree( t );
189                         return LDAP_SUCCESS;
190 #endif
191                 }
192         }
193
194
195         /* not allowed by any oc */
196         return LDAP_OBJECT_CLASS_VIOLATION;
197 }