s4:torture: Fix memory leak
[Samba.git] / source4 / dsdb / samdb / ldb_modules / resolve_oids.c
blob5c1639671e59d08b077f539f290fa121395df142
1 /*
2 ldb database library
4 Copyright (C) Stefan Metzmacher <metze@samba.org> 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "ldb_module.h"
22 #include "dsdb/samdb/samdb.h"
24 static int resolve_oids_need_value(struct ldb_context *ldb,
25 struct dsdb_schema *schema,
26 const struct dsdb_attribute *a,
27 const struct ldb_val *valp)
29 const struct dsdb_attribute *va = NULL;
30 const struct dsdb_class *vo = NULL;
31 const void *p2;
32 char *str = NULL;
34 if (a->syntax->oMSyntax != 6) {
35 return LDB_ERR_COMPARE_FALSE;
38 if (valp) {
39 p2 = memchr(valp->data, '.', valp->length);
40 } else {
41 p2 = NULL;
44 if (!p2) {
45 return LDB_ERR_COMPARE_FALSE;
48 switch (a->attributeID_id) {
49 case DRSUAPI_ATTID_objectClass:
50 case DRSUAPI_ATTID_subClassOf:
51 case DRSUAPI_ATTID_auxiliaryClass:
52 case DRSUAPI_ATTID_systemPossSuperiors:
53 case DRSUAPI_ATTID_possSuperiors:
54 str = talloc_strndup(ldb, (char *)valp->data, valp->length);
55 if (!str) {
56 return ldb_oom(ldb);
58 vo = dsdb_class_by_governsID_oid(schema, str);
59 talloc_free(str);
60 if (!vo) {
61 return LDB_ERR_COMPARE_FALSE;
63 return LDB_ERR_COMPARE_TRUE;
64 case DRSUAPI_ATTID_systemMustContain:
65 case DRSUAPI_ATTID_systemMayContain:
66 case DRSUAPI_ATTID_mustContain:
67 case DRSUAPI_ATTID_mayContain:
68 str = talloc_strndup(ldb, (char *)valp->data, valp->length);
69 if (!str) {
70 return ldb_oom(ldb);
72 va = dsdb_attribute_by_attributeID_oid(schema, str);
73 talloc_free(str);
74 if (!va) {
75 return LDB_ERR_COMPARE_FALSE;
77 return LDB_ERR_COMPARE_TRUE;
78 case DRSUAPI_ATTID_governsID:
79 case DRSUAPI_ATTID_attributeID:
80 case DRSUAPI_ATTID_attributeSyntax:
81 return LDB_ERR_COMPARE_FALSE;
84 return LDB_ERR_COMPARE_FALSE;
87 static int resolve_oids_parse_tree_need(struct ldb_context *ldb,
88 struct dsdb_schema *schema,
89 const struct ldb_parse_tree *tree)
91 unsigned int i;
92 const struct dsdb_attribute *a = NULL;
93 const char *attr;
94 const char *p1;
95 const void *p2;
96 const struct ldb_val *valp = NULL;
97 int ret;
99 switch (tree->operation) {
100 case LDB_OP_AND:
101 case LDB_OP_OR:
102 for (i=0;i<tree->u.list.num_elements;i++) {
103 ret = resolve_oids_parse_tree_need(ldb, schema,
104 tree->u.list.elements[i]);
105 if (ret != LDB_ERR_COMPARE_FALSE) {
106 return ret;
109 return LDB_ERR_COMPARE_FALSE;
110 case LDB_OP_NOT:
111 return resolve_oids_parse_tree_need(ldb, schema,
112 tree->u.isnot.child);
113 case LDB_OP_EQUALITY:
114 attr = tree->u.equality.attr;
115 valp = &tree->u.equality.value;
116 break;
117 case LDB_OP_GREATER:
118 case LDB_OP_LESS:
119 case LDB_OP_APPROX:
120 attr = tree->u.comparison.attr;
121 valp = &tree->u.comparison.value;
122 break;
123 case LDB_OP_SUBSTRING:
124 attr = tree->u.substring.attr;
125 break;
126 case LDB_OP_PRESENT:
127 attr = tree->u.present.attr;
128 break;
129 case LDB_OP_EXTENDED:
130 attr = tree->u.extended.attr;
131 valp = &tree->u.extended.value;
132 break;
133 default:
134 return LDB_ERR_COMPARE_FALSE;
137 p1 = strchr(attr, '.');
139 if (valp) {
140 p2 = memchr(valp->data, '.', valp->length);
141 } else {
142 p2 = NULL;
145 if (!p1 && !p2) {
146 return LDB_ERR_COMPARE_FALSE;
149 if (p1) {
150 a = dsdb_attribute_by_attributeID_oid(schema, attr);
151 } else {
152 a = dsdb_attribute_by_lDAPDisplayName(schema, attr);
154 if (!a) {
155 return LDB_ERR_COMPARE_FALSE;
158 if (!p2) {
159 return LDB_ERR_COMPARE_FALSE;
162 return resolve_oids_need_value(ldb, schema, a, valp);
165 static int resolve_oids_element_need(struct ldb_context *ldb,
166 struct dsdb_schema *schema,
167 const struct ldb_message_element *el)
169 unsigned int i;
170 const struct dsdb_attribute *a = NULL;
171 const char *p1;
173 p1 = strchr(el->name, '.');
175 if (p1) {
176 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
177 } else {
178 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
180 if (!a) {
181 return LDB_ERR_COMPARE_FALSE;
184 for (i=0; i < el->num_values; i++) {
185 int ret;
186 ret = resolve_oids_need_value(ldb, schema, a,
187 &el->values[i]);
188 if (ret != LDB_ERR_COMPARE_FALSE) {
189 return ret;
193 return LDB_ERR_COMPARE_FALSE;
196 static int resolve_oids_message_need(struct ldb_context *ldb,
197 struct dsdb_schema *schema,
198 const struct ldb_message *msg)
200 unsigned int i;
202 for (i=0; i < msg->num_elements; i++) {
203 int ret;
204 ret = resolve_oids_element_need(ldb, schema,
205 &msg->elements[i]);
206 if (ret != LDB_ERR_COMPARE_FALSE) {
207 return ret;
211 return LDB_ERR_COMPARE_FALSE;
214 static int resolve_oids_replace_value(struct ldb_context *ldb,
215 struct dsdb_schema *schema,
216 const struct dsdb_attribute *a,
217 struct ldb_val *valp)
219 const struct dsdb_attribute *va = NULL;
220 const struct dsdb_class *vo = NULL;
221 const void *p2;
222 char *str = NULL;
224 if (a->syntax->oMSyntax != 6) {
225 return LDB_SUCCESS;
228 if (valp) {
229 p2 = memchr(valp->data, '.', valp->length);
230 } else {
231 p2 = NULL;
234 if (!p2) {
235 return LDB_SUCCESS;
238 switch (a->attributeID_id) {
239 case DRSUAPI_ATTID_objectClass:
240 case DRSUAPI_ATTID_subClassOf:
241 case DRSUAPI_ATTID_auxiliaryClass:
242 case DRSUAPI_ATTID_systemPossSuperiors:
243 case DRSUAPI_ATTID_possSuperiors:
244 str = talloc_strndup(schema, (char *)valp->data, valp->length);
245 if (!str) {
246 return ldb_oom(ldb);
248 vo = dsdb_class_by_governsID_oid(schema, str);
249 talloc_free(str);
250 if (!vo) {
251 return LDB_SUCCESS;
253 *valp = data_blob_string_const(vo->lDAPDisplayName);
254 return LDB_SUCCESS;
255 case DRSUAPI_ATTID_systemMustContain:
256 case DRSUAPI_ATTID_systemMayContain:
257 case DRSUAPI_ATTID_mustContain:
258 case DRSUAPI_ATTID_mayContain:
259 str = talloc_strndup(schema, (char *)valp->data, valp->length);
260 if (!str) {
261 return ldb_oom(ldb);
263 va = dsdb_attribute_by_attributeID_oid(schema, str);
264 talloc_free(str);
265 if (!va) {
266 return LDB_SUCCESS;
268 *valp = data_blob_string_const(va->lDAPDisplayName);
269 return LDB_SUCCESS;
270 case DRSUAPI_ATTID_governsID:
271 case DRSUAPI_ATTID_attributeID:
272 case DRSUAPI_ATTID_attributeSyntax:
273 return LDB_SUCCESS;
276 return LDB_SUCCESS;
279 static int resolve_oids_parse_tree_replace(struct ldb_context *ldb,
280 struct dsdb_schema *schema,
281 struct ldb_parse_tree *tree)
283 unsigned int i;
284 const struct dsdb_attribute *a = NULL;
285 const char **attrp;
286 const char *p1;
287 const void *p2;
288 struct ldb_val *valp = NULL;
289 int ret;
291 switch (tree->operation) {
292 case LDB_OP_AND:
293 case LDB_OP_OR:
294 for (i=0;i<tree->u.list.num_elements;i++) {
295 ret = resolve_oids_parse_tree_replace(ldb, schema,
296 tree->u.list.elements[i]);
297 if (ret != LDB_SUCCESS) {
298 return ret;
301 return LDB_SUCCESS;
302 case LDB_OP_NOT:
303 return resolve_oids_parse_tree_replace(ldb, schema,
304 tree->u.isnot.child);
305 case LDB_OP_EQUALITY:
306 attrp = &tree->u.equality.attr;
307 valp = &tree->u.equality.value;
308 break;
309 case LDB_OP_GREATER:
310 case LDB_OP_LESS:
311 case LDB_OP_APPROX:
312 attrp = &tree->u.comparison.attr;
313 valp = &tree->u.comparison.value;
314 break;
315 case LDB_OP_SUBSTRING:
316 attrp = &tree->u.substring.attr;
317 break;
318 case LDB_OP_PRESENT:
319 attrp = &tree->u.present.attr;
320 break;
321 case LDB_OP_EXTENDED:
322 attrp = &tree->u.extended.attr;
323 valp = &tree->u.extended.value;
324 break;
325 default:
326 return LDB_SUCCESS;
329 p1 = strchr(*attrp, '.');
331 if (valp) {
332 p2 = memchr(valp->data, '.', valp->length);
333 } else {
334 p2 = NULL;
337 if (!p1 && !p2) {
338 return LDB_SUCCESS;
341 if (p1) {
342 a = dsdb_attribute_by_attributeID_oid(schema, *attrp);
343 } else {
344 a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp);
346 if (!a) {
347 return LDB_SUCCESS;
350 *attrp = a->lDAPDisplayName;
352 if (!p2) {
353 return LDB_SUCCESS;
356 if (a->syntax->oMSyntax != 6) {
357 return LDB_SUCCESS;
360 return resolve_oids_replace_value(ldb, schema, a, valp);
363 static int resolve_oids_element_replace(struct ldb_context *ldb,
364 struct dsdb_schema *schema,
365 struct ldb_message_element *el)
367 unsigned int i;
368 const struct dsdb_attribute *a = NULL;
369 const char *p1;
371 p1 = strchr(el->name, '.');
373 if (p1) {
374 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
375 } else {
376 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
378 if (!a) {
379 return LDB_SUCCESS;
382 el->name = a->lDAPDisplayName;
384 for (i=0; i < el->num_values; i++) {
385 int ret;
386 ret = resolve_oids_replace_value(ldb, schema, a,
387 &el->values[i]);
388 if (ret != LDB_SUCCESS) {
389 return ret;
393 return LDB_SUCCESS;
396 static int resolve_oids_message_replace(struct ldb_context *ldb,
397 struct dsdb_schema *schema,
398 struct ldb_message *msg)
400 unsigned int i;
402 for (i=0; i < msg->num_elements; i++) {
403 int ret;
404 ret = resolve_oids_element_replace(ldb, schema,
405 &msg->elements[i]);
406 if (ret != LDB_SUCCESS) {
407 return ret;
411 return LDB_SUCCESS;
414 struct resolve_oids_context {
415 struct ldb_module *module;
416 struct ldb_request *req;
419 static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
421 struct resolve_oids_context *ac;
423 ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
425 if (!ares) {
426 return ldb_module_done(ac->req, NULL, NULL,
427 LDB_ERR_OPERATIONS_ERROR);
429 if (ares->error != LDB_SUCCESS) {
430 return ldb_module_done(ac->req, ares->controls,
431 ares->response, ares->error);
434 switch (ares->type) {
435 case LDB_REPLY_ENTRY:
436 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
438 case LDB_REPLY_REFERRAL:
439 return ldb_module_send_referral(ac->req, ares->referral);
441 case LDB_REPLY_DONE:
442 return ldb_module_done(ac->req, ares->controls,
443 ares->response, LDB_SUCCESS);
446 return LDB_SUCCESS;
449 static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
451 struct ldb_context *ldb;
452 struct dsdb_schema *schema;
453 struct ldb_parse_tree *tree;
454 struct ldb_request *down_req;
455 struct resolve_oids_context *ac;
456 int ret;
457 bool needed = false;
458 const char * const *attrs1;
459 const char **attrs2;
460 unsigned int i;
462 ldb = ldb_module_get_ctx(module);
463 schema = dsdb_get_schema(ldb, NULL);
465 if (!schema) {
466 return ldb_next_request(module, req);
469 /* do not manipulate our control entries */
470 if (ldb_dn_is_special(req->op.search.base)) {
471 return ldb_next_request(module, req);
474 ret = resolve_oids_parse_tree_need(ldb, schema,
475 req->op.search.tree);
476 if (ret == LDB_ERR_COMPARE_TRUE) {
477 needed = true;
478 } else if (ret != LDB_ERR_COMPARE_FALSE) {
479 return ret;
482 attrs1 = req->op.search.attrs;
484 for (i=0; attrs1 && attrs1[i]; i++) {
485 const char *p;
486 const struct dsdb_attribute *a;
488 p = strchr(attrs1[i], '.');
489 if (p == NULL) {
490 continue;
493 a = dsdb_attribute_by_attributeID_oid(schema, attrs1[i]);
494 if (a == NULL) {
495 continue;
498 needed = true;
499 break;
502 if (!needed) {
503 return ldb_next_request(module, req);
506 ac = talloc(req, struct resolve_oids_context);
507 if (ac == NULL) {
508 return ldb_oom(ldb);
510 ac->module = module;
511 ac->req = req;
513 tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
514 if (!tree) {
515 return ldb_oom(ldb);
518 schema = talloc_reference(tree, schema);
519 if (!schema) {
520 return ldb_oom(ldb);
523 ret = resolve_oids_parse_tree_replace(ldb, schema,
524 tree);
525 if (ret != LDB_SUCCESS) {
526 return ret;
529 attrs2 = str_list_copy_const(ac,
530 discard_const_p(const char *, req->op.search.attrs));
531 if (req->op.search.attrs && !attrs2) {
532 return ldb_oom(ldb);
535 for (i=0; attrs2 && attrs2[i]; i++) {
536 const char *p;
537 const struct dsdb_attribute *a;
539 p = strchr(attrs2[i], '.');
540 if (p == NULL) {
541 continue;
544 a = dsdb_attribute_by_attributeID_oid(schema, attrs2[i]);
545 if (a == NULL) {
546 continue;
549 attrs2[i] = a->lDAPDisplayName;
552 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
553 req->op.search.base,
554 req->op.search.scope,
555 tree,
556 attrs2,
557 req->controls,
558 ac, resolve_oids_callback,
559 req);
560 LDB_REQ_SET_LOCATION(down_req);
561 if (ret != LDB_SUCCESS) {
562 return ret;
565 /* go on with the call chain */
566 return ldb_next_request(module, down_req);
569 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
571 struct ldb_context *ldb;
572 struct dsdb_schema *schema;
573 int ret;
574 struct ldb_message *msg;
575 struct ldb_request *down_req;
576 struct resolve_oids_context *ac;
578 ldb = ldb_module_get_ctx(module);
579 schema = dsdb_get_schema(ldb, NULL);
581 if (!schema) {
582 return ldb_next_request(module, req);
585 /* do not manipulate our control entries */
586 if (ldb_dn_is_special(req->op.add.message->dn)) {
587 return ldb_next_request(module, req);
590 ret = resolve_oids_message_need(ldb, schema,
591 req->op.add.message);
592 if (ret == LDB_ERR_COMPARE_FALSE) {
593 return ldb_next_request(module, req);
594 } else if (ret != LDB_ERR_COMPARE_TRUE) {
595 return ret;
598 ac = talloc(req, struct resolve_oids_context);
599 if (ac == NULL) {
600 return ldb_oom(ldb);
602 ac->module = module;
603 ac->req = req;
605 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
606 if (!msg) {
607 return ldb_oom(ldb);
610 if (!talloc_reference(msg, schema)) {
611 return ldb_oom(ldb);
614 ret = resolve_oids_message_replace(ldb, schema, msg);
615 if (ret != LDB_SUCCESS) {
616 return ret;
619 ret = ldb_build_add_req(&down_req, ldb, ac,
620 msg,
621 req->controls,
622 ac, resolve_oids_callback,
623 req);
624 LDB_REQ_SET_LOCATION(down_req);
625 if (ret != LDB_SUCCESS) {
626 return ret;
629 /* go on with the call chain */
630 return ldb_next_request(module, down_req);
633 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
635 struct ldb_context *ldb;
636 struct dsdb_schema *schema;
637 int ret;
638 struct ldb_message *msg;
639 struct ldb_request *down_req;
640 struct resolve_oids_context *ac;
642 ldb = ldb_module_get_ctx(module);
643 schema = dsdb_get_schema(ldb, NULL);
645 if (!schema) {
646 return ldb_next_request(module, req);
649 /* do not manipulate our control entries */
650 if (ldb_dn_is_special(req->op.mod.message->dn)) {
651 return ldb_next_request(module, req);
654 ret = resolve_oids_message_need(ldb, schema,
655 req->op.mod.message);
656 if (ret == LDB_ERR_COMPARE_FALSE) {
657 return ldb_next_request(module, req);
658 } else if (ret != LDB_ERR_COMPARE_TRUE) {
659 return ret;
662 ac = talloc(req, struct resolve_oids_context);
663 if (ac == NULL) {
664 return ldb_oom(ldb);
666 ac->module = module;
667 ac->req = req;
669 /* we have to copy the message as the caller might have it as a const */
670 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
671 if (msg == NULL) {
672 return ldb_oom(ldb);
675 if (!talloc_reference(msg, schema)) {
676 return ldb_oom(ldb);
679 ret = resolve_oids_message_replace(ldb, schema, msg);
680 if (ret != LDB_SUCCESS) {
681 return ret;
684 ret = ldb_build_mod_req(&down_req, ldb, ac,
685 msg,
686 req->controls,
687 ac, resolve_oids_callback,
688 req);
689 LDB_REQ_SET_LOCATION(down_req);
690 if (ret != LDB_SUCCESS) {
691 return ret;
694 /* go on with the call chain */
695 return ldb_next_request(module, down_req);
698 static const struct ldb_module_ops ldb_resolve_oids_module_ops = {
699 .name = "resolve_oids",
700 .search = resolve_oids_search,
701 .add = resolve_oids_add,
702 .modify = resolve_oids_modify,
706 int ldb_resolve_oids_module_init(const char *version)
708 LDB_MODULE_CHECK_VERSION(version);
709 return ldb_register_module(&ldb_resolve_oids_module_ops);