c18cd2f6f4976559ff7a4a665c015dab07af7c89
[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         return resolve_oids_need_value(ldb, schema, a, valp);
160 }
161
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
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
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_ATTRIBUTE_objectClass:
237         case DRSUAPI_ATTRIBUTE_subClassOf:
238         case DRSUAPI_ATTRIBUTE_auxiliaryClass:
239         case DRSUAPI_ATTRIBUTE_systemPossSuperiors:
240         case DRSUAPI_ATTRIBUTE_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_ATTRIBUTE_systemMustContain:
253         case DRSUAPI_ATTRIBUTE_systemMayContain:
254         case DRSUAPI_ATTRIBUTE_mustContain:
255         case DRSUAPI_ATTRIBUTE_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_ATTRIBUTE_governsID:
268         case DRSUAPI_ATTRIBUTE_attributeID:
269         case DRSUAPI_ATTRIBUTE_attributeSyntax:
270                 return LDB_SUCCESS;
271         }
272
273         return LDB_SUCCESS;
274 }
275
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
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
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
413 static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
414 {
415         struct ldb_context *ldb;
416         struct resolve_oids_context *ac;
417
418         ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
419         ldb = ldb_module_get_ctx(ac->module);
420
421         if (!ares) {
422                 return ldb_module_done(ac->req, NULL, NULL,
423                                         LDB_ERR_OPERATIONS_ERROR);
424         }
425         if (ares->error != LDB_SUCCESS) {
426                 return ldb_module_done(ac->req, ares->controls,
427                                         ares->response, ares->error);
428         }
429
430         switch (ares->type) {
431         case LDB_REPLY_ENTRY:
432                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
433
434         case LDB_REPLY_REFERRAL:
435                 return ldb_module_send_referral(ac->req, ares->referral);
436
437         case LDB_REPLY_DONE:
438                 return ldb_module_done(ac->req, ares->controls,
439                                        ares->response, LDB_SUCCESS);
440
441         }
442         return LDB_SUCCESS;
443 }
444
445 static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
446 {
447         struct ldb_context *ldb;
448         struct dsdb_schema *schema;
449         struct ldb_parse_tree *tree;
450         struct ldb_request *down_req;
451         struct resolve_oids_context *ac;
452         int ret;
453         bool needed = false;
454         const char * const *attrs1;
455         const char **attrs2;
456         unsigned int i;
457
458         ldb = ldb_module_get_ctx(module);
459         schema = dsdb_get_schema(ldb, NULL);
460
461         if (!schema) {
462                 return ldb_next_request(module, req);
463         }
464
465         /* do not manipulate our control entries */
466         if (ldb_dn_is_special(req->op.search.base)) {
467                 return ldb_next_request(module, req);
468         }
469
470         ret = resolve_oids_parse_tree_need(ldb, schema,
471                                            req->op.search.tree);
472         if (ret == LDB_ERR_COMPARE_TRUE) {
473                 needed = true;
474         } else if (ret != LDB_ERR_COMPARE_FALSE) {
475                 return ret;
476         }
477
478         attrs1 = req->op.search.attrs;
479
480         for (i=0; attrs1 && attrs1[i]; i++) {
481                 const char *p;
482                 const struct dsdb_attribute *a;
483
484                 p = strchr(attrs1[i], '.');
485                 if (p == NULL) {
486                         continue;
487                 }
488
489                 a = dsdb_attribute_by_attributeID_oid(schema, attrs1[i]);
490                 if (a == NULL) {
491                         continue;
492                 }
493
494                 needed = true;
495                 break;
496         }
497
498         if (!needed) {
499                 return ldb_next_request(module, req);
500         }
501
502         ac = talloc(req, struct resolve_oids_context);
503         if (ac == NULL) {
504                 return ldb_oom(ldb);
505         }
506         ac->module = module;
507         ac->req = req;
508
509         tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
510         if (!tree) {
511                 return ldb_oom(ldb);
512         }
513
514         schema = talloc_reference(tree, schema);
515         if (!schema) {
516                 return ldb_oom(ldb);
517         }
518
519         ret = resolve_oids_parse_tree_replace(ldb, schema,
520                                               tree);
521         if (ret != LDB_SUCCESS) {
522                 return ret;
523         }
524
525         attrs2 = str_list_copy_const(ac,
526                                      discard_const_p(const char *, req->op.search.attrs));
527         if (req->op.search.attrs && !attrs2) {
528                 return ldb_oom(ldb);
529         }
530
531         for (i=0; attrs2 && attrs2[i]; i++) {
532                 const char *p;
533                 const struct dsdb_attribute *a;
534
535                 p = strchr(attrs2[i], '.');
536                 if (p == NULL) {
537                         continue;
538                 }
539
540                 a = dsdb_attribute_by_attributeID_oid(schema, attrs2[i]);
541                 if (a == NULL) {
542                         continue;
543                 }
544
545                 attrs2[i] = a->lDAPDisplayName;
546         }
547
548         ret = ldb_build_search_req_ex(&down_req, ldb, ac,
549                                       req->op.search.base,
550                                       req->op.search.scope,
551                                       tree,
552                                       attrs2,
553                                       req->controls,
554                                       ac, resolve_oids_callback,
555                                       req);
556         LDB_REQ_SET_LOCATION(down_req);
557         if (ret != LDB_SUCCESS) {
558                 return ret;
559         }
560
561         /* go on with the call chain */
562         return ldb_next_request(module, down_req);
563 }
564
565 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
566 {
567         struct ldb_context *ldb;
568         struct dsdb_schema *schema;
569         int ret;
570         struct ldb_message *msg;
571         struct ldb_request *down_req;
572         struct resolve_oids_context *ac;
573
574         ldb = ldb_module_get_ctx(module);
575         schema = dsdb_get_schema(ldb, NULL);
576
577         if (!schema) {
578                 return ldb_next_request(module, req);
579         }
580
581         /* do not manipulate our control entries */
582         if (ldb_dn_is_special(req->op.add.message->dn)) {
583                 return ldb_next_request(module, req);
584         }
585
586         ret = resolve_oids_message_need(ldb, schema,
587                                         req->op.add.message);
588         if (ret == LDB_ERR_COMPARE_FALSE) {
589                 return ldb_next_request(module, req);
590         } else if (ret != LDB_ERR_COMPARE_TRUE) {
591                 return ret;
592         }
593
594         ac = talloc(req, struct resolve_oids_context);
595         if (ac == NULL) {
596                 return ldb_oom(ldb);
597         }
598         ac->module = module;
599         ac->req = req;
600
601         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
602         if (!msg) {
603                 return ldb_oom(ldb);
604         }
605
606         if (!talloc_reference(msg, schema)) {
607                 return ldb_oom(ldb);
608         }
609
610         ret = resolve_oids_message_replace(ldb, schema, msg);
611         if (ret != LDB_SUCCESS) {
612                 return ret;
613         }
614
615         ret = ldb_build_add_req(&down_req, ldb, ac,
616                                 msg,
617                                 req->controls,
618                                 ac, resolve_oids_callback,
619                                 req);
620         LDB_REQ_SET_LOCATION(down_req);
621         if (ret != LDB_SUCCESS) {
622                 return ret;
623         }
624
625         /* go on with the call chain */
626         return ldb_next_request(module, down_req);
627 }
628
629 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
630 {
631         struct ldb_context *ldb;
632         struct dsdb_schema *schema;
633         int ret;
634         struct ldb_message *msg;
635         struct ldb_request *down_req;
636         struct resolve_oids_context *ac;
637
638         ldb = ldb_module_get_ctx(module);
639         schema = dsdb_get_schema(ldb, NULL);
640
641         if (!schema) {
642                 return ldb_next_request(module, req);
643         }
644
645         /* do not manipulate our control entries */
646         if (ldb_dn_is_special(req->op.mod.message->dn)) {
647                 return ldb_next_request(module, req);
648         }
649
650         ret = resolve_oids_message_need(ldb, schema,
651                                         req->op.mod.message);
652         if (ret == LDB_ERR_COMPARE_FALSE) {
653                 return ldb_next_request(module, req);
654         } else if (ret != LDB_ERR_COMPARE_TRUE) {
655                 return ret;
656         }
657
658         ac = talloc(req, struct resolve_oids_context);
659         if (ac == NULL) {
660                 return ldb_oom(ldb);
661         }
662         ac->module = module;
663         ac->req = req;
664
665         /* we have to copy the message as the caller might have it as a const */
666         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
667         if (msg == NULL) {
668                 return ldb_oom(ldb);
669         }
670
671         if (!talloc_reference(msg, schema)) {
672                 return ldb_oom(ldb);
673         }
674
675         ret = resolve_oids_message_replace(ldb, schema, msg);
676         if (ret != LDB_SUCCESS) {
677                 return ret;
678         }
679
680         ret = ldb_build_mod_req(&down_req, ldb, ac,
681                                 msg,
682                                 req->controls,
683                                 ac, resolve_oids_callback,
684                                 req);
685         LDB_REQ_SET_LOCATION(down_req);
686         if (ret != LDB_SUCCESS) {
687                 return ret;
688         }
689
690         /* go on with the call chain */
691         return ldb_next_request(module, down_req);
692 }
693
694 _PUBLIC_ const struct ldb_module_ops ldb_resolve_oids_module_ops = {
695         .name           = "resolve_oids",
696         .search         = resolve_oids_search,
697         .add            = resolve_oids_add,
698         .modify         = resolve_oids_modify,
699 };
700