Cosmetic corrections for the DSDB module
[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 "lib/ldb/include/ldb.h"
26 #include "lib/ldb/include/ldb_errors.h"
27 #include "lib/ldb/include/ldb_private.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_drsuapi.h"
31 #include "librpc/gen_ndr/ndr_drsblobs.h"
32 #include "../lib/util/dlinklist.h"
33 #include "param/param.h"
34
35 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
36                                   const struct dsdb_schema *schema);
37 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
38                                    const struct dsdb_schema *schema);
39 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
40                                     const struct dsdb_schema *schema);
41
42 static const struct {
43         const char *attr;
44         int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
45 } generated_attrs[] = {
46         {
47                 .attr = "objectClasses",
48                 .fn = generate_objectClasses
49         },
50         {
51                 .attr = "attributeTypes",
52                 .fn = generate_attributeTypes
53         },
54         {
55                 .attr = "dITContentRules",
56                 .fn = generate_dITContentRules
57         }
58 };
59
60 struct schema_fsmo_private_data {
61         struct ldb_dn *aggregate_dn;
62 };
63
64 struct schema_fsmo_search_data {
65         struct ldb_module *module;
66         struct ldb_request *req;
67
68         const struct dsdb_schema *schema;
69 };
70
71 static int schema_fsmo_init(struct ldb_module *module)
72 {
73         TALLOC_CTX *mem_ctx;
74         struct ldb_dn *schema_dn;
75         struct dsdb_schema *schema;
76         char *error_string = NULL;
77         int ret;
78         struct schema_fsmo_private_data *data;
79
80         schema_dn = samdb_schema_dn(module->ldb);
81         if (!schema_dn) {
82                 ldb_reset_err_string(module->ldb);
83                 ldb_debug(module->ldb, LDB_DEBUG_WARNING,
84                           "schema_fsmo_init: no schema dn present: (skip schema loading)\n");
85                 return ldb_next_init(module);
86         }
87
88         data = talloc(module, struct schema_fsmo_private_data);
89         if (data == NULL) {
90                 ldb_oom(module->ldb);
91                 return LDB_ERR_OPERATIONS_ERROR;
92         }
93
94         /* Check to see if this is a result on the CN=Aggregate schema */
95         data->aggregate_dn = ldb_dn_copy(data, schema_dn);
96         if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) {
97                 ldb_oom(module->ldb);
98                 return LDB_ERR_OPERATIONS_ERROR;
99         }
100
101         module->private_data = data;
102
103         if (dsdb_get_schema(module->ldb)) {
104                 return ldb_next_init(module);
105         }
106
107         mem_ctx = talloc_new(module);
108         if (!mem_ctx) {
109                 ldb_oom(module->ldb);
110                 return LDB_ERR_OPERATIONS_ERROR;
111         }
112
113         ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb,
114                                          lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
115                                          schema_dn, &schema, &error_string);
116
117         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
118                 ldb_reset_err_string(module->ldb);
119                 ldb_debug(module->ldb, LDB_DEBUG_WARNING,
120                           "schema_fsmo_init: no schema head present: (skip schema loading)\n");
121                 talloc_free(mem_ctx);
122                 return ldb_next_init(module);
123         }
124
125         if (ret != LDB_SUCCESS) {
126                 ldb_asprintf_errstring(module->ldb, 
127                                        "schema_fsmo_init: dsdb_schema load failed: %s",
128                                        error_string);
129                 talloc_free(mem_ctx);
130                 return ret;
131         }
132
133         /* dsdb_set_schema() steal schema into the ldb_context */
134         ret = dsdb_set_schema(module->ldb, schema);
135         if (ret != LDB_SUCCESS) {
136                 ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
137                               "schema_fsmo_init: dsdb_set_schema() failed: %d:%s",
138                               ret, ldb_strerror(ret));
139                 talloc_free(mem_ctx);
140                 return ret;
141         }
142
143         talloc_free(mem_ctx);
144         return ldb_next_init(module);
145 }
146
147 static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
148 {
149         struct dsdb_schema *schema;
150         const char *attributeID = NULL;
151         const char *governsID = NULL;
152         const char *oid_attr = NULL;
153         const char *oid = NULL;
154         uint32_t id32;
155         WERROR status;
156
157         /* special objects should always go through */
158         if (ldb_dn_is_special(req->op.add.message->dn)) {
159                 return ldb_next_request(module, req);
160         }
161
162         /* replicated update should always go through */
163         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
164                 return ldb_next_request(module, req);
165         }
166
167         schema = dsdb_get_schema(module->ldb);
168         if (!schema) {
169                 return ldb_next_request(module, req);
170         }
171
172         if (!schema->fsmo.we_are_master) {
173                 ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
174                           "schema_fsmo_add: we are not master: reject request\n");
175                 return LDB_ERR_UNWILLING_TO_PERFORM;
176         }
177
178         attributeID = samdb_result_string(req->op.add.message, "attributeID", NULL);
179         governsID = samdb_result_string(req->op.add.message, "governsID", NULL);
180
181         if (attributeID) {
182                 oid_attr = "attributeID";
183                 oid = attributeID;
184         } else if (governsID) {
185                 oid_attr = "governsID";
186                 oid = governsID;
187         }
188
189         if (!oid) {
190                 return ldb_next_request(module, req);
191         }
192
193         status = dsdb_map_oid2int(schema, oid, &id32);
194         if (W_ERROR_IS_OK(status)) {
195                 return ldb_next_request(module, req);
196         } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
197                 ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
198                           "schema_fsmo_add: failed to map %s[%s]: %s\n",
199                           oid_attr, oid, win_errstr(status));
200                 return LDB_ERR_UNWILLING_TO_PERFORM;
201         }
202
203         status = dsdb_create_prefix_mapping(module->ldb, schema, oid);
204         if (!W_ERROR_IS_OK(status)) {
205                 ldb_debug_set(module->ldb, LDB_DEBUG_ERROR,
206                           "schema_fsmo_add: failed to create prefix mapping for %s[%s]: %s\n",
207                           oid_attr, oid, win_errstr(status));
208                 return LDB_ERR_UNWILLING_TO_PERFORM;
209         }
210
211         return ldb_next_request(module, req);
212 }
213
214 static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req)
215 {
216         struct ldb_dn *schema_dn;
217         struct dsdb_schema *schema;
218         char *error_string = NULL;
219         int ret;
220         TALLOC_CTX *mem_ctx;
221         
222         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) {
223                 return ldb_next_request(module, req);
224         }
225         
226         schema_dn = samdb_schema_dn(module->ldb);
227         if (!schema_dn) {
228                 ldb_reset_err_string(module->ldb);
229                 ldb_debug(module->ldb, LDB_DEBUG_WARNING,
230                           "schema_fsmo_extended: no schema dn present: (skip schema loading)\n");
231                 return ldb_next_request(module, req);
232         }
233         
234         mem_ctx = talloc_new(module);
235         if (!mem_ctx) {
236                 ldb_oom(module->ldb);
237                 return LDB_ERR_OPERATIONS_ERROR;
238         }
239         
240         ret = dsdb_schema_from_schema_dn(mem_ctx, module->ldb,
241                                          lp_iconv_convenience(ldb_get_opaque(module->ldb, "loadparm")),
242                                          schema_dn, &schema, &error_string);
243
244         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
245                 ldb_reset_err_string(module->ldb);
246                 ldb_debug(module->ldb, LDB_DEBUG_WARNING,
247                           "schema_fsmo_extended: no schema head present: (skip schema loading)\n");
248                 talloc_free(mem_ctx);
249                 return ldb_next_request(module, req);
250         }
251
252         if (ret != LDB_SUCCESS) {
253                 ldb_asprintf_errstring(module->ldb, 
254                                        "schema_fsmo_extended: dsdb_schema load failed: %s",
255                                        error_string);
256                 talloc_free(mem_ctx);
257                 return ldb_next_request(module, req);
258         }
259
260         /* Replace the old schema*/
261         ret = dsdb_set_schema(module->ldb, schema);
262         if (ret != LDB_SUCCESS) {
263                 ldb_debug_set(module->ldb, LDB_DEBUG_FATAL,
264                               "schema_fsmo_extended: dsdb_set_schema() failed: %d:%s",
265                               ret, ldb_strerror(ret));
266                 talloc_free(mem_ctx);
267                 return ret;
268         }
269
270         talloc_free(mem_ctx);
271         return LDB_SUCCESS;
272 }
273
274 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
275                                   const struct dsdb_schema *schema) 
276 {
277         const struct dsdb_class *class;
278         int ret;
279
280         for (class = schema->classes; class; class = class->next) {
281                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, class));
282                 if (ret != LDB_SUCCESS) {
283                         return ret;
284                 }
285         }
286         return LDB_SUCCESS;
287 }
288 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
289                                   const struct dsdb_schema *schema) 
290 {
291         const struct dsdb_attribute *attribute;
292         int ret;
293         
294         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
295                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
296                 if (ret != LDB_SUCCESS) {
297                         return ret;
298                 }
299         }
300         return LDB_SUCCESS;
301 }
302
303 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
304                                     const struct dsdb_schema *schema) 
305 {
306         const struct dsdb_class *class;
307         int ret;
308
309         for (class = schema->classes; class; class = class->next) {
310                 if (class->auxiliaryClass || class->systemAuxiliaryClass) {
311                         char *ditcontentrule = schema_class_to_dITContentRule(msg, class, schema);
312                         if (!ditcontentrule) {
313                                 ldb_oom(ldb);
314                                 return LDB_ERR_OPERATIONS_ERROR;
315                         }
316                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
317                         if (ret != LDB_SUCCESS) {
318                                 return ret;
319                         }
320                 }
321         }
322         return LDB_SUCCESS;
323 }
324
325
326
327 /* Add objectClasses, attributeTypes and dITContentRules from the
328    schema object (they are not stored in the database)
329  */
330 static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
331 {
332         struct schema_fsmo_search_data *ac;
333         struct schema_fsmo_private_data *mc;
334         int i, ret;
335
336         ac = talloc_get_type(req->context, struct schema_fsmo_search_data);
337         mc = talloc_get_type(ac->module->private_data, struct schema_fsmo_private_data);
338
339         if (!ares) {
340                 return ldb_module_done(ac->req, NULL, NULL,
341                                         LDB_ERR_OPERATIONS_ERROR);
342         }
343         if (ares->error != LDB_SUCCESS) {
344                 return ldb_module_done(ac->req, ares->controls,
345                                         ares->response, ares->error);
346         }
347         /* Only entries are interesting, and we handle the case of the parent seperatly */
348
349         switch (ares->type) {
350         case LDB_REPLY_ENTRY:
351
352                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) != 0) {
353                         return ldb_module_send_entry(ac->req, ares->message);
354                 }
355
356                 for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
357                         if (ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
358                                 ret = generated_attrs[i].fn(ac->module->ldb, ares->message, ac->schema);
359                                 if (ret != LDB_SUCCESS) {
360                                         return ret;
361                                 }
362                         }
363                 }
364
365                 return ldb_module_send_entry(ac->req, ares->message);
366
367         case LDB_REPLY_REFERRAL:
368
369                 return ldb_module_send_referral(ac->req, ares->referral);
370
371         case LDB_REPLY_DONE:
372
373                 return ldb_module_done(ac->req, ares->controls,
374                                         ares->response, ares->error);
375         }
376
377         return LDB_SUCCESS;
378 }
379
380 /* search */
381 static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req)
382 {
383         int i, ret;
384         struct schema_fsmo_search_data *search_context;
385         struct ldb_request *down_req;
386         struct dsdb_schema *schema = dsdb_get_schema(module->ldb);
387
388         if (!schema || !module->private_data) {
389                 /* If there is no schema, there is little we can do */
390                 return ldb_next_request(module, req);
391         }
392         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
393                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
394                         break;
395                 }
396         }
397         if (i == ARRAY_SIZE(generated_attrs)) {
398                 /* No request for a generated attr found, nothing to
399                  * see here, move along... */
400                 return ldb_next_request(module, req);
401         }
402
403         search_context = talloc(req, struct schema_fsmo_search_data);
404         if (!search_context) {
405                 ldb_oom(module->ldb);
406                 return LDB_ERR_OPERATIONS_ERROR;
407         }
408
409         search_context->module = module;
410         search_context->req = req;
411         search_context->schema = schema;
412
413         ret = ldb_build_search_req_ex(&down_req, module->ldb, search_context,
414                                         req->op.search.base,
415                                         req->op.search.scope,
416                                         req->op.search.tree,
417                                         req->op.search.attrs,
418                                         req->controls,
419                                         search_context, schema_fsmo_search_callback,
420                                         req);
421         if (ret != LDB_SUCCESS) {
422                 return LDB_ERR_OPERATIONS_ERROR;
423         }
424
425         return ldb_next_request(module, down_req);
426 }
427
428
429 _PUBLIC_ const struct ldb_module_ops ldb_schema_fsmo_module_ops = {
430         .name           = "schema_fsmo",
431         .init_context   = schema_fsmo_init,
432         .add            = schema_fsmo_add,
433         .extended       = schema_fsmo_extended,
434         .search         = schema_fsmo_search
435 };