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