Line data Source code
1 : /*
2 : ldb database mapping module
3 :
4 : Copyright (C) Jelmer Vernooij 2005
5 : Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
6 : Copyright (C) Simo Sorce <idra@samba.org> 2008
7 :
8 : ** NOTE! The following LGPL license applies to the ldb
9 : ** library. This does NOT imply that all of Samba is released
10 : ** under the LGPL
11 :
12 : This library is free software; you can redistribute it and/or
13 : modify it under the terms of the GNU Lesser General Public
14 : License as published by the Free Software Foundation; either
15 : version 3 of the License, or (at your option) any later version.
16 :
17 : This library is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 : Lesser General Public License for more details.
21 :
22 : You should have received a copy of the GNU Lesser General Public
23 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 :
25 : */
26 :
27 : #include "replace.h"
28 : #include "system/filesys.h"
29 : #include "system/time.h"
30 : #include "ldb_map.h"
31 : #include "ldb_map_private.h"
32 :
33 :
34 : /* Mapping message elements
35 : * ======================== */
36 :
37 : /* Map a message element into the remote partition. */
38 0 : static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
39 : {
40 : struct ldb_message_element *el;
41 : unsigned int i;
42 :
43 0 : el = talloc_zero(mem_ctx, struct ldb_message_element);
44 0 : if (el == NULL) {
45 0 : map_oom(module);
46 0 : return NULL;
47 : }
48 :
49 0 : el->num_values = old->num_values;
50 0 : el->values = talloc_array(el, struct ldb_val, el->num_values);
51 0 : if (el->values == NULL) {
52 0 : talloc_free(el);
53 0 : map_oom(module);
54 0 : return NULL;
55 : }
56 :
57 0 : el->name = map_attr_map_local(el, map, old->name);
58 :
59 0 : for (i = 0; i < el->num_values; i++) {
60 0 : el->values[i] = ldb_val_map_local(module, el->values, map, &old->values[i]);
61 : }
62 :
63 0 : return el;
64 : }
65 :
66 : /* Add a message element either to a local or to a remote message,
67 : * depending on whether it goes into the local or remote partition. */
68 0 : static int ldb_msg_el_partition(struct ldb_module *module, enum ldb_request_type optype, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
69 : {
70 0 : const struct ldb_map_context *data = map_get_context(module);
71 0 : const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
72 0 : struct ldb_message_element *el=NULL;
73 0 : struct ldb_context *ldb = ldb_module_get_ctx(module);
74 :
75 : /* Unknown attribute: ignore */
76 0 : if (map == NULL) {
77 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
78 : "Not mapping attribute '%s': no mapping found",
79 0 : old->name);
80 0 : goto local;
81 : }
82 :
83 0 : switch (map->type) {
84 0 : case LDB_MAP_RENDROP:
85 0 : if (optype != LDB_ADD) {
86 : /* do the same as LDB_MAP_RENAME */
87 0 : el = ldb_msg_el_map_local(module, remote, map, old);
88 0 : break;
89 : }
90 :
91 : FALL_THROUGH;
92 : case LDB_MAP_IGNORE:
93 0 : goto local;
94 :
95 0 : case LDB_MAP_CONVERT:
96 0 : if (map->u.convert.convert_local == NULL) {
97 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
98 : "Not mapping attribute '%s': "
99 : "'convert_local' not set",
100 0 : map->local_name);
101 0 : goto local;
102 : }
103 :
104 : FALL_THROUGH;
105 : case LDB_MAP_KEEP:
106 : case LDB_MAP_RENAME:
107 0 : el = ldb_msg_el_map_local(module, remote, map, old);
108 0 : break;
109 :
110 0 : case LDB_MAP_GENERATE:
111 0 : if (map->u.generate.generate_remote == NULL) {
112 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
113 : "Not mapping attribute '%s': "
114 : "'generate_remote' not set",
115 0 : map->local_name);
116 0 : goto local;
117 : }
118 :
119 : /* TODO: if this attr requires context:
120 : * make sure all context attrs are mappable (in 'names')
121 : * make sure all context attrs have already been mapped?
122 : * maybe postpone generation until they have been mapped?
123 : */
124 :
125 0 : map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
126 0 : return 0;
127 : }
128 :
129 0 : if (el == NULL) {
130 0 : return -1;
131 : }
132 :
133 0 : return ldb_msg_add(remote, el, old->flags);
134 :
135 0 : local:
136 0 : el = talloc(local, struct ldb_message_element);
137 0 : if (el == NULL) {
138 0 : map_oom(module);
139 0 : return -1;
140 : }
141 :
142 0 : *el = *old; /* copy the old element */
143 :
144 0 : return ldb_msg_add(local, el, old->flags);
145 : }
146 :
147 : /* Mapping messages
148 : * ================ */
149 :
150 : /* Check whether a message will be (partially) mapped into the remote partition. */
151 0 : static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
152 : {
153 0 : const struct ldb_map_context *data = map_get_context(module);
154 : bool ret;
155 : unsigned int i;
156 :
157 0 : for (i = 0; i < msg->num_elements; i++) {
158 0 : ret = map_attr_check_remote(data, msg->elements[i].name);
159 0 : if (ret) {
160 0 : return ret;
161 : }
162 : }
163 :
164 0 : return false;
165 : }
166 :
167 : /* Split message elements that stay in the local partition from those
168 : * that are mapped into the remote partition. */
169 0 : static int ldb_msg_partition(struct ldb_module *module, enum ldb_request_type optype, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
170 : {
171 : /* const char * const names[]; */
172 : struct ldb_context *ldb;
173 : unsigned int i;
174 : int ret;
175 :
176 0 : ldb = ldb_module_get_ctx(module);
177 :
178 0 : for (i = 0; i < msg->num_elements; i++) {
179 : /* Skip 'IS_MAPPED' */
180 0 : if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
181 0 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
182 : "Skipping attribute '%s'",
183 0 : msg->elements[i].name);
184 0 : continue;
185 : }
186 :
187 0 : ret = ldb_msg_el_partition(module, optype, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
188 0 : if (ret) {
189 0 : return ret;
190 : }
191 : }
192 :
193 0 : return 0;
194 : }
195 :
196 :
197 : static int map_add_do_local(struct map_context *ac);
198 : static int map_modify_do_local(struct map_context *ac);
199 : static int map_delete_do_local(struct map_context *ac);
200 : static int map_rename_do_local(struct map_context *ac);
201 : static int map_rename_do_fixup(struct map_context *ac);
202 : static int map_rename_local_callback(struct ldb_request *req,
203 : struct ldb_reply *ares);
204 :
205 :
206 : /*****************************************************************************
207 : * COMMON INBOUND functions
208 : *****************************************************************************/
209 :
210 : /* Store the DN of a single search result in context. */
211 0 : static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
212 : {
213 : struct ldb_context *ldb;
214 : struct map_context *ac;
215 : int ret;
216 :
217 0 : ac = talloc_get_type(req->context, struct map_context);
218 0 : ldb = ldb_module_get_ctx(ac->module);
219 :
220 0 : if (!ares) {
221 0 : return ldb_module_done(ac->req, NULL, NULL,
222 : LDB_ERR_OPERATIONS_ERROR);
223 : }
224 0 : if (ares->error != LDB_SUCCESS) {
225 0 : return ldb_module_done(ac->req, ares->controls,
226 : ares->response, ares->error);
227 : }
228 :
229 : /* We are interested only in the single reply */
230 0 : switch(ares->type) {
231 0 : case LDB_REPLY_ENTRY:
232 : /* We have already found a remote DN */
233 0 : if (ac->local_dn) {
234 0 : ldb_set_errstring(ldb,
235 : "Too many results!");
236 0 : return ldb_module_done(ac->req, NULL, NULL,
237 : LDB_ERR_OPERATIONS_ERROR);
238 : }
239 :
240 : /* Store local DN */
241 0 : ac->local_dn = talloc_steal(ac, ares->message->dn);
242 0 : break;
243 :
244 0 : case LDB_REPLY_DONE:
245 :
246 0 : switch (ac->req->operation) {
247 0 : case LDB_MODIFY:
248 0 : ret = map_modify_do_local(ac);
249 0 : break;
250 0 : case LDB_DELETE:
251 0 : ret = map_delete_do_local(ac);
252 0 : break;
253 0 : case LDB_RENAME:
254 0 : ret = map_rename_do_local(ac);
255 0 : break;
256 0 : default:
257 : /* if we get here we have definitely a problem */
258 0 : ret = LDB_ERR_OPERATIONS_ERROR;
259 : }
260 0 : if (ret != LDB_SUCCESS) {
261 0 : return ldb_module_done(ac->req, NULL, NULL,
262 : LDB_ERR_OPERATIONS_ERROR);
263 : }
264 :
265 0 : break;
266 0 : default:
267 : /* ignore referrals */
268 0 : break;
269 : }
270 :
271 0 : talloc_free(ares);
272 0 : return LDB_SUCCESS;
273 : }
274 :
275 : /* Build a request to search the local record by its DN. */
276 0 : static int map_search_self_req(struct ldb_request **req,
277 : struct map_context *ac,
278 : struct ldb_dn *dn)
279 : {
280 : /* attrs[] is returned from this function in
281 : * ac->search_req->op.search.attrs, so it must be static, as
282 : * otherwise the compiler can put it on the stack */
283 : static const char * const attrs[] = { IS_MAPPED, NULL };
284 : struct ldb_parse_tree *tree;
285 :
286 : /* Limit search to records with 'IS_MAPPED' present */
287 0 : tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
288 0 : if (tree == NULL) {
289 0 : map_oom(ac->module);
290 0 : return LDB_ERR_OPERATIONS_ERROR;
291 : }
292 :
293 0 : *req = map_search_base_req(ac, dn, attrs, tree,
294 : ac, map_search_self_callback);
295 0 : if (*req == NULL) {
296 0 : return LDB_ERR_OPERATIONS_ERROR;
297 : }
298 :
299 0 : return LDB_SUCCESS;
300 : }
301 :
302 0 : static int map_op_local_callback(struct ldb_request *req,
303 : struct ldb_reply *ares)
304 : {
305 : struct ldb_context *ldb;
306 : struct map_context *ac;
307 : int ret;
308 :
309 0 : ac = talloc_get_type(req->context, struct map_context);
310 0 : ldb = ldb_module_get_ctx(ac->module);
311 :
312 0 : if (!ares) {
313 0 : return ldb_module_done(ac->req, NULL, NULL,
314 : LDB_ERR_OPERATIONS_ERROR);
315 : }
316 0 : if (ares->error != LDB_SUCCESS) {
317 0 : return ldb_module_done(ac->req, ares->controls,
318 : ares->response, ares->error);
319 : }
320 :
321 0 : if (ares->type != LDB_REPLY_DONE) {
322 0 : ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
323 0 : return ldb_module_done(ac->req, NULL, NULL,
324 : LDB_ERR_OPERATIONS_ERROR);
325 : }
326 :
327 : /* Do the remote request. */
328 0 : ret = ldb_next_remote_request(ac->module, ac->remote_req);
329 0 : if (ret != LDB_SUCCESS) {
330 0 : return ldb_module_done(ac->req, NULL, NULL,
331 : LDB_ERR_OPERATIONS_ERROR);
332 : }
333 :
334 0 : return LDB_SUCCESS;
335 : }
336 :
337 0 : static int map_op_remote_callback(struct ldb_request *req,
338 : struct ldb_reply *ares)
339 : {
340 : struct ldb_context *ldb;
341 : struct map_context *ac;
342 :
343 0 : ac = talloc_get_type(req->context, struct map_context);
344 0 : ldb = ldb_module_get_ctx(ac->module);
345 :
346 0 : if (!ares) {
347 0 : return ldb_module_done(ac->req, NULL, NULL,
348 : LDB_ERR_OPERATIONS_ERROR);
349 : }
350 0 : if (ares->error != LDB_SUCCESS) {
351 0 : return ldb_module_done(ac->req, ares->controls,
352 : ares->response, ares->error);
353 : }
354 :
355 0 : if (ares->type != LDB_REPLY_DONE) {
356 0 : ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
357 0 : return ldb_module_done(ac->req, NULL, NULL,
358 : LDB_ERR_OPERATIONS_ERROR);
359 : }
360 :
361 0 : return ldb_module_done(ac->req, ares->controls,
362 : ares->response, ares->error);
363 : }
364 :
365 :
366 : /*****************************************************************************
367 : * ADD operations
368 : *****************************************************************************/
369 :
370 :
371 : /* Add a record. */
372 0 : int ldb_map_add(struct ldb_module *module, struct ldb_request *req)
373 : {
374 0 : const struct ldb_message *msg = req->op.add.message;
375 : struct ldb_context *ldb;
376 : struct map_context *ac;
377 : struct ldb_message *remote_msg;
378 : int ret;
379 :
380 0 : ldb = ldb_module_get_ctx(module);
381 :
382 : /* Do not manipulate our control entries */
383 0 : if (ldb_dn_is_special(msg->dn)) {
384 0 : return ldb_next_request(module, req);
385 : }
386 :
387 : /* No mapping requested (perhaps no DN mapping specified), skip to next module */
388 0 : if (!ldb_dn_check_local(module, msg->dn)) {
389 0 : return ldb_next_request(module, req);
390 : }
391 :
392 : /* No mapping needed, fail */
393 0 : if (!ldb_msg_check_remote(module, msg)) {
394 0 : return LDB_ERR_OPERATIONS_ERROR;
395 : }
396 :
397 : /* Prepare context and handle */
398 0 : ac = map_init_context(module, req);
399 0 : if (ac == NULL) {
400 0 : return LDB_ERR_OPERATIONS_ERROR;
401 : }
402 :
403 :
404 : /* Prepare the local message */
405 0 : ac->local_msg = ldb_msg_new(ac);
406 0 : if (ac->local_msg == NULL) {
407 0 : map_oom(module);
408 0 : return LDB_ERR_OPERATIONS_ERROR;
409 : }
410 0 : ac->local_msg->dn = msg->dn;
411 :
412 : /* Prepare the remote message */
413 0 : remote_msg = ldb_msg_new(ac);
414 0 : if (remote_msg == NULL) {
415 0 : map_oom(module);
416 0 : return LDB_ERR_OPERATIONS_ERROR;
417 : }
418 0 : remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
419 :
420 : /* Split local from remote message */
421 0 : ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
422 :
423 : /* Prepare the remote operation */
424 0 : ret = ldb_build_add_req(&ac->remote_req, ldb,
425 : ac, remote_msg,
426 : req->controls,
427 : ac, map_op_remote_callback,
428 : req);
429 0 : LDB_REQ_SET_LOCATION(ac->remote_req);
430 0 : if (ret != LDB_SUCCESS) {
431 0 : return LDB_ERR_OPERATIONS_ERROR;
432 : }
433 :
434 0 : if ((ac->local_msg->num_elements == 0) ||
435 0 : ( ! map_check_local_db(ac->module))) {
436 : /* No local data or db, just run the remote request */
437 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
438 : }
439 :
440 : /* Store remote DN in 'IS_MAPPED' */
441 : /* TODO: use GUIDs here instead */
442 0 : ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
443 : remote_msg->dn);
444 0 : if (ret != LDB_SUCCESS) {
445 0 : return LDB_ERR_OPERATIONS_ERROR;
446 : }
447 :
448 0 : return map_add_do_local(ac);
449 : }
450 :
451 : /* Add the local record. */
452 0 : static int map_add_do_local(struct map_context *ac)
453 : {
454 : struct ldb_request *local_req;
455 : struct ldb_context *ldb;
456 : int ret;
457 :
458 0 : ldb = ldb_module_get_ctx(ac->module);
459 :
460 : /* Prepare the local operation */
461 0 : ret = ldb_build_add_req(&local_req, ldb, ac,
462 0 : ac->local_msg,
463 0 : ac->req->controls,
464 : ac,
465 : map_op_local_callback,
466 : ac->req);
467 0 : LDB_REQ_SET_LOCATION(local_req);
468 0 : if (ret != LDB_SUCCESS) {
469 0 : return LDB_ERR_OPERATIONS_ERROR;
470 : }
471 0 : return ldb_next_request(ac->module, local_req);
472 : }
473 :
474 : /*****************************************************************************
475 : * MODIFY operations
476 : *****************************************************************************/
477 :
478 : /* Modify a record. */
479 0 : int ldb_map_modify(struct ldb_module *module, struct ldb_request *req)
480 : {
481 0 : const struct ldb_message *msg = req->op.mod.message;
482 0 : struct ldb_request *search_req = NULL;
483 : struct ldb_message *remote_msg;
484 : struct ldb_context *ldb;
485 : struct map_context *ac;
486 : int ret;
487 :
488 0 : ldb = ldb_module_get_ctx(module);
489 :
490 : /* Do not manipulate our control entries */
491 0 : if (ldb_dn_is_special(msg->dn)) {
492 0 : return ldb_next_request(module, req);
493 : }
494 :
495 : /* No mapping requested (perhaps no DN mapping specified), skip to next module */
496 0 : if (!ldb_dn_check_local(module, msg->dn)) {
497 0 : return ldb_next_request(module, req);
498 : }
499 :
500 : /* No mapping needed, skip to next module */
501 : /* TODO: What if the remote part exists, the local doesn't,
502 : * and this request wants to modify local data and thus
503 : * add the local record? */
504 0 : if (!ldb_msg_check_remote(module, msg)) {
505 0 : return LDB_ERR_OPERATIONS_ERROR;
506 : }
507 :
508 : /* Prepare context and handle */
509 0 : ac = map_init_context(module, req);
510 0 : if (ac == NULL) {
511 0 : return LDB_ERR_OPERATIONS_ERROR;
512 : }
513 :
514 : /* Prepare the local message */
515 0 : ac->local_msg = ldb_msg_new(ac);
516 0 : if (ac->local_msg == NULL) {
517 0 : map_oom(module);
518 0 : return LDB_ERR_OPERATIONS_ERROR;
519 : }
520 0 : ac->local_msg->dn = msg->dn;
521 :
522 : /* Prepare the remote message */
523 0 : remote_msg = ldb_msg_new(ac->remote_req);
524 0 : if (remote_msg == NULL) {
525 0 : map_oom(module);
526 0 : return LDB_ERR_OPERATIONS_ERROR;
527 : }
528 0 : remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
529 :
530 : /* Split local from remote message */
531 0 : ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
532 :
533 : /* Prepare the remote operation */
534 0 : ret = ldb_build_mod_req(&ac->remote_req, ldb,
535 : ac, remote_msg,
536 : req->controls,
537 : ac, map_op_remote_callback,
538 : req);
539 0 : LDB_REQ_SET_LOCATION(ac->remote_req);
540 0 : if (ret != LDB_SUCCESS) {
541 0 : return LDB_ERR_OPERATIONS_ERROR;
542 : }
543 :
544 0 : if ((ac->local_msg->num_elements == 0) ||
545 0 : ( ! map_check_local_db(ac->module))) {
546 : /* No local data or db, just run the remote request */
547 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
548 : }
549 :
550 : /* prepare the search operation */
551 0 : ret = map_search_self_req(&search_req, ac, msg->dn);
552 0 : if (ret != LDB_SUCCESS) {
553 0 : return LDB_ERR_OPERATIONS_ERROR;
554 : }
555 :
556 0 : return ldb_next_request(module, search_req);
557 : }
558 :
559 : /* Modify the local record. */
560 0 : static int map_modify_do_local(struct map_context *ac)
561 : {
562 : struct ldb_request *local_req;
563 : struct ldb_context *ldb;
564 : int ret;
565 :
566 0 : ldb = ldb_module_get_ctx(ac->module);
567 :
568 0 : if (ac->local_dn == NULL) {
569 : /* No local record present, add it instead */
570 : /* Add local 'IS_MAPPED' */
571 : /* TODO: use GUIDs here instead */
572 0 : ret = ldb_msg_append_linearized_dn(ac->local_msg, IS_MAPPED,
573 0 : ac->remote_req->op.mod.message->dn,
574 : LDB_FLAG_MOD_ADD);
575 0 : if (ret != 0) {
576 0 : return LDB_ERR_OPERATIONS_ERROR;
577 : }
578 :
579 : /* Prepare the local operation */
580 0 : ret = ldb_build_add_req(&local_req, ldb, ac,
581 0 : ac->local_msg,
582 0 : ac->req->controls,
583 : ac,
584 : map_op_local_callback,
585 : ac->req);
586 0 : LDB_REQ_SET_LOCATION(local_req);
587 0 : if (ret != LDB_SUCCESS) {
588 0 : return LDB_ERR_OPERATIONS_ERROR;
589 : }
590 : } else {
591 : /* Prepare the local operation */
592 0 : ret = ldb_build_mod_req(&local_req, ldb, ac,
593 0 : ac->local_msg,
594 0 : ac->req->controls,
595 : ac,
596 : map_op_local_callback,
597 : ac->req);
598 0 : LDB_REQ_SET_LOCATION(local_req);
599 0 : if (ret != LDB_SUCCESS) {
600 0 : return LDB_ERR_OPERATIONS_ERROR;
601 : }
602 : }
603 :
604 0 : return ldb_next_request(ac->module, local_req);
605 : }
606 :
607 : /*****************************************************************************
608 : * DELETE operations
609 : *****************************************************************************/
610 :
611 : /* Delete a record. */
612 0 : int ldb_map_delete(struct ldb_module *module, struct ldb_request *req)
613 : {
614 : struct ldb_request *search_req;
615 : struct ldb_context *ldb;
616 : struct map_context *ac;
617 : int ret;
618 :
619 0 : ldb = ldb_module_get_ctx(module);
620 :
621 : /* Do not manipulate our control entries */
622 0 : if (ldb_dn_is_special(req->op.del.dn)) {
623 0 : return ldb_next_request(module, req);
624 : }
625 :
626 : /* No mapping requested (perhaps no DN mapping specified).
627 : * Skip to next module */
628 0 : if (!ldb_dn_check_local(module, req->op.del.dn)) {
629 0 : return ldb_next_request(module, req);
630 : }
631 :
632 : /* Prepare context and handle */
633 0 : ac = map_init_context(module, req);
634 0 : if (ac == NULL) {
635 0 : return LDB_ERR_OPERATIONS_ERROR;
636 : }
637 :
638 : /* Prepare the remote operation */
639 0 : ret = ldb_build_del_req(&ac->remote_req, ldb, ac,
640 : ldb_dn_map_local(module, ac, req->op.del.dn),
641 : req->controls,
642 : ac,
643 : map_op_remote_callback,
644 : req);
645 0 : LDB_REQ_SET_LOCATION(ac->remote_req);
646 0 : if (ret != LDB_SUCCESS) {
647 0 : return LDB_ERR_OPERATIONS_ERROR;
648 : }
649 :
650 : /* No local db, just run the remote request */
651 0 : if (!map_check_local_db(ac->module)) {
652 : /* Do the remote request. */
653 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
654 : }
655 :
656 : /* Prepare the search operation */
657 0 : ret = map_search_self_req(&search_req, ac, req->op.del.dn);
658 0 : if (ret != LDB_SUCCESS) {
659 0 : map_oom(module);
660 0 : return LDB_ERR_OPERATIONS_ERROR;
661 : }
662 :
663 0 : return ldb_next_request(module, search_req);
664 : }
665 :
666 : /* Delete the local record. */
667 0 : static int map_delete_do_local(struct map_context *ac)
668 : {
669 : struct ldb_request *local_req;
670 : struct ldb_context *ldb;
671 : int ret;
672 :
673 0 : ldb = ldb_module_get_ctx(ac->module);
674 :
675 : /* No local record, continue remotely */
676 0 : if (ac->local_dn == NULL) {
677 : /* Do the remote request. */
678 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
679 : }
680 :
681 : /* Prepare the local operation */
682 0 : ret = ldb_build_del_req(&local_req, ldb, ac,
683 0 : ac->req->op.del.dn,
684 0 : ac->req->controls,
685 : ac,
686 : map_op_local_callback,
687 : ac->req);
688 0 : LDB_REQ_SET_LOCATION(local_req);
689 0 : if (ret != LDB_SUCCESS) {
690 0 : return LDB_ERR_OPERATIONS_ERROR;
691 : }
692 0 : return ldb_next_request(ac->module, local_req);
693 : }
694 :
695 : /*****************************************************************************
696 : * RENAME operations
697 : *****************************************************************************/
698 :
699 : /* Rename a record. */
700 0 : int ldb_map_rename(struct ldb_module *module, struct ldb_request *req)
701 : {
702 0 : struct ldb_request *search_req = NULL;
703 : struct ldb_context *ldb;
704 : struct map_context *ac;
705 : int ret;
706 :
707 0 : ldb = ldb_module_get_ctx(module);
708 :
709 : /* Do not manipulate our control entries */
710 0 : if (ldb_dn_is_special(req->op.rename.olddn)) {
711 0 : return ldb_next_request(module, req);
712 : }
713 :
714 : /* No mapping requested (perhaps no DN mapping specified).
715 : * Skip to next module */
716 0 : if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
717 0 : (!ldb_dn_check_local(module, req->op.rename.newdn))) {
718 0 : return ldb_next_request(module, req);
719 : }
720 :
721 : /* Rename into/out of the mapped partition requested, bail out */
722 0 : if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
723 0 : !ldb_dn_check_local(module, req->op.rename.newdn)) {
724 0 : return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
725 : }
726 :
727 : /* Prepare context and handle */
728 0 : ac = map_init_context(module, req);
729 0 : if (ac == NULL) {
730 0 : return LDB_ERR_OPERATIONS_ERROR;
731 : }
732 :
733 : /* Prepare the remote operation */
734 0 : ret = ldb_build_rename_req(&ac->remote_req, ldb, ac,
735 : ldb_dn_map_local(module, ac, req->op.rename.olddn),
736 : ldb_dn_map_local(module, ac, req->op.rename.newdn),
737 : req->controls,
738 : ac, map_op_remote_callback,
739 : req);
740 0 : LDB_REQ_SET_LOCATION(ac->remote_req);
741 0 : if (ret != LDB_SUCCESS) {
742 0 : return LDB_ERR_OPERATIONS_ERROR;
743 : }
744 :
745 : /* No local db, just run the remote request */
746 0 : if (!map_check_local_db(ac->module)) {
747 : /* Do the remote request. */
748 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
749 : }
750 :
751 : /* Prepare the search operation */
752 0 : ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
753 0 : if (ret != LDB_SUCCESS) {
754 0 : map_oom(module);
755 0 : return LDB_ERR_OPERATIONS_ERROR;
756 : }
757 :
758 0 : return ldb_next_request(module, search_req);
759 : }
760 :
761 : /* Rename the local record. */
762 0 : static int map_rename_do_local(struct map_context *ac)
763 : {
764 : struct ldb_request *local_req;
765 : struct ldb_context *ldb;
766 : int ret;
767 :
768 0 : ldb = ldb_module_get_ctx(ac->module);
769 :
770 : /* No local record, continue remotely */
771 0 : if (ac->local_dn == NULL) {
772 : /* Do the remote request. */
773 0 : return ldb_next_remote_request(ac->module, ac->remote_req);
774 : }
775 :
776 : /* Prepare the local operation */
777 0 : ret = ldb_build_rename_req(&local_req, ldb, ac,
778 0 : ac->req->op.rename.olddn,
779 0 : ac->req->op.rename.newdn,
780 0 : ac->req->controls,
781 : ac,
782 : map_rename_local_callback,
783 : ac->req);
784 0 : LDB_REQ_SET_LOCATION(local_req);
785 0 : if (ret != LDB_SUCCESS) {
786 0 : return LDB_ERR_OPERATIONS_ERROR;
787 : }
788 :
789 0 : return ldb_next_request(ac->module, local_req);
790 : }
791 :
792 0 : static int map_rename_local_callback(struct ldb_request *req,
793 : struct ldb_reply *ares)
794 : {
795 : struct ldb_context *ldb;
796 : struct map_context *ac;
797 : int ret;
798 :
799 0 : ac = talloc_get_type(req->context, struct map_context);
800 0 : ldb = ldb_module_get_ctx(ac->module);
801 :
802 0 : if (!ares) {
803 0 : return ldb_module_done(ac->req, NULL, NULL,
804 : LDB_ERR_OPERATIONS_ERROR);
805 : }
806 0 : if (ares->error != LDB_SUCCESS) {
807 0 : return ldb_module_done(ac->req, ares->controls,
808 : ares->response, ares->error);
809 : }
810 :
811 0 : if (ares->type != LDB_REPLY_DONE) {
812 0 : ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
813 0 : return ldb_module_done(ac->req, NULL, NULL,
814 : LDB_ERR_OPERATIONS_ERROR);
815 : }
816 :
817 : /* proceed with next step */
818 0 : ret = map_rename_do_fixup(ac);
819 0 : if (ret != LDB_SUCCESS) {
820 0 : return ldb_module_done(ac->req, NULL, NULL,
821 : LDB_ERR_OPERATIONS_ERROR);
822 : }
823 :
824 0 : return LDB_SUCCESS;
825 : }
826 :
827 : /* Update the local 'IS_MAPPED' attribute. */
828 0 : static int map_rename_do_fixup(struct map_context *ac)
829 : {
830 : struct ldb_request *local_req;
831 :
832 : /* Prepare the fixup operation */
833 : /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
834 0 : local_req = map_build_fixup_req(ac,
835 0 : ac->req->op.rename.newdn,
836 0 : ac->remote_req->op.rename.newdn,
837 : ac,
838 : map_op_local_callback);
839 0 : if (local_req == NULL) {
840 0 : return LDB_ERR_OPERATIONS_ERROR;
841 : }
842 :
843 0 : return ldb_next_request(ac->module, local_req);
844 : }
|