LDB ASYNC: samba4 modules
[Samba/vfs_proxy.git] / source4 / dsdb / samdb / ldb_modules / schema_fsmo.c
blob56d24a2962859ada27aa34c4a3f233b3c9a25b8a
1 /*
2 Unix SMB/CIFS mplementation.
4 The module that handles the Schema FSMO Role Owner
5 checkings, it also loads the dsdb_schema.
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
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.
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.
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/>.
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"
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);
42 static const struct {
43 const char *attr;
44 int (*fn)(struct ldb_context *, struct ldb_message *, const struct dsdb_schema *);
45 } generated_attrs[] = {
47 .attr = "objectClasses",
48 .fn = generate_objectClasses
51 .attr = "attributeTypes",
52 .fn = generate_attributeTypes
55 .attr = "dITContentRules",
56 .fn = generate_dITContentRules
60 struct schema_fsmo_private_data {
61 struct ldb_dn *aggregate_dn;
64 struct schema_fsmo_search_data {
65 struct ldb_module *module;
66 struct ldb_request *req;
68 const struct dsdb_schema *schema;
71 static int schema_fsmo_init(struct ldb_module *module)
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;
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);
88 data = talloc(module, struct schema_fsmo_private_data);
89 if (data == NULL) {
90 ldb_oom(module->ldb);
91 return LDB_ERR_OPERATIONS_ERROR;
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;
101 module->private_data = data;
103 if (dsdb_get_schema(module->ldb)) {
104 return ldb_next_init(module);
107 mem_ctx = talloc_new(module);
108 if (!mem_ctx) {
109 ldb_oom(module->ldb);
110 return LDB_ERR_OPERATIONS_ERROR;
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);
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);
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;
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;
143 talloc_free(mem_ctx);
144 return ldb_next_init(module);
147 static int schema_fsmo_add(struct ldb_module *module, struct ldb_request *req)
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;
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);
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);
167 schema = dsdb_get_schema(module->ldb);
168 if (!schema) {
169 return ldb_next_request(module, req);
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;
178 attributeID = samdb_result_string(req->op.add.message, "attributeID", NULL);
179 governsID = samdb_result_string(req->op.add.message, "governsID", NULL);
181 if (attributeID) {
182 oid_attr = "attributeID";
183 oid = attributeID;
184 } else if (governsID) {
185 oid_attr = "governsID";
186 oid = governsID;
189 if (!oid) {
190 return ldb_next_request(module, req);
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;
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;
211 return ldb_next_request(module, req);
214 static int schema_fsmo_extended(struct ldb_module *module, struct ldb_request *req)
216 struct ldb_dn *schema_dn;
217 struct dsdb_schema *schema;
218 char *error_string = NULL;
219 int ret;
220 TALLOC_CTX *mem_ctx;
222 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) != 0) {
223 return ldb_next_request(module, req);
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);
234 mem_ctx = talloc_new(module);
235 if (!mem_ctx) {
236 ldb_oom(module->ldb);
237 return LDB_ERR_OPERATIONS_ERROR;
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);
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);
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);
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;
270 talloc_free(mem_ctx);
271 return LDB_SUCCESS;
274 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
275 const struct dsdb_schema *schema)
277 const struct dsdb_class *class;
278 int ret;
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;
286 return LDB_SUCCESS;
288 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
289 const struct dsdb_schema *schema)
291 const struct dsdb_attribute *attribute;
292 int ret;
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;
300 return LDB_SUCCESS;
303 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
304 const struct dsdb_schema *schema)
306 const struct dsdb_class *class;
307 int ret;
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;
316 ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
317 if (ret != LDB_SUCCESS) {
318 return ret;
322 return 0;
327 /* Add objectClasses, attributeTypes and dITContentRules from the
328 schema object (they are not stored in the database)
330 static int schema_fsmo_search_callback(struct ldb_request *req, struct ldb_reply *ares)
332 struct schema_fsmo_search_data *ac;
333 struct schema_fsmo_private_data *mc;
334 int i, ret;
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);
339 if (!ares) {
340 return ldb_module_done(ac->req, NULL, NULL,
341 LDB_ERR_OPERATIONS_ERROR);
343 if (ares->error != LDB_SUCCESS) {
344 return ldb_module_done(ac->req, ares->controls,
345 ares->response, ares->error);
347 /* Only entries are interesting, and we handle the case of the parent seperatly */
349 switch (ares->type) {
350 case LDB_REPLY_ENTRY:
352 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) != 0) {
353 return ldb_module_send_entry(ac->req, ares->message);
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;
365 return ldb_module_send_entry(ac->req, ares->message);
367 case LDB_REPLY_REFERRAL:
369 return ldb_module_send_referral(ac->req, ares->referral);
371 case LDB_REPLY_DONE:
373 return ldb_module_done(ac->req, ares->controls,
374 ares->response, ares->error);
377 return LDB_SUCCESS;
380 /* search */
381 static int schema_fsmo_search(struct ldb_module *module, struct ldb_request *req)
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);
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);
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;
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);
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;
409 search_context->module = module;
410 search_context->req = req;
411 search_context->schema = schema;
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;
425 return ldb_next_request(module, down_req);
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