4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
6 * NOTICE: this module is NOT released under the GNU LGPL license as
7 * other ldb code. This module is release under the GNU GPL v2 or
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Component: ldb partitions module
30 * Description: Implement LDAP partitions
32 * Author: Andrew Bartlett
36 #include "ldb/include/includes.h"
39 struct ldb_module
*module
;
43 struct partition_private_data
{
44 struct partition
**partitions
;
45 struct ldb_dn
**replicate
;
48 struct partition_context
{
49 struct ldb_module
*module
;
50 struct ldb_request
*orig_req
;
52 struct ldb_request
**down_req
;
54 int finished_requests
;
57 static struct ldb_handle
*partition_init_handle(struct ldb_request
*req
, struct ldb_module
*module
)
59 struct partition_context
*ac
;
62 h
= talloc_zero(req
, struct ldb_handle
);
64 ldb_set_errstring(module
->ldb
, "Out of Memory");
70 ac
= talloc_zero(h
, struct partition_context
);
72 ldb_set_errstring(module
->ldb
, "Out of Memory");
77 h
->private_data
= (void *)ac
;
85 struct ldb_module
*make_module_for_next_request(TALLOC_CTX
*mem_ctx
,
86 struct ldb_context
*ldb
,
87 struct ldb_module
*module
)
89 struct ldb_module
*current
;
90 static const struct ldb_module_ops ops
; /* zero */
91 current
= talloc_zero(mem_ctx
, struct ldb_module
);
92 if (current
== NULL
) {
99 current
->next
= module
;
103 struct ldb_module
*find_backend(struct ldb_module
*module
, struct ldb_request
*req
, const struct ldb_dn
*dn
)
106 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
107 struct partition_private_data
);
108 /* Look at base DN */
109 /* Figure out which partition it is under */
110 /* Skip the lot if 'data' isn't here yet (initialistion) */
111 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
112 if (ldb_dn_compare_base(module
->ldb
,
113 data
->partitions
[i
]->dn
,
115 return make_module_for_next_request(req
, module
->ldb
, data
->partitions
[i
]->module
);
124 fire the caller's callback for every entry, but only send 'done' once.
126 static int partition_search_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
128 struct partition_context
*ac
;
130 if (!context
|| !ares
) {
131 ldb_set_errstring(ldb
, "partition_search_callback: NULL Context or Result in 'search' callback");
135 ac
= talloc_get_type(context
, struct partition_context
);
137 if (ares
->type
== LDB_REPLY_ENTRY
) {
138 return ac
->orig_req
->callback(ldb
, ac
->orig_req
->context
, ares
);
140 ac
->finished_requests
++;
141 if (ac
->finished_requests
== ac
->num_requests
) {
142 return ac
->orig_req
->callback(ldb
, ac
->orig_req
->context
, ares
);
150 return LDB_ERR_OPERATIONS_ERROR
;
154 only fire the 'last' callback, and only for START-TLS for now
156 static int partition_other_callback(struct ldb_context
*ldb
, void *context
, struct ldb_reply
*ares
)
158 struct partition_context
*ac
;
161 ldb_set_errstring(ldb
, "partition_other_callback: NULL Context in 'other' callback");
165 ac
= talloc_get_type(context
, struct partition_context
);
167 if (!ac
->orig_req
->callback
) {
173 || (ares
->type
== LDB_REPLY_EXTENDED
174 && strcmp(ares
->response
->oid
, LDB_EXTENDED_START_TLS_OID
))) {
175 ac
->finished_requests
++;
176 if (ac
->finished_requests
== ac
->num_requests
) {
177 return ac
->orig_req
->callback(ldb
, ac
->orig_req
->context
, ares
);
182 ldb_set_errstring(ldb
, "partition_other_callback: Unknown reply type, only supports START_TLS");
185 return LDB_ERR_OPERATIONS_ERROR
;
189 static int partition_send_request(struct partition_context
*ac
, struct ldb_module
*partition
)
192 struct ldb_module
*next
= make_module_for_next_request(ac
->module
, ac
->module
->ldb
, partition
);
194 ac
->down_req
= talloc_realloc(ac
, ac
->down_req
,
195 struct ldb_request
*, ac
->num_requests
+ 1);
197 ldb_set_errstring(ac
->module
->ldb
, "Out of Memory");
198 return LDB_ERR_OPERATIONS_ERROR
;
200 ac
->down_req
[ac
->num_requests
] = talloc(ac
, struct ldb_request
);
201 if (ac
->down_req
[ac
->num_requests
] == NULL
) {
202 ldb_set_errstring(ac
->module
->ldb
, "Out of Memory");
203 return LDB_ERR_OPERATIONS_ERROR
;
206 *ac
->down_req
[ac
->num_requests
] = *ac
->orig_req
; /* copy the request */
208 if (ac
->down_req
[ac
->num_requests
]->operation
== LDB_SEARCH
) {
209 ac
->down_req
[ac
->num_requests
]->callback
= partition_search_callback
;
210 ac
->down_req
[ac
->num_requests
]->context
= ac
;
212 ac
->down_req
[ac
->num_requests
]->callback
= partition_other_callback
;
213 ac
->down_req
[ac
->num_requests
]->context
= ac
;
216 /* Spray off search requests to all backends */
217 ret
= ldb_next_request(next
, ac
->down_req
[ac
->num_requests
]);
218 if (ret
!= LDB_SUCCESS
) {
226 /* Send a request down to all the partitions */
227 static int partition_send_all(struct ldb_module
*module
,
228 struct partition_context
*ac
, struct ldb_request
*req
)
231 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
232 struct partition_private_data
);
233 int ret
= partition_send_request(ac
, module
->next
);
234 if (ret
!= LDB_SUCCESS
) {
237 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
238 ret
= partition_send_request(ac
, data
->partitions
[i
]->module
);
239 if (ret
!= LDB_SUCCESS
) {
246 /* Figure out which backend a request needs to be aimed at. Some
247 * requests must be replicated to all backends */
248 static int partition_replicate(struct ldb_module
*module
, struct ldb_request
*req
, const struct ldb_dn
*dn
)
251 struct ldb_module
*backend
;
252 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
253 struct partition_private_data
);
255 /* Is this a special DN, we need to replicate to every backend? */
256 for (i
=0; data
->replicate
&& data
->replicate
[i
]; i
++) {
257 if (ldb_dn_compare(module
->ldb
,
260 struct ldb_handle
*h
;
261 struct partition_context
*ac
;
263 h
= partition_init_handle(req
, module
);
265 return LDB_ERR_OPERATIONS_ERROR
;
267 /* return our own handle to deal with this call */
270 ac
= talloc_get_type(h
->private_data
, struct partition_context
);
272 return partition_send_all(module
, ac
, req
);
276 /* Otherwise, we need to find the backend to fire it to */
279 backend
= find_backend(module
, req
, dn
);
282 return ldb_next_request(backend
, req
);
287 static int partition_search(struct ldb_module
*module
, struct ldb_request
*req
)
290 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
291 struct partition_private_data
);
294 /* (later) consider if we should be searching multiple
295 * partitions (for 'invisible' partition behaviour */
296 if (ldb_get_opaque(module
->ldb
, "global_catalog")) {
298 struct ldb_handle
*h
;
299 struct partition_context
*ac
;
301 h
= partition_init_handle(req
, module
);
303 return LDB_ERR_OPERATIONS_ERROR
;
305 /* return our own handle to deal with this call */
308 ac
= talloc_get_type(h
->private_data
, struct partition_context
);
310 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
311 /* Find all partitions under the search base */
312 if (ldb_dn_compare_base(module
->ldb
,
314 data
->partitions
[i
]->dn
) == 0) {
315 ret
= partition_send_request(ac
, data
->partitions
[i
]->module
);
316 if (ret
!= LDB_SUCCESS
) {
322 /* Perhaps we didn't match any partitions. Try the main partition, then all partitions */
323 if (ac
->num_requests
== 0) {
324 return partition_send_all(module
, ac
, req
);
329 struct ldb_module
*backend
= find_backend(module
, req
, req
->op
.search
.base
);
331 return ldb_next_request(backend
, req
);
336 static int partition_add(struct ldb_module
*module
, struct ldb_request
*req
)
338 return partition_replicate(module
, req
, req
->op
.add
.message
->dn
);
342 static int partition_modify(struct ldb_module
*module
, struct ldb_request
*req
)
344 return partition_replicate(module
, req
, req
->op
.mod
.message
->dn
);
348 static int partition_delete(struct ldb_module
*module
, struct ldb_request
*req
)
350 return partition_replicate(module
, req
, req
->op
.del
.dn
);
354 static int partition_rename(struct ldb_module
*module
, struct ldb_request
*req
)
357 struct ldb_module
*backend
= find_backend(module
, req
, req
->op
.rename
.olddn
);
358 struct ldb_module
*backend2
= find_backend(module
, req
, req
->op
.rename
.newdn
);
360 if (backend
->next
!= backend2
->next
) {
361 return LDB_ERR_AFFECTS_MULTIPLE_DSAS
;
364 return partition_replicate(module
, req
, req
->op
.rename
.olddn
);
367 /* start a transaction */
368 static int partition_start_trans(struct ldb_module
*module
)
371 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
372 struct partition_private_data
);
373 /* Look at base DN */
374 /* Figure out which partition it is under */
375 /* Skip the lot if 'data' isn't here yet (initialistion) */
376 ret
= ldb_next_start_trans(module
);
377 if (ret
!= LDB_SUCCESS
) {
381 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
382 struct ldb_module
*next
= make_module_for_next_request(module
, module
->ldb
, data
->partitions
[i
]->module
);
384 ret
= ldb_next_start_trans(next
);
386 if (ret
!= LDB_SUCCESS
) {
387 /* Back it out, if it fails on one */
388 for (i
--; i
>= 0; i
--) {
389 next
= make_module_for_next_request(module
, module
->ldb
, data
->partitions
[i
]->module
);
390 ldb_next_del_trans(next
);
399 /* end a transaction */
400 static int partition_end_trans(struct ldb_module
*module
)
402 int i
, ret
, ret2
= LDB_SUCCESS
;
403 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
404 struct partition_private_data
);
405 ret
= ldb_next_end_trans(module
);
406 if (ret
!= LDB_SUCCESS
) {
410 /* Look at base DN */
411 /* Figure out which partition it is under */
412 /* Skip the lot if 'data' isn't here yet (initialistion) */
413 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
414 struct ldb_module
*next
= make_module_for_next_request(module
, module
->ldb
, data
->partitions
[i
]->module
);
416 ret
= ldb_next_end_trans(next
);
418 if (ret
!= LDB_SUCCESS
) {
423 if (ret
!= LDB_SUCCESS
) {
424 /* Back it out, if it fails on one */
425 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
426 struct ldb_module
*next
= make_module_for_next_request(module
, module
->ldb
, data
->partitions
[i
]->module
);
427 ldb_next_del_trans(next
);
434 /* delete a transaction */
435 static int partition_del_trans(struct ldb_module
*module
)
437 int i
, ret
, ret2
= LDB_SUCCESS
;
438 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
439 struct partition_private_data
);
440 ret
= ldb_next_del_trans(module
);
441 if (ret
!= LDB_SUCCESS
) {
445 /* Look at base DN */
446 /* Figure out which partition it is under */
447 /* Skip the lot if 'data' isn't here yet (initialistion) */
448 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
449 struct ldb_module
*next
= make_module_for_next_request(module
, module
->ldb
, data
->partitions
[i
]->module
);
451 ret
= ldb_next_del_trans(next
);
453 if (ret
!= LDB_SUCCESS
) {
460 static int partition_sequence_number(struct ldb_module
*module
, struct ldb_request
*req
)
463 uint64_t seq_number
= 0;
464 struct partition_private_data
*data
= talloc_get_type(module
->private_data
,
465 struct partition_private_data
);
466 ret
= ldb_next_request(module
, req
);
467 if (ret
!= LDB_SUCCESS
) {
470 seq_number
= seq_number
+ req
->op
.seq_num
.seq_num
;
472 /* Look at base DN */
473 /* Figure out which partition it is under */
474 /* Skip the lot if 'data' isn't here yet (initialistion) */
475 for (i
=0; data
&& data
->partitions
&& data
->partitions
[i
]; i
++) {
476 struct ldb_module
*next
= make_module_for_next_request(req
, module
->ldb
, data
->partitions
[i
]->module
);
478 ret
= ldb_next_request(next
, req
);
480 if (ret
!= LDB_SUCCESS
) {
483 seq_number
= seq_number
+ req
->op
.seq_num
.seq_num
;
485 req
->op
.seq_num
.seq_num
= seq_number
;
489 static int sort_compare(void *void1
,
490 void *void2
, void *opaque
)
492 struct ldb_context
*ldb
= talloc_get_type(opaque
, struct ldb_context
);
493 struct partition
**pp1
= void1
;
494 struct partition
**pp2
= void2
;
495 struct partition
*partition1
= talloc_get_type(*pp1
, struct partition
);
496 struct partition
*partition2
= talloc_get_type(*pp2
, struct partition
);
498 return ldb_dn_compare(ldb
, partition1
->dn
, partition2
->dn
);
501 static int partition_init(struct ldb_module
*module
)
504 TALLOC_CTX
*mem_ctx
= talloc_new(module
);
505 static const char *attrs
[] = { "partition", "replicateEntries", "modules", NULL
};
506 struct ldb_result
*res
;
507 struct ldb_message
*msg
;
508 struct ldb_message_element
*partition_attributes
;
509 struct ldb_message_element
*replicate_attributes
;
510 struct ldb_message_element
*modules_attributes
;
512 struct partition_private_data
*data
;
515 return LDB_ERR_OPERATIONS_ERROR
;
518 data
= talloc(mem_ctx
, struct partition_private_data
);
520 return LDB_ERR_OPERATIONS_ERROR
;
523 ret
= ldb_search(module
->ldb
, ldb_dn_explode(mem_ctx
, "@PARTITION"),
527 if (ret
!= LDB_SUCCESS
) {
528 talloc_free(mem_ctx
);
531 talloc_steal(mem_ctx
, res
);
532 if (res
->count
== 0) {
533 talloc_free(mem_ctx
);
534 return ldb_next_init(module
);
537 if (res
->count
> 1) {
538 talloc_free(mem_ctx
);
539 return LDB_ERR_CONSTRAINT_VIOLATION
;
544 partition_attributes
= ldb_msg_find_element(msg
, "partition");
545 if (!partition_attributes
) {
546 ldb_set_errstring(module
->ldb
, "partition_init: no partitions specified");
547 talloc_free(mem_ctx
);
548 return LDB_ERR_CONSTRAINT_VIOLATION
;
550 data
->partitions
= talloc_array(data
, struct partition
*, partition_attributes
->num_values
+ 1);
551 if (!data
->partitions
) {
552 talloc_free(mem_ctx
);
553 return LDB_ERR_OPERATIONS_ERROR
;
555 for (i
=0; i
< partition_attributes
->num_values
; i
++) {
556 char *base
= talloc_strdup(data
->partitions
, (char *)partition_attributes
->values
[i
].data
);
557 char *p
= strchr(base
, ':');
559 ldb_asprintf_errstring(module
->ldb
,
561 "invalid form for partition record (missing ':'): %s", base
);
562 talloc_free(mem_ctx
);
563 return LDB_ERR_CONSTRAINT_VIOLATION
;
568 ldb_asprintf_errstring(module
->ldb
,
570 "invalid form for partition record (missing backend database): %s", base
);
571 talloc_free(mem_ctx
);
572 return LDB_ERR_CONSTRAINT_VIOLATION
;
574 data
->partitions
[i
] = talloc(data
->partitions
, struct partition
);
575 if (!data
->partitions
[i
]) {
576 talloc_free(mem_ctx
);
577 return LDB_ERR_OPERATIONS_ERROR
;
580 data
->partitions
[i
]->dn
= ldb_dn_explode(data
->partitions
[i
], base
);
581 if (!data
->partitions
[i
]->dn
) {
582 ldb_asprintf_errstring(module
->ldb
,
583 "partition_init: invalid DN in partition record: %s", base
);
584 talloc_free(mem_ctx
);
585 return LDB_ERR_CONSTRAINT_VIOLATION
;
588 data
->partitions
[i
]->backend
= private_path(data
->partitions
[i
], p
);
589 ret
= ldb_connect_backend(module
->ldb
, data
->partitions
[i
]->backend
, NULL
, &data
->partitions
[i
]->module
);
590 if (ret
!= LDB_SUCCESS
) {
591 talloc_free(mem_ctx
);
595 data
->partitions
[i
] = NULL
;
597 /* sort these into order, most to least specific */
598 ldb_qsort(data
->partitions
, partition_attributes
->num_values
, sizeof(*data
->partitions
),
599 module
->ldb
, sort_compare
);
601 for (i
=0; data
->partitions
[i
]; i
++) {
602 struct ldb_request
*req
;
603 req
= talloc_zero(mem_ctx
, struct ldb_request
);
605 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "partition: Out of memory!\n");
606 talloc_free(mem_ctx
);
607 return LDB_ERR_OPERATIONS_ERROR
;
610 req
->operation
= LDB_REQ_REGISTER_PARTITION
;
611 req
->op
.reg_partition
.dn
= data
->partitions
[i
]->dn
;
613 ret
= ldb_request(module
->ldb
, req
);
614 if (ret
!= LDB_SUCCESS
) {
615 ldb_debug(module
->ldb
, LDB_DEBUG_ERROR
, "partition: Unable to register partition with rootdse!\n");
616 talloc_free(mem_ctx
);
617 return LDB_ERR_OTHER
;
622 replicate_attributes
= ldb_msg_find_element(msg
, "replicateEntries");
623 if (!replicate_attributes
) {
624 data
->replicate
= NULL
;
626 data
->replicate
= talloc_array(data
, struct ldb_dn
*, replicate_attributes
->num_values
+ 1);
627 if (!data
->replicate
) {
628 talloc_free(mem_ctx
);
629 return LDB_ERR_OPERATIONS_ERROR
;
632 for (i
=0; i
< replicate_attributes
->num_values
; i
++) {
633 data
->replicate
[i
] = ldb_dn_explode(data
->replicate
, replicate_attributes
->values
[i
].data
);
634 if (!data
->replicate
[i
]) {
635 ldb_asprintf_errstring(module
->ldb
,
637 "invalid DN in partition replicate record: %s",
638 replicate_attributes
->values
[i
].data
);
639 talloc_free(mem_ctx
);
640 return LDB_ERR_CONSTRAINT_VIOLATION
;
643 data
->replicate
[i
] = NULL
;
646 /* Make the private data available to any searches the modules may trigger in initialisation */
647 module
->private_data
= data
;
648 talloc_steal(module
, data
);
650 modules_attributes
= ldb_msg_find_element(msg
, "modules");
651 if (modules_attributes
) {
652 for (i
=0; i
< modules_attributes
->num_values
; i
++) {
653 struct ldb_dn
*base_dn
;
655 struct partition
*partition
= NULL
;
656 const char **modules
= NULL
;
658 char *base
= talloc_strdup(data
->partitions
, (char *)modules_attributes
->values
[i
].data
);
659 char *p
= strchr(base
, ':');
661 ldb_asprintf_errstring(module
->ldb
,
663 "invalid form for partition module record (missing ':'): %s", base
);
664 talloc_free(mem_ctx
);
665 return LDB_ERR_CONSTRAINT_VIOLATION
;
670 ldb_asprintf_errstring(module
->ldb
,
672 "invalid form for partition module record (missing backend database): %s", base
);
673 talloc_free(mem_ctx
);
674 return LDB_ERR_CONSTRAINT_VIOLATION
;
677 modules
= ldb_modules_list_from_string(module
->ldb
, mem_ctx
,
680 base_dn
= ldb_dn_explode(mem_ctx
, base
);
682 talloc_free(mem_ctx
);
683 return LDB_ERR_OPERATIONS_ERROR
;
686 for (partition_idx
= 0; data
->partitions
[partition_idx
]; partition_idx
++) {
687 if (ldb_dn_compare(module
->ldb
, data
->partitions
[partition_idx
]->dn
,
689 partition
= data
->partitions
[partition_idx
];
695 ldb_asprintf_errstring(module
->ldb
,
697 "invalid form for partition module record (no such partition): %s", base
);
698 talloc_free(mem_ctx
);
699 return LDB_ERR_CONSTRAINT_VIOLATION
;
702 ret
= ldb_load_modules_list(module
->ldb
, modules
, partition
->module
, &partition
->module
);
703 if (ret
!= LDB_SUCCESS
) {
704 talloc_free(mem_ctx
);
707 ret
= ldb_init_module_chain(module
->ldb
, partition
->module
);
708 if (ret
!= LDB_SUCCESS
) {
709 talloc_free(mem_ctx
);
715 talloc_free(mem_ctx
);
716 return ldb_next_init(module
);
719 static int partition_wait_none(struct ldb_handle
*handle
) {
720 struct partition_context
*ac
;
724 if (!handle
|| !handle
->private_data
) {
725 return LDB_ERR_OPERATIONS_ERROR
;
728 if (handle
->state
== LDB_ASYNC_DONE
) {
729 return handle
->status
;
732 handle
->state
= LDB_ASYNC_PENDING
;
733 handle
->status
= LDB_SUCCESS
;
735 ac
= talloc_get_type(handle
->private_data
, struct partition_context
);
737 for (i
=0; i
< ac
->num_requests
; i
++) {
738 ret
= ldb_wait(ac
->down_req
[i
]->handle
, LDB_WAIT_NONE
);
740 if (ret
!= LDB_SUCCESS
) {
741 handle
->status
= ret
;
744 if (ac
->down_req
[i
]->handle
->status
!= LDB_SUCCESS
) {
745 handle
->status
= ac
->down_req
[i
]->handle
->status
;
749 if (ac
->down_req
[i
]->handle
->state
!= LDB_ASYNC_DONE
) {
757 handle
->state
= LDB_ASYNC_DONE
;
762 static int partition_wait_all(struct ldb_handle
*handle
) {
766 while (handle
->state
!= LDB_ASYNC_DONE
) {
767 ret
= partition_wait_none(handle
);
768 if (ret
!= LDB_SUCCESS
) {
773 return handle
->status
;
776 static int partition_wait(struct ldb_handle
*handle
, enum ldb_wait_type type
)
778 if (type
== LDB_WAIT_ALL
) {
779 return partition_wait_all(handle
);
781 return partition_wait_none(handle
);
785 static const struct ldb_module_ops partition_ops
= {
787 .init_context
= partition_init
,
788 .search
= partition_search
,
789 .add
= partition_add
,
790 .modify
= partition_modify
,
791 .del
= partition_delete
,
792 .rename
= partition_rename
,
793 .start_transaction
= partition_start_trans
,
794 .end_transaction
= partition_end_trans
,
795 .del_transaction
= partition_del_trans
,
796 .sequence_number
= partition_sequence_number
,
797 .wait
= partition_wait
800 int ldb_partition_init(void)
802 return ldb_register_module(&partition_ops
);