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 58 : 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 58 : struct ldb_message_element *el;
41 58 : unsigned int i;
42 :
43 58 : el = talloc_zero(mem_ctx, struct ldb_message_element);
44 58 : if (el == NULL) {
45 0 : map_oom(module);
46 0 : return NULL;
47 : }
48 :
49 58 : el->num_values = old->num_values;
50 58 : el->values = talloc_array(el, struct ldb_val, el->num_values);
51 58 : if (el->values == NULL) {
52 0 : talloc_free(el);
53 0 : map_oom(module);
54 0 : return NULL;
55 : }
56 :
57 58 : el->name = map_attr_map_local(el, map, old->name);
58 :
59 113 : for (i = 0; i < el->num_values; i++) {
60 55 : 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 138 : 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 138 : const struct ldb_map_context *data = map_get_context(module);
71 138 : const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
72 138 : struct ldb_message_element *el=NULL;
73 138 : struct ldb_context *ldb = ldb_module_get_ctx(module);
74 :
75 : /* Unknown attribute: ignore */
76 138 : if (map == NULL) {
77 9 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
78 : "Not mapping attribute '%s': no mapping found",
79 9 : old->name);
80 9 : goto local;
81 : }
82 :
83 129 : 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 66 : FALL_THROUGH;
92 : case LDB_MAP_IGNORE:
93 66 : goto local;
94 :
95 12 : case LDB_MAP_CONVERT:
96 12 : if (map->u.convert.convert_local == NULL) {
97 3 : ldb_debug(ldb, LDB_DEBUG_WARNING, "ldb_map: "
98 : "Not mapping attribute '%s': "
99 : "'convert_local' not set",
100 3 : map->local_name);
101 3 : goto local;
102 : }
103 :
104 58 : FALL_THROUGH;
105 : case LDB_MAP_KEEP:
106 : case LDB_MAP_RENAME:
107 58 : el = ldb_msg_el_map_local(module, remote, map, old);
108 58 : break;
109 :
110 2 : case LDB_MAP_GENERATE:
111 2 : 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 2 : map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
126 2 : return 0;
127 : }
128 :
129 58 : if (el == NULL) {
130 0 : return -1;
131 : }
132 :
133 58 : return ldb_msg_add(remote, el, old->flags);
134 :
135 78 : local:
136 78 : el = talloc(local, struct ldb_message_element);
137 78 : if (el == NULL) {
138 0 : map_oom(module);
139 0 : return -1;
140 : }
141 :
142 78 : *el = *old; /* copy the old element */
143 :
144 78 : 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 15 : static bool ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
152 : {
153 15 : const struct ldb_map_context *data = map_get_context(module);
154 15 : bool ret;
155 15 : unsigned int i;
156 :
157 31 : for (i = 0; i < msg->num_elements; i++) {
158 16 : ret = map_attr_check_remote(data, msg->elements[i].name);
159 16 : 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 15 : 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 15 : struct ldb_context *ldb;
173 15 : unsigned int i;
174 15 : int ret;
175 :
176 15 : ldb = ldb_module_get_ctx(module);
177 :
178 168 : for (i = 0; i < msg->num_elements; i++) {
179 : /* Skip 'IS_MAPPED' */
180 138 : 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 138 : ret = ldb_msg_el_partition(module, optype, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
188 138 : 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 33 : static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
212 : {
213 33 : struct ldb_context *ldb;
214 33 : struct map_context *ac;
215 33 : int ret;
216 :
217 33 : ac = talloc_get_type(req->context, struct map_context);
218 33 : ldb = ldb_module_get_ctx(ac->module);
219 :
220 33 : if (!ares) {
221 0 : return ldb_module_done(ac->req, NULL, NULL,
222 : LDB_ERR_OPERATIONS_ERROR);
223 : }
224 33 : 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 33 : switch(ares->type) {
231 14 : case LDB_REPLY_ENTRY:
232 : /* We have already found a remote DN */
233 14 : 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 14 : ac->local_dn = talloc_steal(ac, ares->message->dn);
242 14 : break;
243 :
244 19 : case LDB_REPLY_DONE:
245 :
246 19 : switch (ac->req->operation) {
247 6 : case LDB_MODIFY:
248 6 : ret = map_modify_do_local(ac);
249 6 : break;
250 10 : case LDB_DELETE:
251 10 : ret = map_delete_do_local(ac);
252 10 : break;
253 3 : case LDB_RENAME:
254 3 : ret = map_rename_do_local(ac);
255 3 : break;
256 0 : default:
257 : /* if we get here we have definitely a problem */
258 0 : ret = LDB_ERR_OPERATIONS_ERROR;
259 : }
260 19 : 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 33 : talloc_free(ares);
272 33 : return LDB_SUCCESS;
273 : }
274 :
275 : /* Build a request to search the local record by its DN. */
276 19 : 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 19 : static const char * const attrs[] = { IS_MAPPED, NULL };
284 19 : struct ldb_parse_tree *tree;
285 :
286 : /* Limit search to records with 'IS_MAPPED' present */
287 19 : tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
288 19 : if (tree == NULL) {
289 0 : map_oom(ac->module);
290 0 : return LDB_ERR_OPERATIONS_ERROR;
291 : }
292 :
293 19 : *req = map_search_base_req(ac, dn, attrs, tree,
294 : ac, map_search_self_callback);
295 19 : if (*req == NULL) {
296 0 : return LDB_ERR_OPERATIONS_ERROR;
297 : }
298 :
299 0 : return LDB_SUCCESS;
300 : }
301 :
302 22 : static int map_op_local_callback(struct ldb_request *req,
303 : struct ldb_reply *ares)
304 : {
305 22 : struct ldb_context *ldb;
306 22 : struct map_context *ac;
307 22 : int ret;
308 :
309 22 : ac = talloc_get_type(req->context, struct map_context);
310 22 : ldb = ldb_module_get_ctx(ac->module);
311 :
312 22 : if (!ares) {
313 0 : return ldb_module_done(ac->req, NULL, NULL,
314 : LDB_ERR_OPERATIONS_ERROR);
315 : }
316 22 : if (ares->error != LDB_SUCCESS) {
317 0 : return ldb_module_done(ac->req, ares->controls,
318 : ares->response, ares->error);
319 : }
320 :
321 22 : 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 22 : ret = ldb_next_remote_request(ac->module, ac->remote_req);
329 22 : 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 28 : static int map_op_remote_callback(struct ldb_request *req,
338 : struct ldb_reply *ares)
339 : {
340 28 : struct ldb_context *ldb;
341 28 : struct map_context *ac;
342 :
343 28 : ac = talloc_get_type(req->context, struct map_context);
344 28 : ldb = ldb_module_get_ctx(ac->module);
345 :
346 28 : if (!ares) {
347 0 : return ldb_module_done(ac->req, NULL, NULL,
348 : LDB_ERR_OPERATIONS_ERROR);
349 : }
350 28 : if (ares->error != LDB_SUCCESS) {
351 0 : return ldb_module_done(ac->req, ares->controls,
352 : ares->response, ares->error);
353 : }
354 :
355 28 : 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 28 : 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 8 : int ldb_map_add(struct ldb_module *module, struct ldb_request *req)
373 : {
374 8 : const struct ldb_message *msg = req->op.add.message;
375 8 : struct ldb_context *ldb;
376 8 : struct map_context *ac;
377 8 : struct ldb_message *remote_msg;
378 8 : int ret;
379 :
380 8 : ldb = ldb_module_get_ctx(module);
381 :
382 : /* Do not manipulate our control entries */
383 8 : 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 8 : if (!ldb_dn_check_local(module, msg->dn)) {
389 2 : return ldb_next_request(module, req);
390 : }
391 :
392 : /* No mapping needed, fail */
393 6 : if (!ldb_msg_check_remote(module, msg)) {
394 0 : return LDB_ERR_OPERATIONS_ERROR;
395 : }
396 :
397 : /* Prepare context and handle */
398 6 : ac = map_init_context(module, req);
399 6 : if (ac == NULL) {
400 0 : return LDB_ERR_OPERATIONS_ERROR;
401 : }
402 :
403 :
404 : /* Prepare the local message */
405 6 : ac->local_msg = ldb_msg_new(ac);
406 6 : if (ac->local_msg == NULL) {
407 0 : map_oom(module);
408 0 : return LDB_ERR_OPERATIONS_ERROR;
409 : }
410 6 : ac->local_msg->dn = msg->dn;
411 :
412 : /* Prepare the remote message */
413 6 : remote_msg = ldb_msg_new(ac);
414 6 : if (remote_msg == NULL) {
415 0 : map_oom(module);
416 0 : return LDB_ERR_OPERATIONS_ERROR;
417 : }
418 6 : remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
419 :
420 : /* Split local from remote message */
421 6 : ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
422 :
423 : /* Prepare the remote operation */
424 6 : 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 6 : LDB_REQ_SET_LOCATION(ac->remote_req);
430 6 : if (ret != LDB_SUCCESS) {
431 0 : return LDB_ERR_OPERATIONS_ERROR;
432 : }
433 :
434 12 : if ((ac->local_msg->num_elements == 0) ||
435 6 : ( ! 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 6 : ret = ldb_msg_add_linearized_dn(ac->local_msg, IS_MAPPED,
443 : remote_msg->dn);
444 6 : if (ret != LDB_SUCCESS) {
445 0 : return LDB_ERR_OPERATIONS_ERROR;
446 : }
447 :
448 6 : return map_add_do_local(ac);
449 : }
450 :
451 : /* Add the local record. */
452 6 : static int map_add_do_local(struct map_context *ac)
453 : {
454 6 : struct ldb_request *local_req;
455 6 : struct ldb_context *ldb;
456 6 : int ret;
457 :
458 6 : ldb = ldb_module_get_ctx(ac->module);
459 :
460 : /* Prepare the local operation */
461 12 : ret = ldb_build_add_req(&local_req, ldb, ac,
462 6 : ac->local_msg,
463 0 : ac->req->controls,
464 : ac,
465 : map_op_local_callback,
466 : ac->req);
467 6 : LDB_REQ_SET_LOCATION(local_req);
468 6 : if (ret != LDB_SUCCESS) {
469 0 : return LDB_ERR_OPERATIONS_ERROR;
470 : }
471 6 : return ldb_next_request(ac->module, local_req);
472 : }
473 :
474 : /*****************************************************************************
475 : * MODIFY operations
476 : *****************************************************************************/
477 :
478 : /* Modify a record. */
479 11 : int ldb_map_modify(struct ldb_module *module, struct ldb_request *req)
480 : {
481 11 : const struct ldb_message *msg = req->op.mod.message;
482 11 : struct ldb_request *search_req = NULL;
483 11 : struct ldb_message *remote_msg;
484 11 : struct ldb_context *ldb;
485 11 : struct map_context *ac;
486 11 : int ret;
487 :
488 11 : ldb = ldb_module_get_ctx(module);
489 :
490 : /* Do not manipulate our control entries */
491 11 : 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 11 : if (!ldb_dn_check_local(module, msg->dn)) {
497 2 : 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 9 : if (!ldb_msg_check_remote(module, msg)) {
505 0 : return LDB_ERR_OPERATIONS_ERROR;
506 : }
507 :
508 : /* Prepare context and handle */
509 9 : ac = map_init_context(module, req);
510 9 : if (ac == NULL) {
511 0 : return LDB_ERR_OPERATIONS_ERROR;
512 : }
513 :
514 : /* Prepare the local message */
515 9 : ac->local_msg = ldb_msg_new(ac);
516 9 : if (ac->local_msg == NULL) {
517 0 : map_oom(module);
518 0 : return LDB_ERR_OPERATIONS_ERROR;
519 : }
520 9 : ac->local_msg->dn = msg->dn;
521 :
522 : /* Prepare the remote message */
523 9 : remote_msg = ldb_msg_new(ac->remote_req);
524 9 : if (remote_msg == NULL) {
525 0 : map_oom(module);
526 0 : return LDB_ERR_OPERATIONS_ERROR;
527 : }
528 9 : remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
529 :
530 : /* Split local from remote message */
531 9 : ldb_msg_partition(module, req->operation, ac->local_msg, remote_msg, msg);
532 :
533 : /* Prepare the remote operation */
534 9 : 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 9 : LDB_REQ_SET_LOCATION(ac->remote_req);
540 9 : if (ret != LDB_SUCCESS) {
541 0 : return LDB_ERR_OPERATIONS_ERROR;
542 : }
543 :
544 15 : if ((ac->local_msg->num_elements == 0) ||
545 6 : ( ! map_check_local_db(ac->module))) {
546 : /* No local data or db, just run the remote request */
547 3 : return ldb_next_remote_request(ac->module, ac->remote_req);
548 : }
549 :
550 : /* prepare the search operation */
551 6 : ret = map_search_self_req(&search_req, ac, msg->dn);
552 6 : if (ret != LDB_SUCCESS) {
553 0 : return LDB_ERR_OPERATIONS_ERROR;
554 : }
555 :
556 6 : return ldb_next_request(module, search_req);
557 : }
558 :
559 : /* Modify the local record. */
560 6 : static int map_modify_do_local(struct map_context *ac)
561 : {
562 6 : struct ldb_request *local_req;
563 6 : struct ldb_context *ldb;
564 6 : int ret;
565 :
566 6 : ldb = ldb_module_get_ctx(ac->module);
567 :
568 6 : 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 4 : ret = ldb_msg_append_linearized_dn(ac->local_msg, IS_MAPPED,
573 2 : ac->remote_req->op.mod.message->dn,
574 : LDB_FLAG_MOD_ADD);
575 2 : if (ret != 0) {
576 0 : return LDB_ERR_OPERATIONS_ERROR;
577 : }
578 :
579 : /* Prepare the local operation */
580 4 : ret = ldb_build_add_req(&local_req, ldb, ac,
581 2 : ac->local_msg,
582 0 : ac->req->controls,
583 : ac,
584 : map_op_local_callback,
585 : ac->req);
586 2 : LDB_REQ_SET_LOCATION(local_req);
587 2 : if (ret != LDB_SUCCESS) {
588 0 : return LDB_ERR_OPERATIONS_ERROR;
589 : }
590 : } else {
591 : /* Prepare the local operation */
592 8 : ret = ldb_build_mod_req(&local_req, ldb, ac,
593 4 : ac->local_msg,
594 0 : ac->req->controls,
595 : ac,
596 : map_op_local_callback,
597 : ac->req);
598 4 : LDB_REQ_SET_LOCATION(local_req);
599 4 : if (ret != LDB_SUCCESS) {
600 0 : return LDB_ERR_OPERATIONS_ERROR;
601 : }
602 : }
603 :
604 6 : return ldb_next_request(ac->module, local_req);
605 : }
606 :
607 : /*****************************************************************************
608 : * DELETE operations
609 : *****************************************************************************/
610 :
611 : /* Delete a record. */
612 11 : int ldb_map_delete(struct ldb_module *module, struct ldb_request *req)
613 : {
614 11 : struct ldb_request *search_req;
615 11 : struct ldb_context *ldb;
616 11 : struct map_context *ac;
617 11 : int ret;
618 :
619 11 : ldb = ldb_module_get_ctx(module);
620 :
621 : /* Do not manipulate our control entries */
622 11 : 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 11 : if (!ldb_dn_check_local(module, req->op.del.dn)) {
629 1 : return ldb_next_request(module, req);
630 : }
631 :
632 : /* Prepare context and handle */
633 10 : ac = map_init_context(module, req);
634 10 : if (ac == NULL) {
635 0 : return LDB_ERR_OPERATIONS_ERROR;
636 : }
637 :
638 : /* Prepare the remote operation */
639 10 : 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 10 : LDB_REQ_SET_LOCATION(ac->remote_req);
646 10 : if (ret != LDB_SUCCESS) {
647 0 : return LDB_ERR_OPERATIONS_ERROR;
648 : }
649 :
650 : /* No local db, just run the remote request */
651 10 : 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 10 : ret = map_search_self_req(&search_req, ac, req->op.del.dn);
658 10 : if (ret != LDB_SUCCESS) {
659 0 : map_oom(module);
660 0 : return LDB_ERR_OPERATIONS_ERROR;
661 : }
662 :
663 10 : return ldb_next_request(module, search_req);
664 : }
665 :
666 : /* Delete the local record. */
667 10 : static int map_delete_do_local(struct map_context *ac)
668 : {
669 10 : struct ldb_request *local_req;
670 10 : struct ldb_context *ldb;
671 10 : int ret;
672 :
673 10 : ldb = ldb_module_get_ctx(ac->module);
674 :
675 : /* No local record, continue remotely */
676 10 : if (ac->local_dn == NULL) {
677 : /* Do the remote request. */
678 3 : return ldb_next_remote_request(ac->module, ac->remote_req);
679 : }
680 :
681 : /* Prepare the local operation */
682 7 : 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 7 : LDB_REQ_SET_LOCATION(local_req);
689 7 : if (ret != LDB_SUCCESS) {
690 0 : return LDB_ERR_OPERATIONS_ERROR;
691 : }
692 7 : return ldb_next_request(ac->module, local_req);
693 : }
694 :
695 : /*****************************************************************************
696 : * RENAME operations
697 : *****************************************************************************/
698 :
699 : /* Rename a record. */
700 4 : int ldb_map_rename(struct ldb_module *module, struct ldb_request *req)
701 : {
702 4 : struct ldb_request *search_req = NULL;
703 4 : struct ldb_context *ldb;
704 4 : struct map_context *ac;
705 4 : int ret;
706 :
707 4 : ldb = ldb_module_get_ctx(module);
708 :
709 : /* Do not manipulate our control entries */
710 4 : 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 5 : if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
717 1 : (!ldb_dn_check_local(module, req->op.rename.newdn))) {
718 1 : return ldb_next_request(module, req);
719 : }
720 :
721 : /* Rename into/out of the mapped partition requested, bail out */
722 6 : if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
723 3 : !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 3 : ac = map_init_context(module, req);
729 3 : if (ac == NULL) {
730 0 : return LDB_ERR_OPERATIONS_ERROR;
731 : }
732 :
733 : /* Prepare the remote operation */
734 3 : 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 3 : LDB_REQ_SET_LOCATION(ac->remote_req);
741 3 : if (ret != LDB_SUCCESS) {
742 0 : return LDB_ERR_OPERATIONS_ERROR;
743 : }
744 :
745 : /* No local db, just run the remote request */
746 3 : 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 3 : ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
753 3 : if (ret != LDB_SUCCESS) {
754 0 : map_oom(module);
755 0 : return LDB_ERR_OPERATIONS_ERROR;
756 : }
757 :
758 3 : return ldb_next_request(module, search_req);
759 : }
760 :
761 : /* Rename the local record. */
762 3 : static int map_rename_do_local(struct map_context *ac)
763 : {
764 3 : struct ldb_request *local_req;
765 3 : struct ldb_context *ldb;
766 3 : int ret;
767 :
768 3 : ldb = ldb_module_get_ctx(ac->module);
769 :
770 : /* No local record, continue remotely */
771 3 : 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 3 : 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 3 : LDB_REQ_SET_LOCATION(local_req);
785 3 : if (ret != LDB_SUCCESS) {
786 0 : return LDB_ERR_OPERATIONS_ERROR;
787 : }
788 :
789 3 : return ldb_next_request(ac->module, local_req);
790 : }
791 :
792 3 : static int map_rename_local_callback(struct ldb_request *req,
793 : struct ldb_reply *ares)
794 : {
795 3 : struct ldb_context *ldb;
796 3 : struct map_context *ac;
797 3 : int ret;
798 :
799 3 : ac = talloc_get_type(req->context, struct map_context);
800 3 : ldb = ldb_module_get_ctx(ac->module);
801 :
802 3 : if (!ares) {
803 0 : return ldb_module_done(ac->req, NULL, NULL,
804 : LDB_ERR_OPERATIONS_ERROR);
805 : }
806 3 : if (ares->error != LDB_SUCCESS) {
807 0 : return ldb_module_done(ac->req, ares->controls,
808 : ares->response, ares->error);
809 : }
810 :
811 3 : 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 3 : ret = map_rename_do_fixup(ac);
819 3 : 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 3 : static int map_rename_do_fixup(struct map_context *ac)
829 : {
830 3 : 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 6 : local_req = map_build_fixup_req(ac,
835 3 : ac->req->op.rename.newdn,
836 3 : ac->remote_req->op.rename.newdn,
837 : ac,
838 : map_op_local_callback);
839 3 : if (local_req == NULL) {
840 0 : return LDB_ERR_OPERATIONS_ERROR;
841 : }
842 :
843 3 : return ldb_next_request(ac->module, local_req);
844 : }
|