s4:dsdb/resolve_oids: check return values in recursion
[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_replace_value(struct ldb_context *ldb,
25                                       struct dsdb_schema *schema,
26                                       const struct dsdb_attribute *a,
27                                       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_SUCCESS;
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_SUCCESS;
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(schema, (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_SUCCESS;
63                 }
64                 *valp = data_blob_string_const(vo->lDAPDisplayName);
65                 return LDB_SUCCESS;
66         case DRSUAPI_ATTRIBUTE_systemMustContain:
67         case DRSUAPI_ATTRIBUTE_systemMayContain:
68         case DRSUAPI_ATTRIBUTE_mustContain:
69         case DRSUAPI_ATTRIBUTE_mayContain:
70                 str = talloc_strndup(schema, (char *)valp->data, valp->length);
71                 if (!str) {
72                         ldb_oom(ldb);
73                         return LDB_ERR_OPERATIONS_ERROR;
74                 }
75                 va = dsdb_attribute_by_attributeID_oid(schema, str);
76                 talloc_free(str);
77                 if (!va) {
78                         return LDB_SUCCESS;
79                 }
80                 *valp = data_blob_string_const(va->lDAPDisplayName);
81                 return LDB_SUCCESS;
82         case DRSUAPI_ATTRIBUTE_governsID:
83         case DRSUAPI_ATTRIBUTE_attributeID:
84         case DRSUAPI_ATTRIBUTE_attributeSyntax:
85                 return LDB_SUCCESS;
86         }
87
88         return LDB_SUCCESS;
89 }
90
91 static int resolve_oids_parse_tree_replace(struct ldb_context *ldb,
92                                            struct dsdb_schema *schema,
93                                            struct ldb_parse_tree *tree)
94 {
95         int i;
96         const struct dsdb_attribute *a = NULL;
97         const char **attrp;
98         const char *p1;
99         const void *p2;
100         struct ldb_val *valp = NULL;
101         int ret;
102
103         switch (tree->operation) {
104         case LDB_OP_AND:
105         case LDB_OP_OR:
106                 for (i=0;i<tree->u.list.num_elements;i++) {
107                         ret = resolve_oids_parse_tree_replace(ldb, schema,
108                                                         tree->u.list.elements[i]);
109                         if (ret != LDB_SUCCESS) {
110                                 return ret;
111                         }
112                 }
113                 return LDB_SUCCESS;
114         case LDB_OP_NOT:
115                 return resolve_oids_parse_tree_replace(ldb, schema,
116                                                 tree->u.isnot.child);
117         case LDB_OP_EQUALITY:
118         case LDB_OP_GREATER:
119         case LDB_OP_LESS:
120         case LDB_OP_APPROX:
121                 attrp = &tree->u.equality.attr;
122                 valp = &tree->u.equality.value;
123                 break;
124         case LDB_OP_SUBSTRING:
125                 attrp = &tree->u.substring.attr;
126                 break;
127         case LDB_OP_PRESENT:
128                 attrp = &tree->u.present.attr;
129                 break;
130         case LDB_OP_EXTENDED:
131                 attrp = &tree->u.extended.attr;
132                 valp = &tree->u.extended.value;
133                 break;
134         default:
135                 return LDB_SUCCESS;
136         }
137
138         p1 = strchr(*attrp, '.');
139
140         if (valp) {
141                 p2 = memchr(valp->data, '.', valp->length);
142         } else {
143                 p2 = NULL;
144         }
145
146         if (!p1 && !p2) {
147                 return LDB_SUCCESS;
148         }
149
150         if (p1) {
151                 a = dsdb_attribute_by_attributeID_oid(schema, *attrp);
152         } else {
153                 a = dsdb_attribute_by_lDAPDisplayName(schema, *attrp);
154         }
155         if (!a) {
156                 return LDB_SUCCESS;
157         }
158
159         *attrp = a->lDAPDisplayName;
160
161         if (!p2) {
162                 return LDB_SUCCESS;
163         }
164
165         if (a->syntax->oMSyntax != 6) {
166                 return LDB_SUCCESS;
167         }
168
169         return resolve_oids_replace_value(ldb, schema, a, valp);
170 }
171
172 static int resolve_oids_element_replace(struct ldb_context *ldb,
173                                         struct dsdb_schema *schema,
174                                         struct ldb_message_element *el)
175 {
176         int i;
177         const struct dsdb_attribute *a = NULL;
178         const char *p1;
179
180         p1 = strchr(el->name, '.');
181
182         if (p1) {
183                 a = dsdb_attribute_by_attributeID_oid(schema, el->name);
184         } else {
185                 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
186         }
187         if (!a) {
188                 return LDB_SUCCESS;
189         }
190
191         el->name = a->lDAPDisplayName;
192
193         for (i=0; i < el->num_values; i++) {
194                 int ret;
195                 ret = resolve_oids_replace_value(ldb, schema, a,
196                                                  &el->values[i]);
197                 if (ret != LDB_SUCCESS) {
198                         return ret;
199                 }
200         }
201
202         return LDB_SUCCESS;
203 }
204
205 static int resolve_oids_message_replace(struct ldb_context *ldb,
206                                         struct dsdb_schema *schema,
207                                         struct ldb_message *msg)
208 {
209         int i;
210
211         for (i=0; i < msg->num_elements; i++) {
212                 int ret;
213                 ret = resolve_oids_element_replace(ldb, schema,
214                                                    &msg->elements[i]);
215                 if (ret != LDB_SUCCESS) {
216                         return ret;
217                 }
218         }
219
220         return LDB_SUCCESS;
221 }
222
223 struct resolve_oids_context {
224         struct ldb_module *module;
225         struct ldb_request *req;
226 };
227
228 static int resolve_oids_callback(struct ldb_request *req, struct ldb_reply *ares)
229 {
230         struct ldb_context *ldb;
231         struct resolve_oids_context *ac;
232
233         ac = talloc_get_type_abort(req->context, struct resolve_oids_context);
234         ldb = ldb_module_get_ctx(ac->module);
235
236         if (!ares) {
237                 return ldb_module_done(ac->req, NULL, NULL,
238                                         LDB_ERR_OPERATIONS_ERROR);
239         }
240         if (ares->error != LDB_SUCCESS) {
241                 return ldb_module_done(ac->req, ares->controls,
242                                         ares->response, ares->error);
243         }
244
245         switch (ares->type) {
246         case LDB_REPLY_ENTRY:
247                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
248
249         case LDB_REPLY_REFERRAL:
250                 return ldb_module_send_referral(ac->req, ares->referral);
251
252         case LDB_REPLY_DONE:
253                 return ldb_module_done(ac->req, ares->controls,
254                                        ares->response, LDB_SUCCESS);
255
256         }
257         return LDB_SUCCESS;
258 }
259
260 static int resolve_oids_search(struct ldb_module *module, struct ldb_request *req)
261 {
262         struct ldb_context *ldb;
263         struct dsdb_schema *schema;
264         struct ldb_parse_tree *tree;
265         struct ldb_request *down_req;
266         struct resolve_oids_context *ac;
267         int ret;
268
269         ldb = ldb_module_get_ctx(module);
270         schema = dsdb_get_schema(ldb);
271
272         if (!schema) {
273                 return ldb_next_request(module, req);
274         }
275
276         /* do not manipulate our control entries */
277         if (ldb_dn_is_special(req->op.search.base)) {
278                 return ldb_next_request(module, req);
279         }
280
281         ac = talloc(req, struct resolve_oids_context);
282         if (ac == NULL) {
283                 ldb_oom(ldb);
284                 return LDB_ERR_OPERATIONS_ERROR;
285         }
286         ac->module = module;
287         ac->req = req;
288
289         tree = ldb_parse_tree_copy_shallow(ac, req->op.search.tree);
290         if (!tree) {
291                 ldb_oom(ldb);
292                 return LDB_ERR_OPERATIONS_ERROR;
293         }
294
295         ret = resolve_oids_parse_tree_replace(ldb, schema,
296                                               tree);
297         if (ret != LDB_SUCCESS) {
298                 return ret;
299         }
300
301         ret = ldb_build_search_req_ex(&down_req, ldb, ac,
302                                       req->op.search.base,
303                                       req->op.search.scope,
304                                       tree,
305                                       req->op.search.attrs,
306                                       req->controls,
307                                       ac, resolve_oids_callback,
308                                       req);
309         if (ret != LDB_SUCCESS) {
310                 return ret;
311         }
312
313         /* go on with the call chain */
314         return ldb_next_request(module, down_req);
315 }
316
317 static int resolve_oids_add(struct ldb_module *module, struct ldb_request *req)
318 {
319         struct ldb_context *ldb;
320         struct dsdb_schema *schema;
321         int ret;
322         struct ldb_message *msg;
323         struct ldb_request *down_req;
324         struct resolve_oids_context *ac;
325
326         ldb = ldb_module_get_ctx(module);
327         schema = dsdb_get_schema(ldb);
328
329         if (!schema) {
330                 return ldb_next_request(module, req);
331         }
332
333         /* do not manipulate our control entries */
334         if (ldb_dn_is_special(req->op.add.message->dn)) {
335                 return ldb_next_request(module, req);
336         }
337
338         ac = talloc(req, struct resolve_oids_context);
339         if (ac == NULL) {
340                 ldb_oom(ldb);
341                 return LDB_ERR_OPERATIONS_ERROR;
342         }
343         ac->module = module;
344         ac->req = req;
345
346         msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
347         if (!msg) {
348                 ldb_oom(ldb);
349                 return LDB_ERR_OPERATIONS_ERROR;
350         }
351
352         ret = resolve_oids_message_replace(ldb, schema, msg);
353         if (ret != LDB_SUCCESS) {
354                 return ret;
355         }
356
357         ret = ldb_build_add_req(&down_req, ldb, ac,
358                                 msg,
359                                 req->controls,
360                                 ac, resolve_oids_callback,
361                                 req);
362         if (ret != LDB_SUCCESS) {
363                 return ret;
364         }
365
366         /* go on with the call chain */
367         return ldb_next_request(module, down_req);
368 }
369
370 static int resolve_oids_modify(struct ldb_module *module, struct ldb_request *req)
371 {
372         struct ldb_context *ldb;
373         struct dsdb_schema *schema;
374         int ret;
375         struct ldb_message *msg;
376         struct ldb_request *down_req;
377         struct resolve_oids_context *ac;
378
379         ldb = ldb_module_get_ctx(module);
380         schema = dsdb_get_schema(ldb);
381
382         if (!schema) {
383                 return ldb_next_request(module, req);
384         }
385
386         /* do not manipulate our control entries */
387         if (ldb_dn_is_special(req->op.mod.message->dn)) {
388                 return ldb_next_request(module, req);
389         }
390
391         ac = talloc(req, struct resolve_oids_context);
392         if (ac == NULL) {
393                 ldb_oom(ldb);
394                 return LDB_ERR_OPERATIONS_ERROR;
395         }
396         ac->module = module;
397         ac->req = req;
398
399         /* we have to copy the message as the caller might have it as a const */
400         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
401         if (msg == NULL) {
402                 ldb_oom(ldb);
403                 return LDB_ERR_OPERATIONS_ERROR;
404         }
405
406         ret = resolve_oids_message_replace(ldb, schema, msg);
407         if (ret != LDB_SUCCESS) {
408                 return ret;
409         }
410
411         ret = ldb_build_mod_req(&down_req, ldb, ac,
412                                 msg,
413                                 req->controls,
414                                 ac, resolve_oids_callback,
415                                 req);
416         if (ret != LDB_SUCCESS) {
417                 return ret;
418         }
419
420         /* go on with the call chain */
421         return ldb_next_request(module, down_req);
422 }
423
424 _PUBLIC_ const struct ldb_module_ops ldb_resolve_oids_module_ops = {
425         .name           = "resolve_oids",
426         .search         = resolve_oids_search,
427         .add            = resolve_oids_add,
428         .modify         = resolve_oids_modify,
429 };
430