3c9ebcd74560197e21680f2a4440d22a6c30c3b0
[mat/samba.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         if (ret != LDB_SUCCESS) {
561                 return ret;
562         }
563
564         /* go on with the call chain */
565         return ldb_next_request(module, down_req);
566 }
567
568 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
569 {
570         struct ldb_context *ldb;
571         struct dsdb_schema *schema;
572         int ret;
573         struct ldb_message *msg;
574         struct ldb_request *down_req;
575         struct resolve_oids_context *ac;
576
577         ldb = ldb_module_get_ctx(module);
578         schema = dsdb_get_schema(ldb, NULL);
579
580         if (!schema) {
581                 return ldb_next_request(module, req);
582         }
583
584         /* do not manipulate our control entries */
585         if (ldb_dn_is_special(req->op.add.message->dn)) {
586                 return ldb_next_request(module, req);
587         }
588
589         ret = resolve_oids_message_need(ldb, schema,
590                                         req->op.add.message);
591         if (ret == LDB_ERR_COMPARE_FALSE) {
592                 return ldb_next_request(module, req);
593         } else if (ret != LDB_ERR_COMPARE_TRUE) {
594                 return ret;
595         }
596
597         ac = talloc(req, struct resolve_oids_context);
598         if (ac == NULL) {
599                 return ldb_oom(ldb);
600         }
601         ac->module = module;
602         ac->req = req;
603
604         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
605         if (!msg) {
606                 return ldb_oom(ldb);
607         }
608
609         if (!talloc_reference(msg, schema)) {
610                 return ldb_oom(ldb);
611         }
612
613         ret = resolve_oids_message_replace(ldb, schema, msg);
614         if (ret != LDB_SUCCESS) {
615                 return ret;
616         }
617
618         ret = ldb_build_add_req(&down_req, ldb, ac,
619                                 msg,
620                                 req->controls,
621                                 ac, resolve_oids_callback,
622                                 req);
623         if (ret != LDB_SUCCESS) {
624                 return ret;
625         }
626
627         /* go on with the call chain */
628         return ldb_next_request(module, down_req);
629 }
630
631 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
632 {
633         struct ldb_context *ldb;
634         struct dsdb_schema *schema;
635         int ret;
636         struct ldb_message *msg;
637         struct ldb_request *down_req;
638         struct resolve_oids_context *ac;
639
640         ldb = ldb_module_get_ctx(module);
641         schema = dsdb_get_schema(ldb, NULL);
642
643         if (!schema) {
644                 return ldb_next_request(module, req);
645         }
646
647         /* do not manipulate our control entries */
648         if (ldb_dn_is_special(req->op.mod.message->dn)) {
649                 return ldb_next_request(module, req);
650         }
651
652         ret = resolve_oids_message_need(ldb, schema,
653                                         req->op.mod.message);
654         if (ret == LDB_ERR_COMPARE_FALSE) {
655                 return ldb_next_request(module, req);
656         } else if (ret != LDB_ERR_COMPARE_TRUE) {
657                 return ret;
658         }
659
660         ac = talloc(req, struct resolve_oids_context);
661         if (ac == NULL) {
662                 return ldb_oom(ldb);
663         }
664         ac->module = module;
665         ac->req = req;
666
667         /* we have to copy the message as the caller might have it as a const */
668         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
669         if (msg == NULL) {
670                 return ldb_oom(ldb);
671         }
672
673         if (!talloc_reference(msg, schema)) {
674                 return ldb_oom(ldb);
675         }
676
677         ret = resolve_oids_message_replace(ldb, schema, msg);
678         if (ret != LDB_SUCCESS) {
679                 return ret;
680         }
681
682         ret = ldb_build_mod_req(&down_req, ldb, ac,
683                                 msg,
684                                 req->controls,
685                                 ac, resolve_oids_callback,
686                                 req);
687         if (ret != LDB_SUCCESS) {
688                 return ret;
689         }
690
691         /* go on with the call chain */
692         return ldb_next_request(module, down_req);
693 }
694
695 _PUBLIC_ const struct ldb_module_ops ldb_resolve_oids_module_ops = {
696         .name           = "resolve_oids",
697         .search         = resolve_oids_search,
698         .add            = resolve_oids_add,
699         .modify         = resolve_oids_modify,
700 };
701