1 /*
2 ldb database library
3
4 Copyright (C) Stefan Metzmacher <metze@samba.org> 2009
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "ldb_module.h"
22 #include "dsdb/samdb/samdb.h"
23
resolve_oids_need_value(struct ldb_context * ldb,struct dsdb_schema * schema,const struct dsdb_attribute * a,const struct ldb_val * valp)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)
28 {
29 const struct dsdb_attribute *va = NULL;
30 const struct dsdb_class *vo = NULL;
31 const void *p2;
32 char *str = NULL;
33
34 if (a->syntax->oMSyntax != 6) {
35 return LDB_ERR_COMPARE_FALSE;
36 }
37
38 if (valp) {
39 p2 = memchr(valp->data, '.', valp->length);
40 } else {
41 p2 = NULL;
42 }
43
44 if (!p2) {
45 return LDB_ERR_COMPARE_FALSE;
46 }
47
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);
57 }
58 vo = dsdb_class_by_governsID_oid(schema, str);
59 talloc_free(str);
60 if (!vo) {
61 return LDB_ERR_COMPARE_FALSE;
62 }
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);
71 }
72 va = dsdb_attribute_by_attributeID_oid(schema, str);
73 talloc_free(str);
74 if (!va) {
75 return LDB_ERR_COMPARE_FALSE;
76 }
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;
82 }
83
84 return LDB_ERR_COMPARE_FALSE;
85 }
86
resolve_oids_parse_tree_need(struct ldb_context * ldb,struct dsdb_schema * schema,const struct ldb_parse_tree * tree)87 static int resolve_oids_parse_tree_need(struct ldb_context *ldb,
88 struct dsdb_schema *schema,
89 const struct ldb_parse_tree *tree)
90 {
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;
98
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;
107 }
108 }
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 case LDB_OP_GREATER:
115 case LDB_OP_LESS:
116 case LDB_OP_APPROX:
117 attr = tree->u.equality.attr;
118 valp = &tree->u.equality.value;
119 break;
120 case LDB_OP_SUBSTRING:
121 attr = tree->u.substring.attr;
122 break;
123 case LDB_OP_PRESENT:
124 attr = tree->u.present.attr;
125 break;
126 case LDB_OP_EXTENDED:
127 attr = tree->u.extended.attr;
128 valp = &tree->u.extended.value;
129 break;
130 default:
131 return LDB_ERR_COMPARE_FALSE;
132 }
133
134 p1 = strchr(attr, '.');
135
136 if (valp) {
137 p2 = memchr(valp->data, '.', valp->length);
138 } else {
139 p2 = NULL;
140 }
141
142 if (!p1 && !p2) {
143 return LDB_ERR_COMPARE_FALSE;
144 }
145
146 if (p1) {
147 a = dsdb_attribute_by_attributeID_oid(schema, attr);
148 } else {
149 a = dsdb_attribute_by_lDAPDisplayName(schema, attr);
150 }
151 if (!a) {
152 return LDB_ERR_COMPARE_FALSE;
153 }
154
155 if (!p2) {
156 return LDB_ERR_COMPARE_FALSE;
157 }
158
159 return resolve_oids_need_value(ldb, schema, a, valp);
160 }
161
resolve_oids_element_need(struct ldb_context * ldb,struct dsdb_schema * schema,const struct ldb_message_element * el)162 static int resolve_oids_element_need(struct ldb_context *ldb,
163 struct dsdb_schema *schema,
164 const struct ldb_message_element *el)
165 {
166 unsigned int i;
167 const struct dsdb_attribute *a = NULL;
168 const char *p1;
169
170 p1 = strchr(el->name, '.');
171
172 if (p1) {
173 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
174 } else {
175 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
176 }
177 if (!a) {
178 return LDB_ERR_COMPARE_FALSE;
179 }
180
181 for (i=0; i < el->num_values; i++) {
182 int ret;
183 ret = resolve_oids_need_value(ldb, schema, a,
184 &el->values[i]);
185 if (ret != LDB_ERR_COMPARE_FALSE) {
186 return ret;
187 }
188 }
189
190 return LDB_ERR_COMPARE_FALSE;
191 }
192
resolve_oids_message_need(struct ldb_context * ldb,struct dsdb_schema * schema,const struct ldb_message * msg)193 static int resolve_oids_message_need(struct ldb_context *ldb,
194 struct dsdb_schema *schema,
195 const struct ldb_message *msg)
196 {
197 unsigned int i;
198
199 for (i=0; i < msg->num_elements; i++) {
200 int ret;
201 ret = resolve_oids_element_need(ldb, schema,
202 &msg->elements[i]);
203 if (ret != LDB_ERR_COMPARE_FALSE) {
204 return ret;
205 }
206 }
207
208 return LDB_ERR_COMPARE_FALSE;
209 }
210
resolve_oids_replace_value(struct ldb_context * ldb,struct dsdb_schema * schema,const struct dsdb_attribute * a,struct ldb_val * valp)211 static int resolve_oids_replace_value(struct ldb_context *ldb,
212 struct dsdb_schema *schema,
213 const struct dsdb_attribute *a,
214 struct ldb_val *valp)
215 {
216 const struct dsdb_attribute *va = NULL;
217 const struct dsdb_class *vo = NULL;
218 const void *p2;
219 char *str = NULL;
220
221 if (a->syntax->oMSyntax != 6) {
222 return LDB_SUCCESS;
223 }
224
225 if (valp) {
226 p2 = memchr(valp->data, '.', valp->length);
227 } else {
228 p2 = NULL;
229 }
230
231 if (!p2) {
232 return LDB_SUCCESS;
233 }
234
235 switch (a->attributeID_id) {
236 case DRSUAPI_ATTID_objectClass:
237 case DRSUAPI_ATTID_subClassOf:
238 case DRSUAPI_ATTID_auxiliaryClass:
239 case DRSUAPI_ATTID_systemPossSuperiors:
240 case DRSUAPI_ATTID_possSuperiors:
241 str = talloc_strndup(schema, (char *)valp->data, valp->length);
242 if (!str) {
243 return ldb_oom(ldb);
244 }
245 vo = dsdb_class_by_governsID_oid(schema, str);
246 talloc_free(str);
247 if (!vo) {
248 return LDB_SUCCESS;
249 }
250 *valp = data_blob_string_const(vo->lDAPDisplayName);
251 return LDB_SUCCESS;
252 case DRSUAPI_ATTID_systemMustContain:
253 case DRSUAPI_ATTID_systemMayContain:
254 case DRSUAPI_ATTID_mustContain:
255 case DRSUAPI_ATTID_mayContain:
256 str = talloc_strndup(schema, (char *)valp->data, valp->length);
257 if (!str) {
258 return ldb_oom(ldb);
259 }
260 va = dsdb_attribute_by_attributeID_oid(schema, str);
261 talloc_free(str);
262 if (!va) {
263 return LDB_SUCCESS;
264 }
265 *valp = data_blob_string_const(va->lDAPDisplayName);
266 return LDB_SUCCESS;
267 case DRSUAPI_ATTID_governsID:
268 case DRSUAPI_ATTID_attributeID:
269 case DRSUAPI_ATTID_attributeSyntax:
270 return LDB_SUCCESS;
271 }
272
273 return LDB_SUCCESS;
274 }
275
resolve_oids_parse_tree_replace(struct ldb_context * ldb,struct dsdb_schema * schema,struct ldb_parse_tree * tree)276 static int resolve_oids_parse_tree_replace(struct ldb_context *ldb,
277 struct dsdb_schema *schema,
278 struct ldb_parse_tree *tree)
279 {
280 unsigned int i;
281 const struct dsdb_attribute *a = NULL;
282 const char **attrp;
283 const char *p1;
284 const void *p2;
285 struct ldb_val *valp = NULL;
286 int ret;
287
288 switch (tree->operation) {
289 case LDB_OP_AND:
290 case LDB_OP_OR:
291 for (i=0;i<tree->u.list.num_elements;i++) {
292 ret = resolve_oids_parse_tree_replace(ldb, schema,
293 tree->u.list.elements[i]);
294 if (ret != LDB_SUCCESS) {
295 return ret;
296 }
297 }
298 return LDB_SUCCESS;
299 case LDB_OP_NOT:
300 return resolve_oids_parse_tree_replace(ldb, schema,
301 tree->u.isnot.child);
302 case LDB_OP_EQUALITY:
303 case LDB_OP_GREATER:
304 case LDB_OP_LESS:
305 case LDB_OP_APPROX:
306 attrp = &tree->u.equality.attr;
307 valp = &tree->u.equality.value;
308 break;
309 case LDB_OP_SUBSTRING:
310 attrp = &tree->u.substring.attr;
311 break;
312 case LDB_OP_PRESENT:
313 attrp = &tree->u.present.attr;
314 break;
315 case LDB_OP_EXTENDED:
316 attrp = &tree->u.extended.attr;
317 valp = &tree->u.extended.value;
318 break;
319 default:
320 return LDB_SUCCESS;
321 }
322
323 p1 = strchr(*attrp, '.');
324
325 if (valp) {
326 p2 = memchr(valp->data, '.', valp->length);
327 } else {
328 p2 = NULL;
329 }
330
331 if (!p1 && !p2) {
332 return LDB_SUCCESS;
333 }
334
335 if (p1) {
336 a = dsdb_attribute_by_attributeID_oid(schema, *attrp);
337 } else {
338 a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp);
339 }
340 if (!a) {
341 return LDB_SUCCESS;
342 }
343
344 *attrp = a->lDAPDisplayName;
345
346 if (!p2) {
347 return LDB_SUCCESS;
348 }
349
350 if (a->syntax->oMSyntax != 6) {
351 return LDB_SUCCESS;
352 }
353
354 return resolve_oids_replace_value(ldb, schema, a, valp);
355 }
356
resolve_oids_element_replace(struct ldb_context * ldb,struct dsdb_schema * schema,struct ldb_message_element * el)357 static int resolve_oids_element_replace(struct ldb_context *ldb,
358 struct dsdb_schema *schema,
359 struct ldb_message_element *el)
360 {
361 unsigned int i;
362 const struct dsdb_attribute *a = NULL;
363 const char *p1;
364
365 p1 = strchr(el->name, '.');
366
367 if (p1) {
368 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
369 } else {
370 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
371 }
372 if (!a) {
373 return LDB_SUCCESS;
374 }
375
376 el->name = a->lDAPDisplayName;
377
378 for (i=0; i < el->num_values; i++) {
379 int ret;
380 ret = resolve_oids_replace_value(ldb, schema, a,
381 &el->values[i]);
382 if (ret != LDB_SUCCESS) {
383 return ret;
384 }
385 }
386
387 return LDB_SUCCESS;
388 }
389
resolve_oids_message_replace(struct ldb_context * ldb,struct dsdb_schema * schema,struct ldb_message * msg)390 static int resolve_oids_message_replace(struct ldb_context *ldb,
391 struct dsdb_schema *schema,
392 struct ldb_message *msg)
393 {
394 unsigned int i;
395
396 for (i=0; i < msg->num_elements; i++) {
397 int ret;
398 ret = resolve_oids_element_replace(ldb, schema,
399 &msg->elements[i]);
400 if (ret != LDB_SUCCESS) {
401 return ret;
402 }
403 }
404
405 return LDB_SUCCESS;
406 }
407
408 struct resolve_oids_context {
409 struct ldb_module *module;
410 struct ldb_request *req;
411 };
412
resolve_oids_callback(struct ldb_request * req,struct ldb_reply * ares)413 static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
414 {
415 struct resolve_oids_context *ac;
416
417 ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
418
419 if (!ares) {
420 return ldb_module_done(ac->req, NULL, NULL,
421 LDB_ERR_OPERATIONS_ERROR);
422 }
423 if (ares->error != LDB_SUCCESS) {
424 return ldb_module_done(ac->req, ares->controls,
425 ares->response, ares->error);
426 }
427
428 switch (ares->type) {
429 case LDB_REPLY_ENTRY:
430 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
431
432 case LDB_REPLY_REFERRAL:
433 return ldb_module_send_referral(ac->req, ares->referral);
434
435 case LDB_REPLY_DONE:
436 return ldb_module_done(ac->req, ares->controls,
437 ares->response, LDB_SUCCESS);
438
439 }
440 return LDB_SUCCESS;
441 }
442
resolve_oids_search(struct ldb_module * module,struct ldb_request * req)443 static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
444 {
445 struct ldb_context *ldb;
446 struct dsdb_schema *schema;
447 struct ldb_parse_tree *tree;
448 struct ldb_request *down_req;
449 struct resolve_oids_context *ac;
450 int ret;
451 bool needed = false;
452 const char * const *attrs1;
453 const char **attrs2;
454 unsigned int i;
455
456 ldb = ldb_module_get_ctx(module);
457 schema = dsdb_get_schema(ldb, NULL);
458
459 if (!schema) {
460 return ldb_next_request(module, req);
461 }
462
463 /* do not manipulate our control entries */
464 if (ldb_dn_is_special(req->op.search.base)) {
465 return ldb_next_request(module, req);
466 }
467
468 ret = resolve_oids_parse_tree_need(ldb, schema,
469 req->op.search.tree);
470 if (ret == LDB_ERR_COMPARE_TRUE) {
471 needed = true;
472 } else if (ret != LDB_ERR_COMPARE_FALSE) {
473 return ret;
474 }
475
476 attrs1 = req->op.search.attrs;
477
478 for (i=0; attrs1 && attrs1[i]; i++) {
479 const char *p;
480 const struct dsdb_attribute *a;
481
482 p = strchr(attrs1[i], '.');
483 if (p == NULL) {
484 continue;
485 }
486
487 a = dsdb_attribute_by_attributeID_oid(schema, attrs1[i]);
488 if (a == NULL) {
489 continue;
490 }
491
492 needed = true;
493 break;
494 }
495
496 if (!needed) {
497 return ldb_next_request(module, req);
498 }
499
500 ac = talloc(req, struct resolve_oids_context);
501 if (ac == NULL) {
502 return ldb_oom(ldb);
503 }
504 ac->module = module;
505 ac->req = req;
506
507 tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
508 if (!tree) {
509 return ldb_oom(ldb);
510 }
511
512 schema = talloc_reference(tree, schema);
513 if (!schema) {
514 return ldb_oom(ldb);
515 }
516
517 ret = resolve_oids_parse_tree_replace(ldb, schema,
518 tree);
519 if (ret != LDB_SUCCESS) {
520 return ret;
521 }
522
523 attrs2 = str_list_copy_const(ac,
524 discard_const_p(const char *, req->op.search.attrs));
525 if (req->op.search.attrs && !attrs2) {
526 return ldb_oom(ldb);
527 }
528
529 for (i=0; attrs2 && attrs2[i]; i++) {
530 const char *p;
531 const struct dsdb_attribute *a;
532
533 p = strchr(attrs2[i], '.');
534 if (p == NULL) {
535 continue;
536 }
537
538 a = dsdb_attribute_by_attributeID_oid(schema, attrs2[i]);
539 if (a == NULL) {
540 continue;
541 }
542
543 attrs2[i] = a->lDAPDisplayName;
544 }
545
546 ret = ldb_build_search_req_ex(&down_req, ldb, ac,
547 req->op.search.base,
548 req->op.search.scope,
549 tree,
550 attrs2,
551 req->controls,
552 ac, resolve_oids_callback,
553 req);
554 LDB_REQ_SET_LOCATION(down_req);
555 if (ret != LDB_SUCCESS) {
556 return ret;
557 }
558
559 /* go on with the call chain */
560 return ldb_next_request(module, down_req);
561 }
562
resolve_oids_add(struct ldb_module * module,struct ldb_request * req)563 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
564 {
565 struct ldb_context *ldb;
566 struct dsdb_schema *schema;
567 int ret;
568 struct ldb_message *msg;
569 struct ldb_request *down_req;
570 struct resolve_oids_context *ac;
571
572 ldb = ldb_module_get_ctx(module);
573 schema = dsdb_get_schema(ldb, NULL);
574
575 if (!schema) {
576 return ldb_next_request(module, req);
577 }
578
579 /* do not manipulate our control entries */
580 if (ldb_dn_is_special(req->op.add.message->dn)) {
581 return ldb_next_request(module, req);
582 }
583
584 ret = resolve_oids_message_need(ldb, schema,
585 req->op.add.message);
586 if (ret == LDB_ERR_COMPARE_FALSE) {
587 return ldb_next_request(module, req);
588 } else if (ret != LDB_ERR_COMPARE_TRUE) {
589 return ret;
590 }
591
592 ac = talloc(req, struct resolve_oids_context);
593 if (ac == NULL) {
594 return ldb_oom(ldb);
595 }
596 ac->module = module;
597 ac->req = req;
598
599 msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
600 if (!msg) {
601 return ldb_oom(ldb);
602 }
603
604 if (!talloc_reference(msg, schema)) {
605 return ldb_oom(ldb);
606 }
607
608 ret = resolve_oids_message_replace(ldb, schema, msg);
609 if (ret != LDB_SUCCESS) {
610 return ret;
611 }
612
613 ret = ldb_build_add_req(&down_req, ldb, ac,
614 msg,
615 req->controls,
616 ac, resolve_oids_callback,
617 req);
618 LDB_REQ_SET_LOCATION(down_req);
619 if (ret != LDB_SUCCESS) {
620 return ret;
621 }
622
623 /* go on with the call chain */
624 return ldb_next_request(module, down_req);
625 }
626
resolve_oids_modify(struct ldb_module * module,struct ldb_request * req)627 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
628 {
629 struct ldb_context *ldb;
630 struct dsdb_schema *schema;
631 int ret;
632 struct ldb_message *msg;
633 struct ldb_request *down_req;
634 struct resolve_oids_context *ac;
635
636 ldb = ldb_module_get_ctx(module);
637 schema = dsdb_get_schema(ldb, NULL);
638
639 if (!schema) {
640 return ldb_next_request(module, req);
641 }
642
643 /* do not manipulate our control entries */
644 if (ldb_dn_is_special(req->op.mod.message->dn)) {
645 return ldb_next_request(module, req);
646 }
647
648 ret = resolve_oids_message_need(ldb, schema,
649 req->op.mod.message);
650 if (ret == LDB_ERR_COMPARE_FALSE) {
651 return ldb_next_request(module, req);
652 } else if (ret != LDB_ERR_COMPARE_TRUE) {
653 return ret;
654 }
655
656 ac = talloc(req, struct resolve_oids_context);
657 if (ac == NULL) {
658 return ldb_oom(ldb);
659 }
660 ac->module = module;
661 ac->req = req;
662
663 /* we have to copy the message as the caller might have it as a const */
664 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
665 if (msg == NULL) {
666 return ldb_oom(ldb);
667 }
668
669 if (!talloc_reference(msg, schema)) {
670 return ldb_oom(ldb);
671 }
672
673 ret = resolve_oids_message_replace(ldb, schema, msg);
674 if (ret != LDB_SUCCESS) {
675 return ret;
676 }
677
678 ret = ldb_build_mod_req(&down_req, ldb, ac,
679 msg,
680 req->controls,
681 ac, resolve_oids_callback,
682 req);
683 LDB_REQ_SET_LOCATION(down_req);
684 if (ret != LDB_SUCCESS) {
685 return ret;
686 }
687
688 /* go on with the call chain */
689 return ldb_next_request(module, down_req);
690 }
691
692 static const struct ldb_module_ops ldb_resolve_oids_module_ops = {
693 .name = "resolve_oids",
694 .search = resolve_oids_search,
695 .add = resolve_oids_add,
696 .modify = resolve_oids_modify,
697 };
698
699
ldb_resolve_oids_module_init(const char * version)700 int ldb_resolve_oids_module_init(const char *version)
701 {
702 LDB_MODULE_CHECK_VERSION(version);
703 return ldb_register_module(&ldb_resolve_oids_module_ops);
704 }
705