7b7d7d09ff5e643bcca137deb7d43830eab74219
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / schema_data.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    The module that handles the Schema checkings and dynamic attributes
5    
6    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
8     
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21    
22 */
23
24 #include "includes.h"
25 #include "ldb_module.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "librpc/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_drsuapi.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "param/param.h"
31 #include "dsdb/samdb/ldb_modules/util.h"
32
33 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
34                                   const struct dsdb_schema *schema);
35 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
36                                    const struct dsdb_schema *schema);
37 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
38                                     const struct dsdb_schema *schema);
39 static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg,
40                                           const struct dsdb_schema *schema);
41 static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg,
42                                       const struct dsdb_schema *schema);
43 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
44                                       const struct dsdb_schema *schema);
45
46 static const struct {
47         const char *attr;
48         int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
49         bool aggregate;
50 } generated_attrs[] = {
51         {
52                 .attr = "objectClasses",
53                 .fn = generate_objectClasses,
54                 .aggregate = true,
55         },
56         {
57                 .attr = "attributeTypes",
58                 .fn = generate_attributeTypes,
59                 .aggregate = true,
60         },
61         {
62                 .attr = "dITContentRules",
63                 .fn = generate_dITContentRules,
64                 .aggregate = true,
65         },
66         {
67                 .attr = "extendedAttributeInfo",
68                 .fn = generate_extendedAttributeInfo,
69                 .aggregate = true,
70         },
71         {
72                 .attr = "extendedClassInfo",
73                 .fn = generate_extendedClassInfo,
74                 .aggregate = true,
75         },
76         {
77                 .attr = "possibleInferiors",
78                 .fn = generate_possibleInferiors,
79                 .aggregate = false,
80         }
81 };
82
83 struct schema_data_private_data {
84         struct ldb_dn *aggregate_dn;
85         struct ldb_dn *schema_dn;
86 };
87
88 struct schema_data_search_data {
89         struct ldb_module *module;
90         struct ldb_request *req;
91
92         const struct dsdb_schema *schema;
93 };
94
95 static int schema_data_init(struct ldb_module *module)
96 {
97         struct ldb_context *ldb;
98         struct ldb_dn *schema_dn;
99         int ret;
100         struct schema_data_private_data *data;
101
102         ret = ldb_next_init(module);
103         if (ret != LDB_SUCCESS) {
104                 return ret;
105         }
106
107         ldb = ldb_module_get_ctx(module);
108         schema_dn = ldb_get_schema_basedn(ldb);
109         if (!schema_dn) {
110                 ldb_reset_err_string(ldb);
111                 ldb_debug(ldb, LDB_DEBUG_WARNING,
112                           "schema_data_init: no schema dn present: (skip schema loading)\n");
113                 return LDB_SUCCESS;
114         }
115
116         data = talloc(module, struct schema_data_private_data);
117         if (data == NULL) {
118                 return ldb_oom(ldb);
119         }
120
121         data->schema_dn = schema_dn;
122
123         /* Used to check to see if this is a result on the CN=Aggregate schema */
124         data->aggregate_dn = samdb_aggregate_schema_dn(ldb, data);
125         if (!data->aggregate_dn) {
126                 ldb_asprintf_errstring(ldb, "schema_data_init: Could not build aggregate schema DN for schema in %s", ldb_dn_get_linearized(schema_dn));
127                 return LDB_ERR_OPERATIONS_ERROR;
128         }
129
130         ldb_module_set_private(module, data);
131         return LDB_SUCCESS;
132 }
133
134 static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
135 {
136         struct ldb_context *ldb;
137         struct dsdb_schema *schema;
138         const struct ldb_val *attributeID = NULL;
139         const struct ldb_val *governsID = NULL;
140         const char *oid_attr = NULL;
141         const char *oid = NULL;
142         WERROR status;
143         bool rodc;
144         int ret;
145
146         ldb = ldb_module_get_ctx(module);
147
148         /* special objects should always go through */
149         if (ldb_dn_is_special(req->op.add.message->dn)) {
150                 return ldb_next_request(module, req);
151         }
152
153         /* replicated update should always go through */
154         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
155                 return ldb_next_request(module, req);
156         }
157
158         schema = dsdb_get_schema(ldb, req);
159         if (!schema) {
160                 return ldb_next_request(module, req);
161         }
162
163         ret = samdb_rodc(ldb, &rodc);
164         if (ret != LDB_SUCCESS) {
165                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
166         }
167
168         if (!schema->fsmo.we_are_master && !rodc) {
169                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
170                           "schema_data_add: we are not master: reject request\n");
171                 return LDB_ERR_UNWILLING_TO_PERFORM;
172         }
173
174         attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID");
175         governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
176
177         if (attributeID) {
178                 oid_attr = "attributeID";
179                 oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
180         } else if (governsID) {
181                 oid_attr = "governsID";
182                 oid = talloc_strndup(req, (const char *)governsID->data, governsID->length);
183         } else {
184                 return ldb_next_request(module, req);
185         }
186
187         if (!oid) {
188                 return ldb_oom(ldb);
189         }
190
191         status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL);
192         if (!W_ERROR_IS_OK(status)) {
193                 /* check for internal errors */
194                 if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
195                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
196                                       "schema_data_add: failed to map %s[%s]: %s\n",
197                                       oid_attr, oid, win_errstr(status));
198                         return LDB_ERR_UNWILLING_TO_PERFORM;
199                 }
200
201                 /* Update prefixMap and save it */
202                 status = dsdb_create_prefix_mapping(ldb, schema, oid);
203                 if (!W_ERROR_IS_OK(status)) {
204                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
205                                   "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
206                                   oid_attr, oid, win_errstr(status));
207                         return LDB_ERR_UNWILLING_TO_PERFORM;
208                 }
209         }
210
211         return ldb_next_request(module, req);
212 }
213
214 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
215                                   const struct dsdb_schema *schema) 
216 {
217         const struct dsdb_class *sclass;
218         int ret;
219
220         for (sclass = schema->classes; sclass; sclass = sclass->next) {
221                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
222                 if (ret != LDB_SUCCESS) {
223                         return ret;
224                 }
225         }
226         return LDB_SUCCESS;
227 }
228 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
229                                   const struct dsdb_schema *schema) 
230 {
231         const struct dsdb_attribute *attribute;
232         int ret;
233         
234         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
235                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
236                 if (ret != LDB_SUCCESS) {
237                         return ret;
238                 }
239         }
240         return LDB_SUCCESS;
241 }
242
243 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
244                                     const struct dsdb_schema *schema) 
245 {
246         const struct dsdb_class *sclass;
247         int ret;
248
249         for (sclass = schema->classes; sclass; sclass = sclass->next) {
250                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
251                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
252                         if (!ditcontentrule) {
253                                 return ldb_oom(ldb);
254                         }
255                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
256                         if (ret != LDB_SUCCESS) {
257                                 return ret;
258                         }
259                 }
260         }
261         return LDB_SUCCESS;
262 }
263
264 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
265                                           struct ldb_message *msg,
266                                           const struct dsdb_schema *schema)
267 {
268         const struct dsdb_attribute *attribute;
269         int ret;
270
271         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
272                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
273                 if (!val) {
274                         return ldb_oom(ldb);
275                 }
276
277                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
278                 if (ret != LDB_SUCCESS) {
279                         return ret;
280                 }
281         }
282
283         return LDB_SUCCESS;
284 }
285
286 static int generate_extendedClassInfo(struct ldb_context *ldb,
287                                       struct ldb_message *msg,
288                                       const struct dsdb_schema *schema)
289 {
290         const struct dsdb_class *sclass;
291         int ret;
292
293         for (sclass = schema->classes; sclass; sclass = sclass->next) {
294                 char *val = schema_class_to_extendedInfo(msg, sclass);
295                 if (!val) {
296                         return ldb_oom(ldb);
297                 }
298
299                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
300                 if (ret != LDB_SUCCESS) {
301                         return ret;
302                 }
303         }
304
305         return LDB_SUCCESS;
306 }
307
308
309 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
310                                       const struct dsdb_schema *schema) 
311 {
312         struct ldb_dn *dn = msg->dn;
313         unsigned int i;
314         int ret;
315         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
316         const struct ldb_val *first_component_val;
317         const struct dsdb_class *schema_class;
318         const char **possibleInferiors;
319
320         if (strcasecmp(first_component_name, "cn") != 0) {
321                 return LDB_SUCCESS;
322         }
323
324         first_component_val = ldb_dn_get_component_val(dn, 0);
325
326         schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val);
327         if (schema_class == NULL) {
328                 return LDB_SUCCESS;
329         }
330         
331         possibleInferiors = schema_class->possibleInferiors;
332         if (possibleInferiors == NULL) {
333                 return LDB_SUCCESS;
334         }
335
336         for (i=0;possibleInferiors[i];i++) {
337                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
338                 if (ret != LDB_SUCCESS) {
339                         return ret;
340                 }
341         }
342
343         return LDB_SUCCESS;
344 }
345
346
347 /* Add objectClasses, attributeTypes and dITContentRules from the
348    schema object (they are not stored in the database)
349  */
350 static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares)
351 {
352         struct ldb_context *ldb;
353         struct schema_data_search_data *ac;
354         struct schema_data_private_data *mc;
355         unsigned int i;
356         int ret;
357
358         ac = talloc_get_type(req->context, struct schema_data_search_data);
359         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data);
360         ldb = ldb_module_get_ctx(ac->module);
361
362         if (!ares) {
363                 return ldb_module_done(ac->req, NULL, NULL,
364                                         LDB_ERR_OPERATIONS_ERROR);
365         }
366         if (ares->error != LDB_SUCCESS) {
367                 return ldb_module_done(ac->req, ares->controls,
368                                         ares->response, ares->error);
369         }
370         /* Only entries are interesting, and we handle the case of the parent seperatly */
371
372         switch (ares->type) {
373         case LDB_REPLY_ENTRY:
374
375                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
376                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
377                                 if (generated_attrs[i].aggregate &&
378                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
379                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
380                                         if (ret != LDB_SUCCESS) {
381                                                 return ret;
382                                         }
383                                 }
384                         }
385                 } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0)
386                            && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) {
387                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
388                                 if (!generated_attrs[i].aggregate &&
389                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
390                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
391                                         if (ret != LDB_SUCCESS) {
392                                                 return ret;
393                                         }
394                                 }
395                         }
396                 }
397
398
399                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
400
401         case LDB_REPLY_REFERRAL:
402
403                 return ldb_module_send_referral(ac->req, ares->referral);
404
405         case LDB_REPLY_DONE:
406
407                 return ldb_module_done(ac->req, ares->controls,
408                                         ares->response, ares->error);
409         }
410
411         return LDB_SUCCESS;
412 }
413
414 /* search */
415 static int schema_data_search(struct ldb_module *module, struct ldb_request *req)
416 {
417         struct ldb_context *ldb = ldb_module_get_ctx(module);
418         unsigned int i;
419         int ret;
420         struct schema_data_search_data *search_context;
421         struct ldb_request *down_req;
422         const struct dsdb_schema *schema;
423         if (!ldb_module_get_private(module)) {
424                 /* If there is no module data, there is little we can do */
425                 return ldb_next_request(module, req);
426         }
427
428         /* The schema manipulation does not apply to special DNs */
429         if (ldb_dn_is_special(req->op.search.base)) {
430                 return ldb_next_request(module, req);
431         }
432
433         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
434                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
435                         break;
436                 }
437         }
438         if (i == ARRAY_SIZE(generated_attrs)) {
439                 /* No request for a generated attr found, nothing to
440                  * see here, move along... */
441                 return ldb_next_request(module, req);
442         }
443
444         schema = dsdb_get_schema(ldb, NULL);
445         if (!schema || !ldb_module_get_private(module)) {
446                 /* If there is no schema, there is little we can do */
447                 return ldb_next_request(module, req);
448         }
449
450         search_context = talloc(req, struct schema_data_search_data);
451         if (!search_context) {
452                 return ldb_oom(ldb);
453         }
454
455         search_context->module = module;
456         search_context->req = req;
457         search_context->schema = talloc_reference(search_context, schema);
458         if (!search_context->schema) {
459                 return ldb_oom(ldb);
460         }
461
462         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
463                                         req->op.search.base,
464                                         req->op.search.scope,
465                                         req->op.search.tree,
466                                         req->op.search.attrs,
467                                         req->controls,
468                                         search_context, schema_data_search_callback,
469                                         req);
470         LDB_REQ_SET_LOCATION(down_req);
471         if (ret != LDB_SUCCESS) {
472                 return ldb_operr(ldb);
473         }
474
475         return ldb_next_request(module, down_req);
476 }
477
478
479 _PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = {
480         .name           = "schema_data",
481         .init_context   = schema_data_init,
482         .add            = schema_data_add,
483         .search         = schema_data_search
484 };