1b8f786c3542eb8378da899f5e47e6fe65f3f3c8
[ira/wip.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         dsdb_make_schema_global(ldb);
301
302         talloc_free(mem_ctx);
303         return LDB_SUCCESS;
304 }
305
306 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
307                                   const struct dsdb_schema *schema) 
308 {
309         const struct dsdb_class *sclass;
310         int ret;
311
312         for (sclass = schema->classes; sclass; sclass = sclass->next) {
313                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
314                 if (ret != LDB_SUCCESS) {
315                         return ret;
316                 }
317         }
318         return LDB_SUCCESS;
319 }
320 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
321                                   const struct dsdb_schema *schema) 
322 {
323         const struct dsdb_attribute *attribute;
324         int ret;
325         
326         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
327                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
328                 if (ret != LDB_SUCCESS) {
329                         return ret;
330                 }
331         }
332         return LDB_SUCCESS;
333 }
334
335 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
336                                     const struct dsdb_schema *schema) 
337 {
338         const struct dsdb_class *sclass;
339         int ret;
340
341         for (sclass = schema->classes; sclass; sclass = sclass->next) {
342                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
343                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
344                         if (!ditcontentrule) {
345                                 ldb_oom(ldb);
346                                 return LDB_ERR_OPERATIONS_ERROR;
347                         }
348                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
349                         if (ret != LDB_SUCCESS) {
350                                 return ret;
351                         }
352                 }
353         }
354         return LDB_SUCCESS;
355 }
356
357 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
358                                           struct ldb_message *msg,
359                                           const struct dsdb_schema *schema)
360 {
361         const struct dsdb_attribute *attribute;
362         int ret;
363
364         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
365                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
366                 if (!val) {
367                         ldb_oom(ldb);
368                         return LDB_ERR_OPERATIONS_ERROR;
369                 }
370
371                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
372                 if (ret != LDB_SUCCESS) {
373                         return ret;
374                 }
375         }
376
377         return LDB_SUCCESS;
378 }
379
380 static int generate_extendedClassInfo(struct ldb_context *ldb,
381                                       struct ldb_message *msg,
382                                       const struct dsdb_schema *schema)
383 {
384         const struct dsdb_class *sclass;
385         int ret;
386
387         for (sclass = schema->classes; sclass; sclass = sclass->next) {
388                 char *val = schema_class_to_extendedInfo(msg, sclass);
389                 if (!val) {
390                         ldb_oom(ldb);
391                         return LDB_ERR_OPERATIONS_ERROR;
392                 }
393
394                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
395                 if (ret != LDB_SUCCESS) {
396                         return ret;
397                 }
398         }
399
400         return LDB_SUCCESS;
401 }
402
403
404 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
405                                       const struct dsdb_schema *schema) 
406 {
407         struct ldb_dn *dn = msg->dn;
408         int ret, i;
409         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
410         const struct ldb_val *first_component_val;
411         const char *class_name;
412         const struct dsdb_class *schema_class;
413         const char **possibleInferiors;
414
415         if (strcasecmp(first_component_name, "cn") != 0) {
416                 return LDB_SUCCESS;
417         }
418
419         first_component_val = ldb_dn_get_component_val(dn, 0);
420         class_name = (const char *)first_component_val->data;
421
422         schema_class = dsdb_class_by_cn(schema, class_name);
423         if (schema_class == NULL) {
424                 return LDB_SUCCESS;
425         }
426         
427         possibleInferiors = schema_class->possibleInferiors;
428         if (possibleInferiors == NULL) {
429                 return LDB_SUCCESS;
430         }
431
432         for (i=0;possibleInferiors[i];i++) {
433                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
434                 if (ret != LDB_SUCCESS) {
435                         return ret;
436                 }
437         }
438
439         return LDB_SUCCESS;
440 }
441
442
443 /* Add objectClasses, attributeTypes and dITContentRules from the
444    schema object (they are not stored in the database)
445  */
446 static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
447 {
448         struct ldb_context *ldb;
449         struct schema_fsmo_search_data *ac;
450         struct schema_fsmo_private_data *mc;
451         int i, ret;
452
453         ac = talloc_get_type(req->context, struct schema_fsmo_search_data);
454         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_fsmo_private_data);
455         ldb = ldb_module_get_ctx(ac->module);
456
457         if (!ares) {
458                 return ldb_module_done(ac->req, NULL, NULL,
459                                         LDB_ERR_OPERATIONS_ERROR);
460         }
461         if (ares->error != LDB_SUCCESS) {
462                 return ldb_module_done(ac->req, ares->controls,
463                                         ares->response, ares->error);
464         }
465         /* Only entries are interesting, and we handle the case of the parent seperatly */
466
467         switch (ares->type) {
468         case LDB_REPLY_ENTRY:
469
470                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
471                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
472                                 if (generated_attrs[i].aggregate &&
473                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
474                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
475                                         if (ret != LDB_SUCCESS) {
476                                                 return ret;
477                                         }
478                                 }
479                         }
480                 } else {
481                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
482                                 if (!generated_attrs[i].aggregate &&
483                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
484                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
485                                         if (ret != LDB_SUCCESS) {
486                                                 return ret;
487                                         }
488                                 }
489                         }
490                 }
491
492
493                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
494
495         case LDB_REPLY_REFERRAL:
496
497                 return ldb_module_send_referral(ac->req, ares->referral);
498
499         case LDB_REPLY_DONE:
500
501                 return ldb_module_done(ac->req, ares->controls,
502                                         ares->response, ares->error);
503         }
504
505         return LDB_SUCCESS;
506 }
507
508 /* search */
509 static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req)
510 {
511         struct ldb_context *ldb = ldb_module_get_ctx(module);
512         int i, ret;
513         struct schema_fsmo_search_data *search_context;
514         struct ldb_request *down_req;
515         struct dsdb_schema *schema = dsdb_get_schema(ldb);
516
517         if (!schema || !ldb_module_get_private(module)) {
518                 /* If there is no schema, there is little we can do */
519                 return ldb_next_request(module, req);
520         }
521         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
522                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
523                         break;
524                 }
525         }
526         if (i == ARRAY_SIZE(generated_attrs)) {
527                 /* No request for a generated attr found, nothing to
528                  * see here, move along... */
529                 return ldb_next_request(module, req);
530         }
531
532         search_context = talloc(req, struct schema_fsmo_search_data);
533         if (!search_context) {
534                 ldb_oom(ldb);
535                 return LDB_ERR_OPERATIONS_ERROR;
536         }
537
538         search_context->module = module;
539         search_context->req = req;
540         search_context->schema = schema;
541
542         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
543                                         req->op.search.base,
544                                         req->op.search.scope,
545                                         req->op.search.tree,
546                                         req->op.search.attrs,
547                                         req->controls,
548                                         search_context, schema_fsmo_search_callback,
549                                         req);
550         if (ret != LDB_SUCCESS) {
551                 return LDB_ERR_OPERATIONS_ERROR;
552         }
553
554         return ldb_next_request(module, down_req);
555 }
556
557
558 _PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {
559         .name           = "schema_fsmo",
560         .init_context   = schema_fsmo_init,
561         .add            = schema_fsmo_add,
562         .extended       = schema_fsmo_extended,
563         .search         = schema_fsmo_search
564 };