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