s4:dsdb/schema_data: reject changes to schemaInfo, msDs-Schema-Extensions, msDS-IntId
[samba.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         struct ldb_dn *parent_dn = NULL;
143         int cmp;
144         WERROR status;
145         bool rodc = false;
146         int ret;
147
148         ldb = ldb_module_get_ctx(module);
149
150         /* special objects should always go through */
151         if (ldb_dn_is_special(req->op.add.message->dn)) {
152                 return ldb_next_request(module, req);
153         }
154
155         /* replicated update should always go through */
156         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
157                 return ldb_next_request(module, req);
158         }
159
160         schema = dsdb_get_schema(ldb, req);
161         if (!schema) {
162                 return ldb_next_request(module, req);
163         }
164
165         if (schema->base_dn == NULL) {
166                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
167                           "schema_data_add: base_dn NULL\n");
168                 return LDB_ERR_OPERATIONS_ERROR;
169         }
170
171         ret = samdb_rodc(ldb, &rodc);
172         if (ret != LDB_SUCCESS) {
173                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
174         }
175
176         if (!schema->fsmo.we_are_master && !rodc) {
177                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
178                           "schema_data_add: we are not master: reject request\n");
179                 return LDB_ERR_UNWILLING_TO_PERFORM;
180         }
181
182         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
183                 /*
184                  * the provision code needs to create
185                  * the schema root object.
186                  */
187                 cmp = ldb_dn_compare(req->op.add.message->dn, schema->base_dn);
188                 if (cmp == 0) {
189                         return ldb_next_request(module, req);
190                 }
191         }
192
193         parent_dn = ldb_dn_get_parent(req, req->op.add.message->dn);
194         if (!parent_dn) {
195                 return ldb_oom(ldb);
196         }
197
198         cmp = ldb_dn_compare(parent_dn, schema->base_dn);
199         if (cmp != 0) {
200                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
201                           "schema_data_add: no direct child :%s\n",
202                           ldb_dn_get_linearized(req->op.add.message->dn));
203                 return LDB_ERR_UNWILLING_TO_PERFORM;
204         }
205
206         attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID");
207         governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
208
209         if (attributeID) {
210                 oid_attr = "attributeID";
211                 oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
212         } else if (governsID) {
213                 oid_attr = "governsID";
214                 oid = talloc_strndup(req, (const char *)governsID->data, governsID->length);
215         } else {
216                 return ldb_next_request(module, req);
217         }
218
219         if (!oid) {
220                 return ldb_oom(ldb);
221         }
222
223         status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL);
224         if (!W_ERROR_IS_OK(status)) {
225                 /* check for internal errors */
226                 if (!W_ERROR_EQUAL(status, WERR_NOT_FOUND)) {
227                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
228                                       "schema_data_add: failed to map %s[%s]: %s\n",
229                                       oid_attr, oid, win_errstr(status));
230                         return LDB_ERR_UNWILLING_TO_PERFORM;
231                 }
232
233                 /* Update prefixMap and save it */
234                 status = dsdb_create_prefix_mapping(ldb, schema, oid);
235                 if (!W_ERROR_IS_OK(status)) {
236                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
237                                   "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
238                                   oid_attr, oid, win_errstr(status));
239                         return LDB_ERR_UNWILLING_TO_PERFORM;
240                 }
241         }
242
243         return ldb_next_request(module, req);
244 }
245
246 static int schema_data_modify(struct ldb_module *module, struct ldb_request *req)
247 {
248         struct ldb_context *ldb;
249         struct dsdb_schema *schema;
250         int cmp;
251         bool rodc = false;
252         int ret;
253
254         ldb = ldb_module_get_ctx(module);
255
256         /* special objects should always go through */
257         if (ldb_dn_is_special(req->op.mod.message->dn)) {
258                 return ldb_next_request(module, req);
259         }
260
261         /* replicated update should always go through */
262         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
263                 return ldb_next_request(module, req);
264         }
265
266         /* dbcheck should be able to fix things */
267         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
268                 return ldb_next_request(module, req);
269         }
270
271         schema = dsdb_get_schema(ldb, req);
272         if (!schema) {
273                 return ldb_next_request(module, req);
274         }
275
276         cmp = ldb_dn_compare(req->op.mod.message->dn, schema->base_dn);
277         if (cmp == 0) {
278                 static const char * const constrained_attrs[] = {
279                         "schemaInfo",
280                         "prefixMap",
281                         "msDs-Schema-Extensions",
282                         "msDS-IntId",
283                         NULL
284                 };
285                 size_t i;
286                 struct ldb_message_element *el;
287
288                 if (ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID)) {
289                         return ldb_next_request(module, req);
290                 }
291
292                 for (i=0; constrained_attrs[i]; i++) {
293                         el = ldb_msg_find_element(req->op.mod.message,
294                                                   constrained_attrs[i]);
295                         if (el == NULL) {
296                                 continue;
297                         }
298
299                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
300                                       "schema_data_modify: reject update "
301                                       "of attribute[%s]\n",
302                                       constrained_attrs[i]);
303                         return LDB_ERR_CONSTRAINT_VIOLATION;
304                 }
305
306                 return ldb_next_request(module, req);
307         }
308
309         ret = samdb_rodc(ldb, &rodc);
310         if (ret != LDB_SUCCESS) {
311                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
312         }
313
314         if (!schema->fsmo.we_are_master && !rodc) {
315                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
316                           "schema_data_modify: we are not master: reject request\n");
317                 return LDB_ERR_UNWILLING_TO_PERFORM;
318         }
319
320         return ldb_next_request(module, req);
321 }
322
323 static int schema_data_del(struct ldb_module *module, struct ldb_request *req)
324 {
325         struct ldb_context *ldb;
326         struct dsdb_schema *schema;
327         bool rodc = false;
328         int ret;
329
330         ldb = ldb_module_get_ctx(module);
331
332         /* special objects should always go through */
333         if (ldb_dn_is_special(req->op.del.dn)) {
334                 return ldb_next_request(module, req);
335         }
336
337         /* replicated update should always go through */
338         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
339                 return ldb_next_request(module, req);
340         }
341
342         /* dbcheck should be able to fix things */
343         if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
344                 return ldb_next_request(module, req);
345         }
346
347         schema = dsdb_get_schema(ldb, req);
348         if (!schema) {
349                 return ldb_next_request(module, req);
350         }
351
352         ret = samdb_rodc(ldb, &rodc);
353         if (ret != LDB_SUCCESS) {
354                 DEBUG(4, (__location__ ": unable to tell if we are an RODC \n"));
355         }
356
357         if (!schema->fsmo.we_are_master && !rodc) {
358                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
359                           "schema_data_modify: we are not master: reject request\n");
360                 return LDB_ERR_UNWILLING_TO_PERFORM;
361         }
362
363         /*
364          * normaly the DACL will prevent delete
365          * with LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS
366          * above us.
367          */
368         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
369                       "schema_data_del: delete is not allowed in the schema\n");
370         return LDB_ERR_UNWILLING_TO_PERFORM;
371 }
372
373 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
374                                   const struct dsdb_schema *schema) 
375 {
376         const struct dsdb_class *sclass;
377         int ret;
378
379         for (sclass = schema->classes; sclass; sclass = sclass->next) {
380                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
381                 if (ret != LDB_SUCCESS) {
382                         return ret;
383                 }
384         }
385         return LDB_SUCCESS;
386 }
387 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
388                                   const struct dsdb_schema *schema) 
389 {
390         const struct dsdb_attribute *attribute;
391         int ret;
392         
393         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
394                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
395                 if (ret != LDB_SUCCESS) {
396                         return ret;
397                 }
398         }
399         return LDB_SUCCESS;
400 }
401
402 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
403                                     const struct dsdb_schema *schema) 
404 {
405         const struct dsdb_class *sclass;
406         int ret;
407
408         for (sclass = schema->classes; sclass; sclass = sclass->next) {
409                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
410                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
411                         if (!ditcontentrule) {
412                                 return ldb_oom(ldb);
413                         }
414                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
415                         if (ret != LDB_SUCCESS) {
416                                 return ret;
417                         }
418                 }
419         }
420         return LDB_SUCCESS;
421 }
422
423 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
424                                           struct ldb_message *msg,
425                                           const struct dsdb_schema *schema)
426 {
427         const struct dsdb_attribute *attribute;
428         int ret;
429
430         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
431                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
432                 if (!val) {
433                         return ldb_oom(ldb);
434                 }
435
436                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
437                 if (ret != LDB_SUCCESS) {
438                         return ret;
439                 }
440         }
441
442         return LDB_SUCCESS;
443 }
444
445 static int generate_extendedClassInfo(struct ldb_context *ldb,
446                                       struct ldb_message *msg,
447                                       const struct dsdb_schema *schema)
448 {
449         const struct dsdb_class *sclass;
450         int ret;
451
452         for (sclass = schema->classes; sclass; sclass = sclass->next) {
453                 char *val = schema_class_to_extendedInfo(msg, sclass);
454                 if (!val) {
455                         return ldb_oom(ldb);
456                 }
457
458                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
459                 if (ret != LDB_SUCCESS) {
460                         return ret;
461                 }
462         }
463
464         return LDB_SUCCESS;
465 }
466
467
468 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
469                                       const struct dsdb_schema *schema) 
470 {
471         struct ldb_dn *dn = msg->dn;
472         unsigned int i;
473         int ret;
474         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
475         const struct ldb_val *first_component_val;
476         const struct dsdb_class *schema_class;
477         const char **possibleInferiors;
478
479         if (strcasecmp(first_component_name, "cn") != 0) {
480                 return LDB_SUCCESS;
481         }
482
483         first_component_val = ldb_dn_get_component_val(dn, 0);
484
485         schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val);
486         if (schema_class == NULL) {
487                 return LDB_SUCCESS;
488         }
489         
490         possibleInferiors = schema_class->possibleInferiors;
491         if (possibleInferiors == NULL) {
492                 return LDB_SUCCESS;
493         }
494
495         for (i=0;possibleInferiors[i];i++) {
496                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
497                 if (ret != LDB_SUCCESS) {
498                         return ret;
499                 }
500         }
501
502         return LDB_SUCCESS;
503 }
504
505
506 /* Add objectClasses, attributeTypes and dITContentRules from the
507    schema object (they are not stored in the database)
508  */
509 static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares)
510 {
511         struct ldb_context *ldb;
512         struct schema_data_search_data *ac;
513         struct schema_data_private_data *mc;
514         unsigned int i;
515         int ret;
516
517         ac = talloc_get_type(req->context, struct schema_data_search_data);
518         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data);
519         ldb = ldb_module_get_ctx(ac->module);
520
521         if (!ares) {
522                 return ldb_module_done(ac->req, NULL, NULL,
523                                         LDB_ERR_OPERATIONS_ERROR);
524         }
525         if (ares->error != LDB_SUCCESS) {
526                 return ldb_module_done(ac->req, ares->controls,
527                                         ares->response, ares->error);
528         }
529         /* Only entries are interesting, and we handle the case of the parent seperatly */
530
531         switch (ares->type) {
532         case LDB_REPLY_ENTRY:
533
534                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
535                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
536                                 if (generated_attrs[i].aggregate &&
537                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
538                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
539                                         if (ret != LDB_SUCCESS) {
540                                                 return ret;
541                                         }
542                                 }
543                         }
544                 } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0)
545                            && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) {
546                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
547                                 if (!generated_attrs[i].aggregate &&
548                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
549                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
550                                         if (ret != LDB_SUCCESS) {
551                                                 return ret;
552                                         }
553                                 }
554                         }
555                 }
556
557
558                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
559
560         case LDB_REPLY_REFERRAL:
561
562                 return ldb_module_send_referral(ac->req, ares->referral);
563
564         case LDB_REPLY_DONE:
565
566                 return ldb_module_done(ac->req, ares->controls,
567                                         ares->response, ares->error);
568         }
569
570         return LDB_SUCCESS;
571 }
572
573 /* search */
574 static int schema_data_search(struct ldb_module *module, struct ldb_request *req)
575 {
576         struct ldb_context *ldb = ldb_module_get_ctx(module);
577         unsigned int i;
578         int ret;
579         struct schema_data_search_data *search_context;
580         struct ldb_request *down_req;
581         const struct dsdb_schema *schema;
582         if (!ldb_module_get_private(module)) {
583                 /* If there is no module data, there is little we can do */
584                 return ldb_next_request(module, req);
585         }
586
587         /* The schema manipulation does not apply to special DNs */
588         if (ldb_dn_is_special(req->op.search.base)) {
589                 return ldb_next_request(module, req);
590         }
591
592         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
593                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
594                         break;
595                 }
596         }
597         if (i == ARRAY_SIZE(generated_attrs)) {
598                 /* No request for a generated attr found, nothing to
599                  * see here, move along... */
600                 return ldb_next_request(module, req);
601         }
602
603         schema = dsdb_get_schema(ldb, NULL);
604         if (!schema || !ldb_module_get_private(module)) {
605                 /* If there is no schema, there is little we can do */
606                 return ldb_next_request(module, req);
607         }
608
609         search_context = talloc(req, struct schema_data_search_data);
610         if (!search_context) {
611                 return ldb_oom(ldb);
612         }
613
614         search_context->module = module;
615         search_context->req = req;
616         search_context->schema = talloc_reference(search_context, schema);
617         if (!search_context->schema) {
618                 return ldb_oom(ldb);
619         }
620
621         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
622                                         req->op.search.base,
623                                         req->op.search.scope,
624                                         req->op.search.tree,
625                                         req->op.search.attrs,
626                                         req->controls,
627                                         search_context, schema_data_search_callback,
628                                         req);
629         LDB_REQ_SET_LOCATION(down_req);
630         if (ret != LDB_SUCCESS) {
631                 return ldb_operr(ldb);
632         }
633
634         return ldb_next_request(module, down_req);
635 }
636
637
638 static const struct ldb_module_ops ldb_schema_data_module_ops = {
639         .name           = "schema_data",
640         .init_context   = schema_data_init,
641         .add            = schema_data_add,
642         .modify         = schema_data_modify,
643         .del            = schema_data_del,
644         .search         = schema_data_search
645 };
646
647 int ldb_schema_data_module_init(const char *version)
648 {
649         LDB_MODULE_CHECK_VERSION(version);
650         return ldb_register_module(&ldb_schema_data_module_ops);
651 }