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.
26 * Component: ldb local_password module
28 * Description: correctly update hash values based on changes to sambaPassword and friends
30 * Author: Andrew Bartlett
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
[] = {
61 "msDS-KeyVersionNumber",
65 /* And we merge them back into search requests when asked to do so */
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
;
97 h
= talloc_zero(req
, struct ldb_handle
);
99 ldb_set_errstring(module
->ldb
, "Out of Memory");
105 ac
= talloc_zero(h
, struct lpdb_context
);
107 ldb_set_errstring(module
->ldb
, "Out of Memory");
112 h
->private_data
= (void *)ac
;
114 h
->state
= LDB_ASYNC_INIT
;
115 h
->status
= LDB_SUCCESS
;
124 /* Add a record, splitting password attributes from the user's main
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
;
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
])) {
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
);
170 return LDB_ERR_OPERATIONS_ERROR
;
172 ac
= talloc_get_type(h
->private_data
, struct lpdb_context
);
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 */
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
;
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
])) {
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
);
296 return LDB_ERR_OPERATIONS_ERROR
;
298 ac
= talloc_get_type(h
->private_data
, struct lpdb_context
);
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 */
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");
372 return LDB_ERR_OPERATIONS_ERROR
;
375 ac
->search_res
= talloc_steal(ac
, ares
);
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 */
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
:
478 if (local_context
->local_res
!= NULL
) {
479 ldb_set_errstring(ldb
, "Too many results to base search for password entry!");
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
);
496 if (ldb_msg_add_empty(local_context
->remote_res
->message
,
497 ares
->message
->elements
[i
].name
, 0, &el
) != LDB_SUCCESS
) {
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
);
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
);
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");
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
);
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
;
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
);
613 return ac
->orig_req
->callback(ldb
, ac
->orig_req
->context
, 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
;
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
])) {
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
);
659 return LDB_ERR_OPERATIONS_ERROR
;
662 ac
= talloc_get_type(h
->private_data
, struct lpdb_context
);
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
;
685 return LDB_ERR_OPERATIONS_ERROR
;
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
;
694 return LDB_ERR_OPERATIONS_ERROR
;
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
;
720 static int lpdb_wait(struct ldb_handle
*handle
) {
721 struct lpdb_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 lpdb_context
);
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
;
745 if (ac
->remote_req
->handle
->status
!= LDB_SUCCESS
) {
746 handle
->status
= ac
->remote_req
->handle
->status
;
750 if (ac
->remote_req
->handle
->state
!= LDB_ASYNC_DONE
) {
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
;
764 if (ac
->remote_req
->handle
->status
!= LDB_SUCCESS
) {
765 handle
->status
= ac
->remote_req
->handle
->status
;
769 if (ac
->remote_req
->handle
->state
!= LDB_ASYNC_DONE
) {
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
;
783 if (ac
->search_req
->handle
->status
!= LDB_SUCCESS
) {
784 handle
->status
= ac
->search_req
->handle
->status
;
788 if (ac
->search_req
->handle
->state
!= LDB_ASYNC_DONE
) {
792 /* original request done, go on */
793 return local_password_mod_local(handle
);
796 ret
= ldb_wait(ac
->local_req
->handle
, LDB_WAIT_NONE
);
798 if (ret
!= LDB_SUCCESS
) {
799 handle
->status
= ret
;
802 if (ac
->local_req
->handle
->status
!= LDB_SUCCESS
) {
803 handle
->status
= ac
->local_req
->handle
->status
;
807 if (ac
->local_req
->handle
->state
!= LDB_ASYNC_DONE
) {
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
;
820 if (ac
->remote_req
->handle
->status
!= LDB_SUCCESS
) {
821 handle
->status
= ac
->remote_req
->handle
->status
;
825 if (ac
->remote_req
->handle
->state
!= LDB_ASYNC_DONE
) {
832 ret
= LDB_ERR_OPERATIONS_ERROR
;
839 handle
->state
= LDB_ASYNC_DONE
;
843 static int lpdb_wait_all(struct ldb_handle
*handle
) {
847 while (handle
->state
!= LDB_ASYNC_DONE
) {
848 ret
= lpdb_wait(handle
);
849 if (ret
!= LDB_SUCCESS
) {
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
);
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
);