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