r21362: rename:
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / local_password.c
blobe72b7cb3a3ed11d55d506e0ba6e3d65d303dfdc9
1 /*
2 ldb database module
4 Copyright (C) Simo Sorce 2004-2006
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Name: ldb
26 * Component: ldb local_password module
28 * Description: correctly update hash values based on changes to sambaPassword and friends
30 * Author: Andrew Bartlett
33 #include "includes.h"
34 #include "libcli/ldap/ldap.h"
35 #include "ldb/include/ldb_errors.h"
36 #include "ldb/include/ldb_private.h"
37 #include "dsdb/samdb/samdb.h"
38 #include "librpc/ndr/libndr.h"
39 #include "dsdb/samdb/ldb_modules/password_modules.h"
41 #define PASSWORD_GUID_ATTR "masterGUID"
43 /* This module maintains a local password database, seperate from the main LDAP server.
45 This allows the password database to be syncronised in a multi-master
46 fashion, seperate to the more difficult concerns of the main
47 database. (With passwords, the last writer always wins)
49 Each incoming add/modify is split into a remote, and a local request, done in that order.
51 We maintain a list of attributes that are kept locally:
54 static const char * const password_attrs[] = {
55 "sambaPassword",
56 "krb5Key",
57 "unicodePwd",
58 "dBCSPwd",
59 "lmPwdHistory",
60 "ntPwdHistory",
61 "msDS-KeyVersionNumber",
62 "pwdLastSet"
65 /* And we merge them back into search requests when asked to do so */
67 struct lpdb_context {
69 enum lpdb_type {LPDB_ADD, LPDB_MOD, LPDB_SEARCH} type;
70 enum lpdb_step {LPDB_ADD_REMOTE, LPDB_MOD_REMOTE, LPDB_MOD_SEARCH_SELF, LPDB_LOCAL, LPDB_SEARCH_REMOTE} step;
72 struct ldb_module *module;
73 struct ldb_request *orig_req;
74 struct ldb_request *remote_req;
75 struct ldb_request *search_req;
76 struct ldb_request *local_req;
78 struct ldb_message *local_message;
80 BOOL added_objectGUID;
81 BOOL added_objectClass;
83 struct ldb_reply *search_res;
86 struct lpdb_local_search_context {
87 struct lpdb_context *ac;
88 struct ldb_reply *remote_res;
89 struct ldb_reply *local_res;
92 static struct ldb_handle *lpdb_init_handle(struct ldb_request *req, struct ldb_module *module, enum lpdb_type type)
94 struct lpdb_context *ac;
95 struct ldb_handle *h;
97 h = talloc_zero(req, struct ldb_handle);
98 if (h == NULL) {
99 ldb_set_errstring(module->ldb, "Out of Memory");
100 return NULL;
103 h->module = module;
105 ac = talloc_zero(h, struct lpdb_context);
106 if (ac == NULL) {
107 ldb_set_errstring(module->ldb, "Out of Memory");
108 talloc_free(h);
109 return NULL;
112 h->private_data = (void *)ac;
114 h->state = LDB_ASYNC_INIT;
115 h->status = LDB_SUCCESS;
117 ac->type = type;
118 ac->module = module;
119 ac->orig_req = req;
121 return h;
124 /* Add a record, splitting password attributes from the user's main
125 * record */
127 static int local_password_add(struct ldb_module *module, struct ldb_request *req)
129 struct ldb_handle *h;
130 struct lpdb_context *ac;
131 struct ldb_message *remote_message;
132 struct ldb_message *local_message;
133 struct GUID objectGUID;
134 int i;
136 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_add\n");
138 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
139 return ldb_next_request(module, req);
142 /* If the caller is manipulating the local passwords directly, let them pass */
143 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
144 req->op.add.message->dn) == 0) {
145 return ldb_next_request(module, req);
148 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
149 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
150 break;
154 /* It didn't match any of our password attributes, go on */
155 if (i == ARRAY_SIZE(password_attrs)) {
156 return ldb_next_request(module, req);
159 /* TODO: remove this when sambaPassword will be in schema */
160 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
161 ldb_asprintf_errstring(module->ldb,
162 "Cannot relocate a password on entry: %s, does not have objectClass 'person'",
163 ldb_dn_get_linearized(req->op.add.message->dn));
164 return LDB_ERR_OBJECT_CLASS_VIOLATION;
167 /* From here, we assume we have password attributes to split off */
168 h = lpdb_init_handle(req, module, LPDB_ADD);
169 if (!h) {
170 return LDB_ERR_OPERATIONS_ERROR;
172 ac = talloc_get_type(h->private_data, struct lpdb_context);
174 ac->orig_req = req;
176 ac->remote_req = talloc(ac, struct ldb_request);
177 if (ac->remote_req == NULL) {
178 return LDB_ERR_OPERATIONS_ERROR;
181 *(ac->remote_req) = *(ac->orig_req);
183 remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.add.message);
184 if (remote_message == NULL) {
185 return LDB_ERR_OPERATIONS_ERROR;
188 /* Remove any password attributes from the remote message */
189 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
190 ldb_msg_remove_attr(remote_message, password_attrs[i]);
193 ac->remote_req->op.add.message = remote_message;
195 ac->remote_req->context = NULL;
196 ac->remote_req->callback = NULL;
198 ac->local_req = talloc(ac, struct ldb_request);
199 if (ac->local_req == NULL) {
200 return LDB_ERR_OPERATIONS_ERROR;
203 *(ac->local_req) = *(ac->orig_req);
204 local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.add.message);
205 if (local_message == NULL) {
206 return LDB_ERR_OPERATIONS_ERROR;
209 /* Remove anything seen in the remote message from the local
210 * message (leaving only password attributes) */
211 for (i=0;i<ac->remote_req->op.add.message->num_elements;i++) {
212 ldb_msg_remove_attr(local_message, ac->remote_req->op.add.message->elements[i].name);
215 /* We must have an objectGUID already, or we don't know where
216 * to add the password. This may be changed to an 'add and
217 * search', to allow the directory to create the objectGUID */
218 if (ldb_msg_find_ldb_val(ac->orig_req->op.add.message, "objectGUID") == NULL) {
219 ldb_set_errstring(module->ldb,
220 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
221 return LDB_ERR_CONSTRAINT_VIOLATION;
224 /* Find the objectGUID to use as the key */
225 objectGUID = samdb_result_guid(ac->orig_req->op.add.message, "objectGUID");
227 local_message->dn = ldb_dn_new(local_message, module->ldb, LOCAL_BASE);
228 ldb_dn_add_child_fmt(local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(local_message, &objectGUID));
230 ac->local_req->op.add.message = local_message;
232 ac->local_req->context = NULL;
233 ac->local_req->callback = NULL;
235 ac->step = LPDB_ADD_REMOTE;
237 /* Return our own handle do deal with this call */
238 req->handle = h;
240 return ldb_next_request(module, ac->remote_req);
243 /* After adding the remote entry, add the local one */
244 static int local_password_add_local(struct ldb_handle *h) {
246 struct lpdb_context *ac;
247 ac = talloc_get_type(h->private_data, struct lpdb_context);
249 h->state = LDB_ASYNC_INIT;
250 h->status = LDB_SUCCESS;
252 ac->step = LPDB_LOCAL;
254 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
256 /* perform the local add */
257 return ldb_next_request(ac->module, ac->local_req);
260 static int local_password_mod_search_self(struct ldb_handle *h);
262 static int local_password_modify(struct ldb_module *module, struct ldb_request *req)
264 struct ldb_handle *h;
265 struct lpdb_context *ac;
266 struct ldb_message *remote_message;
267 struct ldb_message *local_message;
268 int i;
270 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_modify\n");
272 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
273 return ldb_next_request(module, req);
276 /* If the caller is manipulating the local passwords directly, let them pass */
277 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
278 req->op.mod.message->dn) == 0) {
279 return ldb_next_request(module, req);
282 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
283 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
284 break;
288 /* It didn't match any of our password attributes, then we have nothing to do here */
289 if (i == ARRAY_SIZE(password_attrs)) {
290 return ldb_next_request(module, req);
293 /* From here, we assume we have password attributes to split off */
294 h = lpdb_init_handle(req, module, LPDB_MOD);
295 if (!h) {
296 return LDB_ERR_OPERATIONS_ERROR;
298 ac = talloc_get_type(h->private_data, struct lpdb_context);
300 ac->orig_req = req;
302 ac->remote_req = talloc(ac, struct ldb_request);
303 if (ac->remote_req == NULL) {
304 return LDB_ERR_OPERATIONS_ERROR;
307 *(ac->remote_req) = *(ac->orig_req);
308 remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.mod.message);
309 if (remote_message == NULL) {
310 return LDB_ERR_OPERATIONS_ERROR;
313 /* Remove any password attributes from the remote message */
314 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
315 ldb_msg_remove_attr(remote_message, password_attrs[i]);
318 ac->remote_req->op.mod.message = remote_message;
320 ac->remote_req->context = NULL;
321 ac->remote_req->callback = NULL;
323 ac->local_req = talloc(ac, struct ldb_request);
324 if (ac->local_req == NULL) {
325 return LDB_ERR_OPERATIONS_ERROR;
328 *(ac->local_req) = *(ac->orig_req);
329 local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.mod.message);
330 if (local_message == NULL) {
331 return LDB_ERR_OPERATIONS_ERROR;
334 /* Remove anything seen in the remote message from the local
335 * message (leaving only password attributes) */
336 for (i=0;i<ac->remote_req->op.mod.message->num_elements;i++) {
337 ldb_msg_remove_attr(local_message, ac->remote_req->op.mod.message->elements[i].name);
340 ac->local_req->op.mod.message = local_message;
341 ac->local_message = local_message;
343 ac->local_req->context = NULL;
344 ac->local_req->callback = NULL;
346 ac->step = LPDB_MOD_REMOTE;
348 /* Return our own handle do deal with this call */
349 req->handle = h;
351 return ldb_next_request(module, ac->remote_req);
354 /* Called when we search for our oen entry. Stores the one entry we
355 * expect (as it is a base search) on the context pointer */
356 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
358 struct lpdb_context *ac;
360 if (!context || !ares) {
361 ldb_set_errstring(ldb, "NULL Context or Result in callback");
362 return LDB_ERR_OPERATIONS_ERROR;
365 ac = talloc_get_type(context, struct lpdb_context);
367 /* we are interested only in the single reply (base search) we receive here */
368 if (ares->type == LDB_REPLY_ENTRY) {
369 if (ac->search_res != NULL) {
370 ldb_set_errstring(ldb, "Too many results");
371 talloc_free(ares);
372 return LDB_ERR_OPERATIONS_ERROR;
375 ac->search_res = talloc_steal(ac, ares);
376 } else {
377 talloc_free(ares);
380 return LDB_SUCCESS;
383 /* On a modify, we don't have the objectGUID handy, so we need to
384 * search our DN for it */
385 static int local_password_mod_search_self(struct ldb_handle *h) {
387 struct lpdb_context *ac;
388 static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
390 ac = talloc_get_type(h->private_data, struct lpdb_context);
392 /* prepare the search operation */
393 ac->search_req = talloc_zero(ac, struct ldb_request);
394 if (ac->search_req == NULL) {
395 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
396 return LDB_ERR_OPERATIONS_ERROR;
399 ac->search_req->operation = LDB_SEARCH;
400 ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
401 ac->search_req->op.search.scope = LDB_SCOPE_BASE;
402 ac->search_req->op.search.tree = ldb_parse_tree(ac->orig_req, NULL);
403 if (ac->search_req->op.search.tree == NULL) {
404 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
405 return LDB_ERR_OPERATIONS_ERROR;
407 ac->search_req->op.search.attrs = attrs;
408 ac->search_req->controls = NULL;
409 ac->search_req->context = ac;
410 ac->search_req->callback = get_self_callback;
411 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
413 ac->step = LPDB_MOD_SEARCH_SELF;
415 return ldb_next_request(ac->module, ac->search_req);
418 /* After we find out the objectGUID for the entry, modify the local
419 * password database as required */
420 static int local_password_mod_local(struct ldb_handle *h) {
422 struct lpdb_context *ac;
423 struct GUID objectGUID;
424 ac = talloc_get_type(h->private_data, struct lpdb_context);
426 /* if it is not an entry of type person this is an error */
427 /* TODO: remove this when sambaPassword will be in schema */
428 if (!ac->search_res) {
429 ldb_asprintf_errstring(ac->module->ldb,
430 "entry just modified (%s) not found!",
431 ldb_dn_get_linearized(ac->remote_req->op.mod.message->dn));
432 return LDB_ERR_OPERATIONS_ERROR;
434 if (!ldb_msg_check_string_attribute(ac->search_res->message, "objectClass", "person")) {
435 /* Not relevent to us */
436 return LDB_SUCCESS;
439 if (ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID") == NULL) {
440 ldb_set_errstring(ac->module->ldb,
441 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
442 return LDB_ERR_OBJECT_CLASS_VIOLATION;
445 objectGUID = samdb_result_guid(ac->search_res->message, "objectGUID");
447 ac->local_message->dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
448 ldb_dn_add_child_fmt(ac->local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID));
450 h->state = LDB_ASYNC_INIT;
451 h->status = LDB_SUCCESS;
453 ac->step = LPDB_LOCAL;
455 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
457 /* perform the local update */
458 return ldb_next_request(ac->module, ac->local_req);
462 static int lpdb_local_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
464 struct lpdb_local_search_context *local_context;
466 if (!context || !ares) {
467 ldb_set_errstring(ldb, "NULL Context or Result in callback");
468 return LDB_ERR_OPERATIONS_ERROR;
471 local_context = talloc_get_type(context, struct lpdb_local_search_context);
473 /* we are interested only in the single reply (base search) we receive here */
474 switch (ares->type) {
475 case LDB_REPLY_ENTRY:
477 int i;
478 if (local_context->local_res != NULL) {
479 ldb_set_errstring(ldb, "Too many results to base search for password entry!");
480 talloc_free(ares);
481 return LDB_ERR_OPERATIONS_ERROR;
484 local_context->local_res = ares;
486 /* Make sure never to return the internal key attribute to the caller */
487 ldb_msg_remove_attr(ares->message, PASSWORD_GUID_ATTR);
489 talloc_steal(local_context->remote_res->message->elements, ares->message->elements);
490 for (i=0; i < ares->message->num_elements; i++) {
491 struct ldb_message_element *el;
493 el = ldb_msg_find_element(local_context->remote_res->message,
494 ares->message->elements[i].name);
495 if (!el) {
496 if (ldb_msg_add_empty(local_context->remote_res->message,
497 ares->message->elements[i].name, 0, &el) != LDB_SUCCESS) {
498 talloc_free(ares);
499 return LDB_ERR_OPERATIONS_ERROR;
501 *el = ares->message->elements[i];
504 return local_context->ac->orig_req->callback(ldb,
505 local_context->ac->orig_req->context,
506 local_context->remote_res);
508 case LDB_REPLY_DONE:
510 /* Fire off the callback if there was no local entry, so we get the rest returned */
511 if (local_context->local_res == NULL) {
512 return local_context->ac->orig_req->callback(ldb,
513 local_context->ac->orig_req->context,
514 local_context->remote_res);
516 return LDB_SUCCESS;
517 break;
519 default:
521 talloc_free(ares);
522 ldb_set_errstring(ldb, "Unexpected result type in base search for password entry!");
523 return LDB_ERR_OPERATIONS_ERROR;
528 /* For each entry returned in a remote search, do a local base search,
529 * based on the objectGUID we asked for as an additional attribute */
530 static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
532 struct lpdb_context *ac;
534 if (!context || !ares) {
535 ldb_set_errstring(ldb, "NULL Context or Result in callback");
536 goto error;
539 ac = talloc_get_type(context, struct lpdb_context);
541 if (ares->type == LDB_REPLY_ENTRY) {
542 struct ldb_request *req;
543 struct lpdb_local_search_context *local_context;
544 struct GUID objectGUID;
546 /* No point searching further if it's not a 'person' entry */
547 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
549 /* Make sure to remove anything we added */
550 if (ac->added_objectGUID) {
551 ldb_msg_remove_attr(ares->message, "objectGUID");
554 if (ac->added_objectClass) {
555 ldb_msg_remove_attr(ares->message, "objectClass");
558 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
561 if (ldb_msg_find_ldb_val(ares->message, "objectGUID") == NULL) {
562 ldb_set_errstring(ac->module->ldb,
563 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
564 return LDB_ERR_OPERATIONS_ERROR;
567 objectGUID = samdb_result_guid(ares->message, "objectGUID");
569 if (ac->added_objectGUID) {
570 ldb_msg_remove_attr(ares->message, "objectGUID");
573 if (ac->added_objectClass) {
574 ldb_msg_remove_attr(ares->message, "objectClass");
577 req = talloc_zero(ac, struct ldb_request);
578 if (!req) {
579 return LDB_ERR_OPERATIONS_ERROR;
582 local_context = talloc(ac, struct lpdb_local_search_context);
583 if (!local_context) {
584 return LDB_ERR_OPERATIONS_ERROR;
586 local_context->ac = ac;
587 local_context->remote_res = ares;
588 local_context->local_res = NULL;
590 req->op.search.base = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
591 if ( ! ldb_dn_add_child_fmt(req->op.search.base, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID))) {
592 return LDB_ERR_OPERATIONS_ERROR;
594 req->operation = LDB_SEARCH;
595 req->op.search.scope = LDB_SCOPE_BASE;
596 req->op.search.tree = ldb_parse_tree(req, NULL);
597 if (req->op.search.tree == NULL) {
598 ldb_set_errstring(ac->module->ldb, "Out of Memory");
599 return LDB_ERR_OPERATIONS_ERROR;
601 req->op.search.attrs = ac->orig_req->op.search.attrs;
602 req->controls = NULL;
603 req->context = ac;
604 req->callback = get_self_callback;
606 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
608 req->context = local_context;
609 req->callback = lpdb_local_search_callback;
611 return ldb_next_request(ac->module, req);
612 } else {
613 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
615 error:
616 talloc_free(ares);
617 return LDB_ERR_OPERATIONS_ERROR;
620 /* Search for passwords and other attributes. The passwords are
621 * local, but the other attributes are remote, and we need to glue the
622 * two search spaces back togeather */
624 static int local_password_search(struct ldb_module *module, struct ldb_request *req)
626 struct ldb_handle *h;
627 struct lpdb_context *ac;
628 int i;
629 int ret;
630 const char * const *search_attrs = NULL;
632 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_search\n");
634 if (ldb_dn_is_special(req->op.search.base)) { /* do not manipulate our control entries */
635 return ldb_next_request(module, req);
638 /* If the caller is searching for the local passwords directly, let them pass */
639 if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
640 req->op.search.base) == 0) {
641 return ldb_next_request(module, req);
644 if (req->op.search.attrs && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
645 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
646 if (ldb_attr_in_list(req->op.search.attrs, password_attrs[i])) {
647 break;
651 /* It didn't match any of our password attributes, go on */
652 if (i == ARRAY_SIZE(password_attrs)) {
653 return ldb_next_request(module, req);
657 h = lpdb_init_handle(req, module, LPDB_SEARCH);
658 if (!h) {
659 return LDB_ERR_OPERATIONS_ERROR;
662 ac = talloc_get_type(h->private_data, struct lpdb_context);
664 ac->orig_req = req;
666 ac->remote_req = talloc(ac, struct ldb_request);
667 if (ac->remote_req == NULL) {
668 return LDB_ERR_OPERATIONS_ERROR;
671 /* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
672 *(ac->remote_req) = *(ac->orig_req);
674 /* Return our own handle do deal with this call */
675 ac->remote_req->handle = h;
677 ac->remote_req->context = ac;
678 ac->remote_req->callback = lpdb_remote_search_callback;
680 if (req->op.search.attrs && !ldb_attr_in_list(req->op.search.attrs, "*")) {
681 if (!ldb_attr_in_list(req->op.search.attrs, "objectGUID")) {
682 search_attrs = ldb_attr_list_copy_add(req, req->op.search.attrs, "objectGUID");
683 ac->added_objectGUID = True;
684 if (!search_attrs) {
685 return LDB_ERR_OPERATIONS_ERROR;
687 } else {
688 search_attrs = req->op.search.attrs;
690 if (!ldb_attr_in_list(search_attrs, "objectClass")) {
691 search_attrs = ldb_attr_list_copy_add(req, search_attrs, "objectClass");
692 ac->added_objectClass = True;
693 if (!search_attrs) {
694 return LDB_ERR_OPERATIONS_ERROR;
697 } else {
698 search_attrs = req->op.search.attrs;
701 ac->remote_req->op.search.attrs = search_attrs;
703 ldb_set_timeout_from_prev_req(module->ldb, ac->orig_req, ac->remote_req);
705 h->state = LDB_ASYNC_INIT;
706 h->status = LDB_SUCCESS;
708 ac->step = LPDB_SEARCH_REMOTE;
710 /* perform the search */
711 ret = ldb_next_request(module, ac->remote_req);
713 if (ret == LDB_SUCCESS) {
714 req->handle = ac->remote_req->handle;
717 return ret;
720 static int lpdb_wait(struct ldb_handle *handle) {
721 struct lpdb_context *ac;
722 int ret;
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 lpdb_context);
737 switch (ac->step) {
738 case LPDB_ADD_REMOTE:
739 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
741 if (ret != LDB_SUCCESS) {
742 handle->status = ret;
743 goto done;
745 if (ac->remote_req->handle->status != LDB_SUCCESS) {
746 handle->status = ac->remote_req->handle->status;
747 goto done;
750 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
751 return LDB_SUCCESS;
754 /* original request done, go on */
755 return local_password_add_local(handle);
757 case LPDB_MOD_REMOTE:
758 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
760 if (ret != LDB_SUCCESS) {
761 handle->status = ret;
762 goto done;
764 if (ac->remote_req->handle->status != LDB_SUCCESS) {
765 handle->status = ac->remote_req->handle->status;
766 goto done;
769 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
770 return LDB_SUCCESS;
773 /* original request done, go on */
774 return local_password_mod_search_self(handle);
776 case LPDB_MOD_SEARCH_SELF:
777 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
779 if (ret != LDB_SUCCESS) {
780 handle->status = ret;
781 goto done;
783 if (ac->search_req->handle->status != LDB_SUCCESS) {
784 handle->status = ac->search_req->handle->status;
785 goto done;
788 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
789 return LDB_SUCCESS;
792 /* original request done, go on */
793 return local_password_mod_local(handle);
795 case LPDB_LOCAL:
796 ret = ldb_wait(ac->local_req->handle, LDB_WAIT_NONE);
798 if (ret != LDB_SUCCESS) {
799 handle->status = ret;
800 goto done;
802 if (ac->local_req->handle->status != LDB_SUCCESS) {
803 handle->status = ac->local_req->handle->status;
804 goto done;
807 if (ac->local_req->handle->state != LDB_ASYNC_DONE) {
808 return LDB_SUCCESS;
811 break;
813 case LPDB_SEARCH_REMOTE:
814 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
816 if (ret != LDB_SUCCESS) {
817 handle->status = ret;
818 goto done;
820 if (ac->remote_req->handle->status != LDB_SUCCESS) {
821 handle->status = ac->remote_req->handle->status;
822 goto done;
825 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
826 return LDB_SUCCESS;
829 break;
831 default:
832 ret = LDB_ERR_OPERATIONS_ERROR;
833 goto done;
836 ret = LDB_SUCCESS;
838 done:
839 handle->state = LDB_ASYNC_DONE;
840 return ret;
843 static int lpdb_wait_all(struct ldb_handle *handle) {
845 int ret;
847 while (handle->state != LDB_ASYNC_DONE) {
848 ret = lpdb_wait(handle);
849 if (ret != LDB_SUCCESS) {
850 return ret;
854 return handle->status;
857 static int local_password_wait(struct ldb_handle *handle, enum ldb_wait_type type)
859 if (type == LDB_WAIT_ALL) {
860 return lpdb_wait_all(handle);
861 } else {
862 return lpdb_wait(handle);
866 static const struct ldb_module_ops local_password_ops = {
867 .name = "local_password",
868 .add = local_password_add,
869 .modify = local_password_modify,
870 .search = local_password_search,
871 .wait = local_password_wait
875 int local_password_module_init(void)
877 return ldb_register_module(&local_password_ops);