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