ldb: mark the location of a lot more ldb requests
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / resolve_oids.c
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
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_ATTRIBUTE_objectClass:
50         case DRSUAPI_ATTRIBUTE_subClassOf:
51         case DRSUAPI_ATTRIBUTE_auxiliaryClass:
52         case DRSUAPI_ATTRIBUTE_systemPossSuperiors:
53         case DRSUAPI_ATTRIBUTE_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_ATTRIBUTE_systemMustContain:
65         case DRSUAPI_ATTRIBUTE_systemMayContain:
66         case DRSUAPI_ATTRIBUTE_mustContain:
67         case DRSUAPI_ATTRIBUTE_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_ATTRIBUTE_governsID:
79         case DRSUAPI_ATTRIBUTE_attributeID:
80         case DRSUAPI_ATTRIBUTE_attributeSyntax:
81                 return LDB_ERR_COMPARE_FALSE;
82         }
83
84         return LDB_ERR_COMPARE_FALSE;
85 }
86
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         if (a->syntax->oMSyntax != 6) {
160                 return LDB_ERR_COMPARE_FALSE;
161         }
162
163         return resolve_oids_need_value(ldb, schema, a, valp);
164 }
165
166 static int resolve_oids_element_need(struct ldb_context *ldb,
167                                      struct dsdb_schema *schema,
168                                      const struct ldb_message_element *el)
169 {
170         unsigned int i;
171         const struct dsdb_attribute *a = NULL;
172         const char *p1;
173
174         p1 = strchr(el->name, '.');
175
176         if (p1) {
177                 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
178         } else {
179                 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
180         }
181         if (!a) {
182                 return LDB_ERR_COMPARE_FALSE;
183         }
184
185         for (i=0; i < el->num_values; i++) {
186                 int ret;
187                 ret = resolve_oids_need_value(ldb, schema, a,
188                                               &el->values[i]);
189                 if (ret != LDB_ERR_COMPARE_FALSE) {
190                         return ret;
191                 }
192         }
193
194         return LDB_ERR_COMPARE_FALSE;
195 }
196
197 static int resolve_oids_message_need(struct ldb_context *ldb,
198                                      struct dsdb_schema *schema,
199                                      const struct ldb_message *msg)
200 {
201         int i;
202
203         for (i=0; i < msg->num_elements; i++) {
204                 int ret;
205                 ret = resolve_oids_element_need(ldb, schema,
206                                                 &msg->elements[i]);
207                 if (ret != LDB_ERR_COMPARE_FALSE) {
208                         return ret;
209                 }
210         }
211
212         return LDB_ERR_COMPARE_FALSE;
213 }
214
215 static int resolve_oids_replace_value(struct ldb_context *ldb,
216                                       struct dsdb_schema *schema,
217                                       const struct dsdb_attribute *a,
218                                       struct ldb_val *valp)
219 {
220         const struct dsdb_attribute *va = NULL;
221         const struct dsdb_class *vo = NULL;
222         const void *p2;
223         char *str = NULL;
224
225         if (a->syntax->oMSyntax != 6) {
226                 return LDB_SUCCESS;
227         }
228
229         if (valp) {
230                 p2 = memchr(valp->data, '.', valp->length);
231         } else {
232                 p2 = NULL;
233         }
234
235         if (!p2) {
236                 return LDB_SUCCESS;
237         }
238
239         switch (a->attributeID_id) {
240         case DRSUAPI_ATTRIBUTE_objectClass:
241         case DRSUAPI_ATTRIBUTE_subClassOf:
242         case DRSUAPI_ATTRIBUTE_auxiliaryClass:
243         case DRSUAPI_ATTRIBUTE_systemPossSuperiors:
244         case DRSUAPI_ATTRIBUTE_possSuperiors:
245                 str = talloc_strndup(schema, (char *)valp->data, valp->length);
246                 if (!str) {
247                         return ldb_oom(ldb);
248                 }
249                 vo = dsdb_class_by_governsID_oid(schema, str);
250                 talloc_free(str);
251                 if (!vo) {
252                         return LDB_SUCCESS;
253                 }
254                 *valp = data_blob_string_const(vo->lDAPDisplayName);
255                 return LDB_SUCCESS;
256         case DRSUAPI_ATTRIBUTE_systemMustContain:
257         case DRSUAPI_ATTRIBUTE_systemMayContain:
258         case DRSUAPI_ATTRIBUTE_mustContain:
259         case DRSUAPI_ATTRIBUTE_mayContain:
260                 str = talloc_strndup(schema, (char *)valp->data, valp->length);
261                 if (!str) {
262                         return ldb_oom(ldb);
263                 }
264                 va = dsdb_attribute_by_attributeID_oid(schema, str);
265                 talloc_free(str);
266                 if (!va) {
267                         return LDB_SUCCESS;
268                 }
269                 *valp = data_blob_string_const(va->lDAPDisplayName);
270                 return LDB_SUCCESS;
271         case DRSUAPI_ATTRIBUTE_governsID:
272         case DRSUAPI_ATTRIBUTE_attributeID:
273         case DRSUAPI_ATTRIBUTE_attributeSyntax:
274                 return LDB_SUCCESS;
275         }
276
277         return LDB_SUCCESS;
278 }
279
280 static int resolve_oids_parse_tree_replace(struct ldb_context *ldb,
281                                            struct dsdb_schema *schema,
282                                            struct ldb_parse_tree *tree)
283 {
284         unsigned int i;
285         const struct dsdb_attribute *a = NULL;
286         const char **attrp;
287         const char *p1;
288         const void *p2;
289         struct ldb_val *valp = NULL;
290         int ret;
291
292         switch (tree->operation) {
293         case LDB_OP_AND:
294         case LDB_OP_OR:
295                 for (i=0;i<tree->u.list.num_elements;i++) {
296                         ret = resolve_oids_parse_tree_replace(ldb, schema,
297                                                         tree->u.list.elements[i]);
298                         if (ret != LDB_SUCCESS) {
299                                 return ret;
300                         }
301                 }
302                 return LDB_SUCCESS;
303         case LDB_OP_NOT:
304                 return resolve_oids_parse_tree_replace(ldb, schema,
305                                                 tree->u.isnot.child);
306         case LDB_OP_EQUALITY:
307         case LDB_OP_GREATER:
308         case LDB_OP_LESS:
309         case LDB_OP_APPROX:
310                 attrp = &tree->u.equality.attr;
311                 valp = &tree->u.equality.value;
312                 break;
313         case LDB_OP_SUBSTRING:
314                 attrp = &tree->u.substring.attr;
315                 break;
316         case LDB_OP_PRESENT:
317                 attrp = &tree->u.present.attr;
318                 break;
319         case LDB_OP_EXTENDED:
320                 attrp = &tree->u.extended.attr;
321                 valp = &tree->u.extended.value;
322                 break;
323         default:
324                 return LDB_SUCCESS;
325         }
326
327         p1 = strchr(*attrp, '.');
328
329         if (valp) {
330                 p2 = memchr(valp->data, '.', valp->length);
331         } else {
332                 p2 = NULL;
333         }
334
335         if (!p1 && !p2) {
336                 return LDB_SUCCESS;
337         }
338
339         if (p1) {
340                 a = dsdb_attribute_by_attributeID_oid(schema, *attrp);
341         } else {
342                 a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp);
343         }
344         if (!a) {
345                 return LDB_SUCCESS;
346         }
347
348         *attrp = a->lDAPDisplayName;
349
350         if (!p2) {
351                 return LDB_SUCCESS;
352         }
353
354         if (a->syntax->oMSyntax != 6) {
355                 return LDB_SUCCESS;
356         }
357
358         return resolve_oids_replace_value(ldb, schema, a, valp);
359 }
360
361 static int resolve_oids_element_replace(struct ldb_context *ldb,
362                                         struct dsdb_schema *schema,
363                                         struct ldb_message_element *el)
364 {
365         unsigned int i;
366         const struct dsdb_attribute *a = NULL;
367         const char *p1;
368
369         p1 = strchr(el->name, '.');
370
371         if (p1) {
372                 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
373         } else {
374                 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
375         }
376         if (!a) {
377                 return LDB_SUCCESS;
378         }
379
380         el->name = a->lDAPDisplayName;
381
382         for (i=0; i < el->num_values; i++) {
383                 int ret;
384                 ret = resolve_oids_replace_value(ldb, schema, a,
385                                                  &el->values[i]);
386                 if (ret != LDB_SUCCESS) {
387                         return ret;
388                 }
389         }
390
391         return LDB_SUCCESS;
392 }
393
394 static int resolve_oids_message_replace(struct ldb_context *ldb,
395                                         struct dsdb_schema *schema,
396                                         struct ldb_message *msg)
397 {
398         unsigned int i;
399
400         for (i=0; i < msg->num_elements; i++) {
401                 int ret;
402                 ret = resolve_oids_element_replace(ldb, schema,
403                                                    &msg->elements[i]);
404                 if (ret != LDB_SUCCESS) {
405                         return ret;
406                 }
407         }
408
409         return LDB_SUCCESS;
410 }
411
412 struct resolve_oids_context {
413         struct ldb_module *module;
414         struct ldb_request *req;
415 };
416
417 static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
418 {
419         struct ldb_context *ldb;
420         struct resolve_oids_context *ac;
421
422         ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
423         ldb = ldb_module_get_ctx(ac->module);
424
425         if (!ares) {
426                 return ldb_module_done(ac->req, NULL, NULL,
427                                         LDB_ERR_OPERATIONS_ERROR);
428         }
429         if (ares->error != LDB_SUCCESS) {
430                 return ldb_module_done(ac->req, ares->controls,
431                                         ares->response, ares->error);
432         }
433
434         switch (ares->type) {
435         case LDB_REPLY_ENTRY:
436                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
437
438         case LDB_REPLY_REFERRAL:
439                 return ldb_module_send_referral(ac->req, ares->referral);
440
441         case LDB_REPLY_DONE:
442                 return ldb_module_done(ac->req, ares->controls,
443                                        ares->response, LDB_SUCCESS);
444
445         }
446         return LDB_SUCCESS;
447 }
448
449 static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
450 {
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         uint32_t i;
461
462         ldb = ldb_module_get_ctx(module);
463         schema = dsdb_get_schema(ldb, NULL);
464
465         if (!schema) {
466                 return ldb_next_request(module, req);
467         }
468
469         /* do not manipulate our control entries */
470         if (ldb_dn_is_special(req->op.search.base)) {
471                 return ldb_next_request(module, req);
472         }
473
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;
480         }
481
482         attrs1 = req->op.search.attrs;
483
484         for (i=0; attrs1 && attrs1[i]; i++) {
485                 const char *p;
486                 const struct dsdb_attribute *a;
487
488                 p = strchr(attrs1[i], '.');
489                 if (p == NULL) {
490                         continue;
491                 }
492
493                 a = dsdb_attribute_by_attributeID_oid(schema, attrs1[i]);
494                 if (a == NULL) {
495                         continue;
496                 }
497
498                 needed = true;
499                 break;
500         }
501
502         if (!needed) {
503                 return ldb_next_request(module, req);
504         }
505
506         ac = talloc(req, struct resolve_oids_context);
507         if (ac == NULL) {
508                 return ldb_oom(ldb);
509         }
510         ac->module = module;
511         ac->req = req;
512
513         tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
514         if (!tree) {
515                 return ldb_oom(ldb);
516         }
517
518         schema = talloc_reference(tree, schema);
519         if (!schema) {
520                 return ldb_oom(ldb);
521         }
522
523         ret = resolve_oids_parse_tree_replace(ldb, schema,
524                                               tree);
525         if (ret != LDB_SUCCESS) {
526                 return ret;
527         }
528
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);
533         }
534
535         for (i=0; attrs2 && attrs2[i]; i++) {
536                 const char *p;
537                 const struct dsdb_attribute *a;
538
539                 p = strchr(attrs2[i], '.');
540                 if (p == NULL) {
541                         continue;
542                 }
543
544                 a = dsdb_attribute_by_attributeID_oid(schema, attrs2[i]);
545                 if (a == NULL) {
546                         continue;
547                 }
548
549                 attrs2[i] = a->lDAPDisplayName;
550         }
551
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;
563         }
564
565         /* go on with the call chain */
566         return ldb_next_request(module, down_req);
567 }
568
569 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
570 {
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;
577
578         ldb = ldb_module_get_ctx(module);
579         schema = dsdb_get_schema(ldb, NULL);
580
581         if (!schema) {
582                 return ldb_next_request(module, req);
583         }
584
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);
588         }
589
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;
596         }
597
598         ac = talloc(req, struct resolve_oids_context);
599         if (ac == NULL) {
600                 return ldb_oom(ldb);
601         }
602         ac->module = module;
603         ac->req = req;
604
605         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
606         if (!msg) {
607                 return ldb_oom(ldb);
608         }
609
610         if (!talloc_reference(msg, schema)) {
611                 return ldb_oom(ldb);
612         }
613
614         ret = resolve_oids_message_replace(ldb, schema, msg);
615         if (ret != LDB_SUCCESS) {
616                 return ret;
617         }
618
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;
627         }
628
629         /* go on with the call chain */
630         return ldb_next_request(module, down_req);
631 }
632
633 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
634 {
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;
641
642         ldb = ldb_module_get_ctx(module);
643         schema = dsdb_get_schema(ldb, NULL);
644
645         if (!schema) {
646                 return ldb_next_request(module, req);
647         }
648
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);
652         }
653
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;
660         }
661
662         ac = talloc(req, struct resolve_oids_context);
663         if (ac == NULL) {
664                 return ldb_oom(ldb);
665         }
666         ac->module = module;
667         ac->req = req;
668
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);
673         }
674
675         if (!talloc_reference(msg, schema)) {
676                 return ldb_oom(ldb);
677         }
678
679         ret = resolve_oids_message_replace(ldb, schema, msg);
680         if (ret != LDB_SUCCESS) {
681                 return ret;
682         }
683
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;
692         }
693
694         /* go on with the call chain */
695         return ldb_next_request(module, down_req);
696 }
697
698 _PUBLIC_ 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,
703 };
704