s4/drs: dsdb_map_oid2int() replaced by dsdb_schema_pfm_make_attid()
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / schema_data.c
1 /* 
2    Unix SMB/CIFS mplementation.
3
4    The module that handles the Schema checkings and dynamic attributes
5    
6    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
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 #include "dsdb/samdb/ldb_modules/util.h"
32
33 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
34                                   const struct dsdb_schema *schema);
35 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
36                                    const struct dsdb_schema *schema);
37 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
38                                     const struct dsdb_schema *schema);
39 static int generate_extendedAttributeInfo(struct ldb_context *ldb, struct ldb_message *msg,
40                                           const struct dsdb_schema *schema);
41 static int generate_extendedClassInfo(struct ldb_context *ldb, struct ldb_message *msg,
42                                       const struct dsdb_schema *schema);
43 static int generate_possibleInferiors(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         bool aggregate;
50 } generated_attrs[] = {
51         {
52                 .attr = "objectClasses",
53                 .fn = generate_objectClasses,
54                 .aggregate = true,
55         },
56         {
57                 .attr = "attributeTypes",
58                 .fn = generate_attributeTypes,
59                 .aggregate = true,
60         },
61         {
62                 .attr = "dITContentRules",
63                 .fn = generate_dITContentRules,
64                 .aggregate = true,
65         },
66         {
67                 .attr = "extendedAttributeInfo",
68                 .fn = generate_extendedAttributeInfo,
69                 .aggregate = true,
70         },
71         {
72                 .attr = "extendedClassInfo",
73                 .fn = generate_extendedClassInfo,
74                 .aggregate = true,
75         },
76         {
77                 .attr = "possibleInferiors",
78                 .fn = generate_possibleInferiors,
79                 .aggregate = false,
80         }
81 };
82
83 struct schema_data_private_data {
84         struct ldb_dn *aggregate_dn;
85         struct ldb_dn *schema_dn;
86 };
87
88 struct schema_data_search_data {
89         struct ldb_module *module;
90         struct ldb_request *req;
91
92         const struct dsdb_schema *schema;
93 };
94
95 static int schema_data_init(struct ldb_module *module)
96 {
97         struct ldb_context *ldb;
98         struct ldb_dn *schema_dn;
99         int ret;
100         struct schema_data_private_data *data;
101
102         ret = ldb_next_init(module);
103         if (ret != LDB_SUCCESS) {
104                 return ret;
105         }
106
107         ldb = ldb_module_get_ctx(module);
108         schema_dn = samdb_schema_dn(ldb);
109         if (!schema_dn) {
110                 ldb_reset_err_string(ldb);
111                 ldb_debug(ldb, LDB_DEBUG_WARNING,
112                           "schema_data_init: no schema dn present: (skip schema loading)\n");
113                 return LDB_SUCCESS;
114         }
115
116         data = talloc(module, struct schema_data_private_data);
117         if (data == NULL) {
118                 ldb_oom(ldb);
119                 return LDB_ERR_OPERATIONS_ERROR;
120         }
121
122         /* Check to see if this is a result on the CN=Aggregate schema */
123         data->aggregate_dn = ldb_dn_copy(data, schema_dn);
124         if (!ldb_dn_add_child_fmt(data->aggregate_dn, "CN=Aggregate")) {
125                 ldb_oom(ldb);
126                 return LDB_ERR_OPERATIONS_ERROR;
127         }
128
129         data->schema_dn = schema_dn;
130
131         ldb_module_set_private(module, data);
132         return LDB_SUCCESS;
133 }
134
135 static int schema_data_add(struct ldb_module *module, struct ldb_request *req)
136 {
137         struct ldb_context *ldb;
138         struct dsdb_schema *schema;
139         const struct ldb_val *attributeID = NULL;
140         const struct ldb_val *governsID = NULL;
141         const char *oid_attr = NULL;
142         const char *oid = NULL;
143         uint32_t attid;
144         WERROR status;
145
146         ldb = ldb_module_get_ctx(module);
147
148         /* special objects should always go through */
149         if (ldb_dn_is_special(req->op.add.message->dn)) {
150                 return ldb_next_request(module, req);
151         }
152
153         /* replicated update should always go through */
154         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
155                 return ldb_next_request(module, req);
156         }
157
158         schema = dsdb_get_schema(ldb);
159         if (!schema) {
160                 return ldb_next_request(module, req);
161         }
162
163         if (!schema->fsmo.we_are_master) {
164                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
165                           "schema_data_add: we are not master: reject request\n");
166                 return LDB_ERR_UNWILLING_TO_PERFORM;
167         }
168
169         attributeID = ldb_msg_find_ldb_val(req->op.add.message, "attributeID");
170         governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID");
171
172         if (attributeID) {
173                 oid_attr = "attributeID";
174                 oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length);
175         } else if (governsID) {
176                 oid_attr = "governsID";
177                 oid = talloc_strndup(req, (const char *)governsID->data, governsID->length);
178         } else {
179                 return ldb_next_request(module, req);
180         }
181
182         if (!oid) {
183                 ldb_oom(ldb);
184                 return LDB_ERR_OPERATIONS_ERROR;
185         }
186                 
187         status = dsdb_schema_pfm_make_attid(schema->prefixmap, oid, &attid);
188         if (W_ERROR_IS_OK(status)) {
189                 return ldb_next_request(module, req);
190         } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) {
191                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
192                           "schema_data_add: failed to map %s[%s]: %s\n",
193                           oid_attr, oid, win_errstr(status));
194                 return LDB_ERR_UNWILLING_TO_PERFORM;
195         }
196
197         status = dsdb_create_prefix_mapping(ldb, schema, oid);
198         if (!W_ERROR_IS_OK(status)) {
199                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
200                           "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n",
201                           oid_attr, oid, win_errstr(status));
202                 return LDB_ERR_UNWILLING_TO_PERFORM;
203         }
204
205         return ldb_next_request(module, req);
206 }
207
208 static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg,
209                                   const struct dsdb_schema *schema) 
210 {
211         const struct dsdb_class *sclass;
212         int ret;
213
214         for (sclass = schema->classes; sclass; sclass = sclass->next) {
215                 ret = ldb_msg_add_string(msg, "objectClasses", schema_class_to_description(msg, sclass));
216                 if (ret != LDB_SUCCESS) {
217                         return ret;
218                 }
219         }
220         return LDB_SUCCESS;
221 }
222 static int generate_attributeTypes(struct ldb_context *ldb, struct ldb_message *msg,
223                                   const struct dsdb_schema *schema) 
224 {
225         const struct dsdb_attribute *attribute;
226         int ret;
227         
228         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
229                 ret = ldb_msg_add_string(msg, "attributeTypes", schema_attribute_to_description(msg, attribute));
230                 if (ret != LDB_SUCCESS) {
231                         return ret;
232                 }
233         }
234         return LDB_SUCCESS;
235 }
236
237 static int generate_dITContentRules(struct ldb_context *ldb, struct ldb_message *msg,
238                                     const struct dsdb_schema *schema) 
239 {
240         const struct dsdb_class *sclass;
241         int ret;
242
243         for (sclass = schema->classes; sclass; sclass = sclass->next) {
244                 if (sclass->auxiliaryClass || sclass->systemAuxiliaryClass) {
245                         char *ditcontentrule = schema_class_to_dITContentRule(msg, sclass, schema);
246                         if (!ditcontentrule) {
247                                 ldb_oom(ldb);
248                                 return LDB_ERR_OPERATIONS_ERROR;
249                         }
250                         ret = ldb_msg_add_steal_string(msg, "dITContentRules", ditcontentrule);
251                         if (ret != LDB_SUCCESS) {
252                                 return ret;
253                         }
254                 }
255         }
256         return LDB_SUCCESS;
257 }
258
259 static int generate_extendedAttributeInfo(struct ldb_context *ldb,
260                                           struct ldb_message *msg,
261                                           const struct dsdb_schema *schema)
262 {
263         const struct dsdb_attribute *attribute;
264         int ret;
265
266         for (attribute = schema->attributes; attribute; attribute = attribute->next) {
267                 char *val = schema_attribute_to_extendedInfo(msg, attribute);
268                 if (!val) {
269                         ldb_oom(ldb);
270                         return LDB_ERR_OPERATIONS_ERROR;
271                 }
272
273                 ret = ldb_msg_add_string(msg, "extendedAttributeInfo", val);
274                 if (ret != LDB_SUCCESS) {
275                         return ret;
276                 }
277         }
278
279         return LDB_SUCCESS;
280 }
281
282 static int generate_extendedClassInfo(struct ldb_context *ldb,
283                                       struct ldb_message *msg,
284                                       const struct dsdb_schema *schema)
285 {
286         const struct dsdb_class *sclass;
287         int ret;
288
289         for (sclass = schema->classes; sclass; sclass = sclass->next) {
290                 char *val = schema_class_to_extendedInfo(msg, sclass);
291                 if (!val) {
292                         ldb_oom(ldb);
293                         return LDB_ERR_OPERATIONS_ERROR;
294                 }
295
296                 ret = ldb_msg_add_string(msg, "extendedClassInfo", val);
297                 if (ret != LDB_SUCCESS) {
298                         return ret;
299                 }
300         }
301
302         return LDB_SUCCESS;
303 }
304
305
306 static int generate_possibleInferiors(struct ldb_context *ldb, struct ldb_message *msg,
307                                       const struct dsdb_schema *schema) 
308 {
309         struct ldb_dn *dn = msg->dn;
310         int ret, i;
311         const char *first_component_name = ldb_dn_get_component_name(dn, 0);
312         const struct ldb_val *first_component_val;
313         const struct dsdb_class *schema_class;
314         const char **possibleInferiors;
315
316         if (strcasecmp(first_component_name, "cn") != 0) {
317                 return LDB_SUCCESS;
318         }
319
320         first_component_val = ldb_dn_get_component_val(dn, 0);
321
322         schema_class = dsdb_class_by_cn_ldb_val(schema, first_component_val);
323         if (schema_class == NULL) {
324                 return LDB_SUCCESS;
325         }
326         
327         possibleInferiors = schema_class->possibleInferiors;
328         if (possibleInferiors == NULL) {
329                 return LDB_SUCCESS;
330         }
331
332         for (i=0;possibleInferiors[i];i++) {
333                 ret = ldb_msg_add_string(msg, "possibleInferiors", possibleInferiors[i]);
334                 if (ret != LDB_SUCCESS) {
335                         return ret;
336                 }
337         }
338
339         return LDB_SUCCESS;
340 }
341
342
343 /* Add objectClasses, attributeTypes and dITContentRules from the
344    schema object (they are not stored in the database)
345  */
346 static int schema_data_search_callback(struct ldb_request *req, struct ldb_reply *ares)
347 {
348         struct ldb_context *ldb;
349         struct schema_data_search_data *ac;
350         struct schema_data_private_data *mc;
351         int i, ret;
352
353         ac = talloc_get_type(req->context, struct schema_data_search_data);
354         mc = talloc_get_type(ldb_module_get_private(ac->module), struct schema_data_private_data);
355         ldb = ldb_module_get_ctx(ac->module);
356
357         if (!ares) {
358                 return ldb_module_done(ac->req, NULL, NULL,
359                                         LDB_ERR_OPERATIONS_ERROR);
360         }
361         if (ares->error != LDB_SUCCESS) {
362                 return ldb_module_done(ac->req, ares->controls,
363                                         ares->response, ares->error);
364         }
365         /* Only entries are interesting, and we handle the case of the parent seperatly */
366
367         switch (ares->type) {
368         case LDB_REPLY_ENTRY:
369
370                 if (ldb_dn_compare(ares->message->dn, mc->aggregate_dn) == 0) {
371                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
372                                 if (generated_attrs[i].aggregate &&
373                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
374                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
375                                         if (ret != LDB_SUCCESS) {
376                                                 return ret;
377                                         }
378                                 }
379                         }
380                 } else if ((ldb_dn_compare_base(mc->schema_dn, ares->message->dn) == 0)
381                            && (ldb_dn_compare(mc->schema_dn, ares->message->dn) != 0)) {
382                         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
383                                 if (!generated_attrs[i].aggregate &&
384                                     ldb_attr_in_list(ac->req->op.search.attrs, generated_attrs[i].attr)) {
385                                         ret = generated_attrs[i].fn(ldb, ares->message, ac->schema);
386                                         if (ret != LDB_SUCCESS) {
387                                                 return ret;
388                                         }
389                                 }
390                         }
391                 }
392
393
394                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
395
396         case LDB_REPLY_REFERRAL:
397
398                 return ldb_module_send_referral(ac->req, ares->referral);
399
400         case LDB_REPLY_DONE:
401
402                 return ldb_module_done(ac->req, ares->controls,
403                                         ares->response, ares->error);
404         }
405
406         return LDB_SUCCESS;
407 }
408
409 /* search */
410 static int schema_data_search(struct ldb_module *module, struct ldb_request *req)
411 {
412         struct ldb_context *ldb = ldb_module_get_ctx(module);
413         int i, ret;
414         struct schema_data_search_data *search_context;
415         struct ldb_request *down_req;
416         struct dsdb_schema *schema = dsdb_get_schema(ldb);
417
418         if (!schema || !ldb_module_get_private(module)) {
419                 /* If there is no schema, there is little we can do */
420                 return ldb_next_request(module, req);
421         }
422         for (i=0; i < ARRAY_SIZE(generated_attrs); i++) {
423                 if (ldb_attr_in_list(req->op.search.attrs, generated_attrs[i].attr)) {
424                         break;
425                 }
426         }
427         if (i == ARRAY_SIZE(generated_attrs)) {
428                 /* No request for a generated attr found, nothing to
429                  * see here, move along... */
430                 return ldb_next_request(module, req);
431         }
432
433         search_context = talloc(req, struct schema_data_search_data);
434         if (!search_context) {
435                 ldb_oom(ldb);
436                 return LDB_ERR_OPERATIONS_ERROR;
437         }
438
439         search_context->module = module;
440         search_context->req = req;
441         search_context->schema = schema;
442
443         ret = ldb_build_search_req_ex(&down_req, ldb, search_context,
444                                         req->op.search.base,
445                                         req->op.search.scope,
446                                         req->op.search.tree,
447                                         req->op.search.attrs,
448                                         req->controls,
449                                         search_context, schema_data_search_callback,
450                                         req);
451         if (ret != LDB_SUCCESS) {
452                 return LDB_ERR_OPERATIONS_ERROR;
453         }
454
455         return ldb_next_request(module, down_req);
456 }
457
458
459 _PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = {
460         .name           = "schema_data",
461         .init_context   = schema_data_init,
462         .add            = schema_data_add,
463         .search         = schema_data_search
464 };