b1d8711cfa14dbd0a0507c61ee90d02fe05462a1
[samba.git] / source4 / dsdb / samdb / ldb_modules / schema_fsmo.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    The module that handles the Schema FSMO Role Owner
5    checkings, it also loads the dsdb_schema.
6    
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
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
32 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
33                                   const struct dsdb_schema *schema);
34 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
35                                    const struct dsdb_schema *schema);
36 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
37                                     const struct dsdb_schema *schema);
38 static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg,
39                                           const struct dsdb_schema *schema);
40 static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg,
41                                       const struct dsdb_schema *schema);
42 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
43                                       const struct dsdb_schema *schema);
44
45 static const struct {
46         const char *attr;
47         int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
48         bool aggregate;
49 } generated_attrs[] = {
50         {
51                 .attr = "objectClasses",
52                 .fn = generate_objectClasses,
53                 .aggregate = true,
54         },
55         {
56                 .attr = "attributeTypes",
57                 .fn = generate_attributeTypes,
58                 .aggregate = true,
59         },
60         {
61                 .attr = "dITContentRules",
62                 .fn = generate_dITContentRules,
63                 .aggregate = true,
64         },
65         {
66                 .attr = "extendedAttributeInfo",
67                 .fn = generate_extendedAttributeInfo,
68                 .aggregate = true,
69         },
70         {
71                 .attr = "extendedClassInfo",
72                 .fn = generate_extendedClassInfo,
73                 .aggregate = true,
74         },
75         {
76                 .attr = "possibleInferiors",
77                 .fn = generate_possibleInferiors,
78                 .aggregate = false,
79         }
80 };
81
82 struct schema_fsmo_private_data {
83         struct ldb_dn *aggregate_dn;
84 };
85
86 struct schema_fsmo_search_data {
87         struct ldb_module *module;
88         struct ldb_request *req;
89
90         const struct dsdb_schema *schema;
91 };
92
93 static int schema_fsmo_init(struct ldb_module *module)
94 {
95         struct ldb_context *ldb;
96         TALLOC_CTX *mem_ctx;
97         struct ldb_dn *schema_dn;
98         struct dsdb_schema *schema;
99         char *error_string = NULL;
100         int ret;
101         struct schema_fsmo_private_data *data;
102
103         ldb = ldb_module_get_ctx(module);
104         schema_dn = samdb_schema_dn(ldb);
105         if (!schema_dn) {
106                 ldb_reset_err_string(ldb);
107                 ldb_debug(ldb, LDB_DEBUG_WARNING,
108                           "schema_fsmo_init: no schema dn present: (skip schema loading)\n");
109                 return ldb_next_init(module);
110         }
111
112         data = talloc(module, struct schema_fsmo_private_data);
113         if (data == NULL) {
114                 ldb_oom(ldb);
115                 return LDB_ERR_OPERATIONS_ERROR;
116         }
117
118         /* Check to see if this is a result on the CN=Aggregate schema */
119         data->aggregate_dn = ldb_dn_copy(data, schema_dn);
120         if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) {
121                 ldb_oom(ldb);
122                 return LDB_ERR_OPERATIONS_ERROR;
123         }
124
125         ldb_module_set_private(module, data);
126
127         if (dsdb_get_schema(ldb)) {
128                 return ldb_next_init(module);
129         }
130
131         mem_ctx = talloc_new(module);
132         if (!mem_ctx) {
133                 ldb_oom(ldb);
134                 return LDB_ERR_OPERATIONS_ERROR;
135         }
136
137         ret = dsdb_schema_from_schema_dn(mem_ctx, ldb,
138                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
139                                          schema_dn, &schema, &error_string);
140
141         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
142                 ldb_reset_err_string(ldb);
143                 ldb_debug(ldb, LDB_DEBUG_WARNING,
144                           "schema_fsmo_init: no schema head present: (skip schema loading)\n");
145                 talloc_free(mem_ctx);
146                 return ldb_next_init(module);
147         }
148
149         if (ret != LDB_SUCCESS) {
150                 ldb_asprintf_errstring(ldb, 
151                                        "schema_fsmo_init: dsdb_schema load failed: %s",
152                                        error_string);
153                 talloc_free(mem_ctx);
154                 return ret;
155         }
156
157         /* dsdb_set_schema() steal schema into the ldb_context */
158         ret = dsdb_set_schema(ldb, schema);
159         if (ret != LDB_SUCCESS) {
160                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
161                               "schema_fsmo_init: dsdb_set_schema() failed: %d:%s",
162                               ret, ldb_strerror(ret));
163                 talloc_free(mem_ctx);
164                 return ret;
165         }
166
167         talloc_free(mem_ctx);
168         return ldb_next_init(module);
169 }
170
171 static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
172 {
173         struct ldb_context *ldb;
174         struct dsdb_schema *schema;
175         const char *attributeID = NULL;
176         const char *governsID = NULL;
177         const char *oid_attr = NULL;
178         const char *oid = NULL;
179         uint32_t id32;
180         WERROR status;
181
182         ldb = ldb_module_get_ctx(module);
183
184         /* special objects should always go through */
185         if (ldb_dn_is_special(req->op.add.message->dn)) {
186                 return ldb_next_request(module, req);
187         }
188
189         /* replicated update should always go through */
190         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
191                 return ldb_next_request(module, req);
192         }
193
194         schema = dsdb_get_schema(ldb);
195         if (!schema) {
196                 return ldb_next_request(module, req);
197         }
198
199         if (!schema->fsmo.we_are_master) {
200                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
201                           "schema_fsmo_add: we are not master: reject request\n");
202                 return LDB_ERR_UNWILLING_TO_PERFORM;
203         }
204
205         attributeID = samdb_result_string(req->op.add.message, "attributeID", NULL);
206         governsID = samdb_result_string(req->op.add.message, "governsID", NULL);
207
208         if (attributeID) {
209                 oid_attr = "attributeID";
210                 oid = attributeID;
211         } else if (governsID) {
212                 oid_attr = "governsID";
213                 oid = governsID;
214         }
215
216         if (!oid) {
217                 return ldb_next_request(module, req);
218         }
219
220         status = dsdb_map_oid2int(schema, oid, &id32);
221         if (W_ERROR_IS_OK(status)) {
222                 return ldb_next_request(module, req);
223         } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
224                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
225                           "schema_fsmo_add: failed to map %s[%s]: %s\n",
226                           oid_attr, oid, win_errstr(status));
227                 return LDB_ERR_UNWILLING_TO_PERFORM;
228         }
229
230         status = dsdb_create_prefix_mapping(ldb, schema, oid);
231         if (!W_ERROR_IS_OK(status)) {
232                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
233                           "schema_fsmo_add: failed to create prefix mapping for %s[%s]: %s\n",
234                           oid_attr, oid, win_errstr(status));
235                 return LDB_ERR_UNWILLING_TO_PERFORM;
236         }
237
238         return ldb_next_request(module, req);
239 }
240
241 static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req)
242 {
243         struct ldb_context *ldb;
244         struct ldb_dn *schema_dn;
245         struct dsdb_schema *schema;
246         char *error_string = NULL;
247         int ret;
248         TALLOC_CTX *mem_ctx;
249
250         ldb = ldb_module_get_ctx(module);
251
252         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) {
253                 return ldb_next_request(module, req);
254         }
255         
256         schema_dn = samdb_schema_dn(ldb);
257         if (!schema_dn) {
258                 ldb_reset_err_string(ldb);
259                 ldb_debug(ldb, LDB_DEBUG_WARNING,
260                           "schema_fsmo_extended: no schema dn present: (skip schema loading)\n");
261                 return ldb_next_request(module, req);
262         }
263         
264         mem_ctx = talloc_new(module);
265         if (!mem_ctx) {
266                 ldb_oom(ldb);
267                 return LDB_ERR_OPERATIONS_ERROR;
268         }
269         
270         ret = dsdb_schema_from_schema_dn(mem_ctx, ldb,
271                                          lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
272                                          schema_dn, &schema, &error_string);
273
274         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
275                 ldb_reset_err_string(ldb);
276                 ldb_debug(ldb, LDB_DEBUG_WARNING,
277                           "schema_fsmo_extended: no schema head present: (skip schema loading)\n");
278                 talloc_free(mem_ctx);
279                 return ldb_next_request(module, req);
280         }
281
282         if (ret != LDB_SUCCESS) {
283                 ldb_asprintf_errstring(ldb, 
284                                        "schema_fsmo_extended: dsdb_schema load failed: %s",
285                                        error_string);
286                 talloc_free(mem_ctx);
287                 return ldb_next_request(module, req);
288         }
289
290         /* Replace the old schema*/
291         ret = dsdb_set_schema(ldb, schema);
292         if (ret != LDB_SUCCESS) {
293                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
294                               "schema_fsmo_extended: dsdb_set_schema() failed: %d:%s",
295                               ret, ldb_strerror(ret));
296                 talloc_free(mem_ctx);
297                 return ret;
298         }
299
300         talloc_free(mem_ctx);
301         return LDB_SUCCESS;
302 }
303
304 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
305                                   const struct dsdb_schema *schema) 
306 {
307         const struct dsdb_class *sclass;
308         int ret;
309
310         for (sclass = schema->classes; sclass; sclass = sclass->next) {
311                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
312                 if (ret != LDB_SUCCESS) {
313                         return ret;
314                 }
315         }
316         return LDB_SUCCESS;
317 }
318 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
319                                   const struct dsdb_schema *schema) 
320 {
321         const struct dsdb_attribute *attribute;
322         int ret;
323         
324         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
325                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
326                 if (ret != LDB_SUCCESS) {
327                         return ret;
328                 }
329         }
330         return LDB_SUCCESS;
331 }
332
333 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
334                                     const struct dsdb_schema *schema) 
335 {
336         const struct dsdb_class *sclass;
337         int ret;
338
339         for (sclass = schema->classes; sclass; sclass = sclass->next) {
340                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
341                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
342                         if (!ditcontentrule) {
343                                 ldb_oom(ldb);
344                                 return LDB_ERR_OPERATIONS_ERROR;
345                         }
346                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
347                         if (ret != LDB_SUCCESS) {
348                                 return ret;
349                         }
350                 }
351         }
352         return LDB_SUCCESS;
353 }
354
355 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
356                                           struct ldb_message *msg,
357                                           const struct dsdb_schema *schema)
358 {
359         const struct dsdb_attribute *attribute;
360         int ret;
361
362         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
363                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
364                 if (!val) {
365                         ldb_oom(ldb);
366                         return LDB_ERR_OPERATIONS_ERROR;
367                 }
368
369                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
370                 if (ret != LDB_SUCCESS) {
371                         return ret;
372                 }
373         }
374
375         return LDB_SUCCESS;
376 }
377
378 static int generate_extendedClassInfo(struct ldb_context *ldb,
379                                       struct ldb_message *msg,
380                                       const struct dsdb_schema *schema)
381 {
382         const struct dsdb_class *sclass;
383         int ret;
384
385         for (sclass = schema->classes; sclass; sclass = sclass->next) {
386                 char *val = schema_class_to_extendedInfo(msg, sclass);
387                 if (!val) {
388                         ldb_oom(ldb);
389                         return LDB_ERR_OPERATIONS_ERROR;
390                 }
391
392                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
393                 if (ret != LDB_SUCCESS) {
394                         return ret;
395                 }
396         }
397
398         return LDB_SUCCESS;
399 }
400
401
402 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
403                                       const struct dsdb_schema *schema) 
404 {
405         struct ldb_dn *dn = msg->dn;
406         int ret, i;
407         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
408         const struct ldb_val *first_component_val;
409         const char *class_name;
410         const struct dsdb_class *schema_class;
411         const char **possibleInferiors;
412
413         if (strcasecmp(first_component_name, "cn") != 0) {
414                 return LDB_SUCCESS;
415         }
416
417         first_component_val = ldb_dn_get_component_val(dn, 0);
418         class_name = (const char *)first_component_val->data;
419
420         schema_class = dsdb_class_by_cn(schema, class_name);
421         if (schema_class == NULL) {
422                 return LDB_SUCCESS;
423         }
424         
425         possibleInferiors = schema_class->possibleInferiors;
426         if (possibleInferiors == NULL) {
427                 return LDB_SUCCESS;
428         }
429
430         for (i=0;possibleInferiors[i];i++) {
431                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
432                 if (ret != LDB_SUCCESS) {
433                         return ret;
434                 }
435         }
436
437         return LDB_SUCCESS;
438 }
439
440
441 /* Add objectClasses, attributeTypes and dITContentRules from the
442    schema object (they are not stored in the database)
443  */
444 static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
445 {
446         struct ldb_context *ldb;
447         struct schema_fsmo_search_data *ac;
448         struct schema_fsmo_private_data *mc;
449         int i, ret;
450
451         ac = talloc_get_type(req->context, struct schema_fsmo_search_data);
452         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_fsmo_private_data);
453         ldb = ldb_module_get_ctx(ac->module);
454
455         if (!ares) {
456                 return ldb_module_done(ac->req, NULL, NULL,
457                                         LDB_ERR_OPERATIONS_ERROR);
458         }
459         if (ares->error != LDB_SUCCESS) {
460                 return ldb_module_done(ac->req, ares->controls,
461                                         ares->response, ares->error);
462         }
463         /* Only entries are interesting, and we handle the case of the parent seperatly */
464
465         switch (ares->type) {
466         case LDB_REPLY_ENTRY:
467
468                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
469                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
470                                 if (generated_attrs[i].aggregate &&
471                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
472                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
473                                         if (ret != LDB_SUCCESS) {
474                                                 return ret;
475                                         }
476                                 }
477                         }
478                 } else {
479                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
480                                 if (!generated_attrs[i].aggregate &&
481                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
482                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
483                                         if (ret != LDB_SUCCESS) {
484                                                 return ret;
485                                         }
486                                 }
487                         }
488                 }
489
490
491                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
492
493         case LDB_REPLY_REFERRAL:
494
495                 return ldb_module_send_referral(ac->req, ares->referral);
496
497         case LDB_REPLY_DONE:
498
499                 return ldb_module_done(ac->req, ares->controls,
500                                         ares->response, ares->error);
501         }
502
503         return LDB_SUCCESS;
504 }
505
506 /* search */
507 static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req)
508 {
509         struct ldb_context *ldb = ldb_module_get_ctx(module);
510         int i, ret;
511         struct schema_fsmo_search_data *search_context;
512         struct ldb_request *down_req;
513         struct dsdb_schema *schema = dsdb_get_schema(ldb);
514
515         if (!schema || !ldb_module_get_private(module)) {
516                 /* If there is no schema, there is little we can do */
517                 return ldb_next_request(module, req);
518         }
519         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
520                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
521                         break;
522                 }
523         }
524         if (i == ARRAY_SIZE(generated_attrs)) {
525                 /* No request for a generated attr found, nothing to
526                  * see here, move along... */
527                 return ldb_next_request(module, req);
528         }
529
530         search_context = talloc(req, struct schema_fsmo_search_data);
531         if (!search_context) {
532                 ldb_oom(ldb);
533                 return LDB_ERR_OPERATIONS_ERROR;
534         }
535
536         search_context->module = module;
537         search_context->req = req;
538         search_context->schema = schema;
539
540         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
541                                         req->op.search.base,
542                                         req->op.search.scope,
543                                         req->op.search.tree,
544                                         req->op.search.attrs,
545                                         req->controls,
546                                         search_context, schema_fsmo_search_callback,
547                                         req);
548         if (ret != LDB_SUCCESS) {
549                 return LDB_ERR_OPERATIONS_ERROR;
550         }
551
552         return ldb_next_request(module, down_req);
553 }
554
555
556 _PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {
557         .name           = "schema_fsmo",
558         .init_context   = schema_fsmo_init,
559         .add            = schema_fsmo_add,
560         .extended       = schema_fsmo_extended,
561         .search         = schema_fsmo_search
562 };