r23792: convert Samba4 to GPLv3
[ira/wip.git] / source4 / dsdb / samdb / ldb_modules / local_password.c
1 /* 
2    ldb database module
3
4    Copyright (C) Simo Sorce  2004-2006
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6    Copyright (C) Andrew Tridgell 2004
7
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 3 of the License, or
11    (at your option) any later version.
12    
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.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /*
23  *  Name: ldb
24  *
25  *  Component: ldb local_password module
26  *
27  *  Description: correctly update hash values based on changes to sambaPassword and friends
28  *
29  *  Author: Andrew Bartlett
30  */
31
32 #include "includes.h"
33 #include "libcli/ldap/ldap.h"
34 #include "ldb/include/ldb_errors.h"
35 #include "ldb/include/ldb_private.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "librpc/ndr/libndr.h"
38 #include "dsdb/samdb/ldb_modules/password_modules.h"
39
40 #define PASSWORD_GUID_ATTR "masterGUID"
41
42 /* This module maintains a local password database, seperate from the main LDAP server.
43
44    This allows the password database to be syncronised in a multi-master
45    fashion, seperate to the more difficult concerns of the main
46    database.  (With passwords, the last writer always wins)
47    
48    Each incoming add/modify is split into a remote, and a local request, done in that order.
49
50    We maintain a list of attributes that are kept locally:
51  */
52
53 static const char * const password_attrs[] = {
54         "supplementalCredentials",
55         "unicodePwd",
56         "dBCSPwd",
57         "lmPwdHistory", 
58         "ntPwdHistory", 
59         "msDS-KeyVersionNumber",
60         "pwdLastSet"
61 };
62
63 /* And we merge them back into search requests when asked to do so */
64
65 struct lpdb_context {
66
67         enum lpdb_type {LPDB_ADD, LPDB_MOD, LPDB_SEARCH} type;
68         enum lpdb_step {LPDB_ADD_REMOTE, LPDB_MOD_REMOTE, LPDB_MOD_SEARCH_SELF, LPDB_LOCAL, LPDB_SEARCH_REMOTE} step;
69
70         struct ldb_module *module;
71         struct ldb_request *orig_req;
72         struct ldb_request *remote_req;
73         struct ldb_request *search_req;
74         struct ldb_request *local_req;
75
76         struct ldb_message *local_message;
77
78         BOOL added_objectGUID;
79         BOOL added_objectClass;
80
81         struct ldb_reply *search_res;
82 };
83
84 struct lpdb_local_search_context {
85         struct lpdb_context *ac;
86         struct ldb_reply *remote_res;
87         struct ldb_reply *local_res;
88 };
89
90 static struct ldb_handle *lpdb_init_handle(struct ldb_request *req, struct ldb_module *module, enum lpdb_type type)
91 {
92         struct lpdb_context *ac;
93         struct ldb_handle *h;
94
95         h = talloc_zero(req, struct ldb_handle);
96         if (h == NULL) {
97                 ldb_set_errstring(module->ldb, "Out of Memory");
98                 return NULL;
99         }
100
101         h->module = module;
102
103         ac = talloc_zero(h, struct lpdb_context);
104         if (ac == NULL) {
105                 ldb_set_errstring(module->ldb, "Out of Memory");
106                 talloc_free(h);
107                 return NULL;
108         }
109
110         h->private_data = (void *)ac;
111
112         h->state = LDB_ASYNC_INIT;
113         h->status = LDB_SUCCESS;
114
115         ac->type = type;
116         ac->module = module;
117         ac->orig_req = req;
118
119         return h;
120 }
121
122 /* Add a record, splitting password attributes from the user's main
123  * record */
124
125 static int local_password_add(struct ldb_module *module, struct ldb_request *req)
126 {
127         struct ldb_handle *h;
128         struct lpdb_context *ac;
129         struct ldb_message *remote_message;
130         struct ldb_message *local_message;
131         struct GUID objectGUID;
132         int i;
133
134         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_add\n");
135
136         if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
137                 return ldb_next_request(module, req);
138         }
139
140         /* If the caller is manipulating the local passwords directly, let them pass */
141         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
142                                 req->op.add.message->dn) == 0) {
143                 return ldb_next_request(module, req);
144         }
145
146         for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
147                 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
148                         break;
149                 }
150         }
151
152         /* It didn't match any of our password attributes, go on */
153         if (i == ARRAY_SIZE(password_attrs)) {
154                 return ldb_next_request(module, req);
155         }
156
157         /* TODO: remove this when sambaPassword will be in schema */
158         if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
159                 ldb_asprintf_errstring(module->ldb,
160                                         "Cannot relocate a password on entry: %s, does not have objectClass 'person'",
161                                         ldb_dn_get_linearized(req->op.add.message->dn));
162                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
163         }
164
165         /* From here, we assume we have password attributes to split off */
166         h = lpdb_init_handle(req, module, LPDB_ADD);
167         if (!h) {
168                 return LDB_ERR_OPERATIONS_ERROR;
169         }
170         ac = talloc_get_type(h->private_data, struct lpdb_context);
171
172         ac->orig_req = req;
173
174         ac->remote_req = talloc(ac, struct ldb_request);
175         if (ac->remote_req == NULL) {
176                 return LDB_ERR_OPERATIONS_ERROR;
177         }
178
179         *(ac->remote_req) = *(ac->orig_req);
180
181         remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.add.message);
182         if (remote_message == NULL) {
183                 return LDB_ERR_OPERATIONS_ERROR;
184         }
185
186         /* Remove any password attributes from the remote message */
187         for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
188                 ldb_msg_remove_attr(remote_message, password_attrs[i]);
189         }
190
191         ac->remote_req->op.add.message = remote_message;
192
193         ac->remote_req->context = NULL;
194         ac->remote_req->callback = NULL;
195
196         ac->local_req = talloc(ac, struct ldb_request);
197         if (ac->local_req == NULL) {
198                 return LDB_ERR_OPERATIONS_ERROR;
199         }
200
201         *(ac->local_req) = *(ac->orig_req);
202         local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.add.message);
203         if (local_message == NULL) {
204                 return LDB_ERR_OPERATIONS_ERROR;
205         }
206
207         /* Remove anything seen in the remote message from the local
208          * message (leaving only password attributes) */
209         for (i=0;i<ac->remote_req->op.add.message->num_elements;i++) {
210                 ldb_msg_remove_attr(local_message, ac->remote_req->op.add.message->elements[i].name);
211         }
212
213         /* We must have an objectGUID already, or we don't know where
214          * to add the password.  This may be changed to an 'add and
215          * search', to allow the directory to create the objectGUID */
216         if (ldb_msg_find_ldb_val(ac->orig_req->op.add.message, "objectGUID") == NULL) {
217                 ldb_set_errstring(module->ldb, 
218                                   "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
219                 return LDB_ERR_CONSTRAINT_VIOLATION;
220         }
221
222         /* Find the objectGUID to use as the key */
223         objectGUID = samdb_result_guid(ac->orig_req->op.add.message, "objectGUID");
224         
225         local_message->dn = ldb_dn_new(local_message, module->ldb, LOCAL_BASE);
226         ldb_dn_add_child_fmt(local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(local_message, &objectGUID));
227
228         ac->local_req->op.add.message = local_message;
229
230         ac->local_req->context = NULL;
231         ac->local_req->callback = NULL;
232
233         ac->step = LPDB_ADD_REMOTE;
234
235         /* Return our own handle do deal with this call */
236         req->handle = h;
237
238         return ldb_next_request(module, ac->remote_req);
239 }
240
241 /* After adding the remote entry, add the local one */
242 static int local_password_add_local(struct ldb_handle *h) {
243
244         struct lpdb_context *ac;
245         ac = talloc_get_type(h->private_data, struct lpdb_context);
246
247         h->state = LDB_ASYNC_INIT;
248         h->status = LDB_SUCCESS;
249
250         ac->step = LPDB_LOCAL;
251
252         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
253
254         /* perform the local add */
255         return ldb_next_request(ac->module, ac->local_req);
256 }
257
258 static int local_password_mod_search_self(struct ldb_handle *h);
259
260 static int local_password_modify(struct ldb_module *module, struct ldb_request *req)
261 {
262         struct ldb_handle *h;
263         struct lpdb_context *ac;
264         struct ldb_message *remote_message;
265         struct ldb_message *local_message;
266         int i;
267
268         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_modify\n");
269
270         if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
271                 return ldb_next_request(module, req);
272         }
273
274         /* If the caller is manipulating the local passwords directly, let them pass */
275         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
276                                 req->op.mod.message->dn) == 0) {
277                 return ldb_next_request(module, req);
278         }
279
280         for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
281                 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
282                         break;
283                 }
284         }
285
286         /* It didn't match any of our password attributes, then we have nothing to do here */
287         if (i == ARRAY_SIZE(password_attrs)) {
288                 return ldb_next_request(module, req);
289         }
290
291         /* From here, we assume we have password attributes to split off */
292         h = lpdb_init_handle(req, module, LPDB_MOD);
293         if (!h) {
294                 return LDB_ERR_OPERATIONS_ERROR;
295         }
296         ac = talloc_get_type(h->private_data, struct lpdb_context);
297
298         ac->orig_req = req;
299
300         ac->remote_req = talloc(ac, struct ldb_request);
301         if (ac->remote_req == NULL) {
302                 return LDB_ERR_OPERATIONS_ERROR;
303         }
304
305         *(ac->remote_req) = *(ac->orig_req);
306         remote_message = ldb_msg_copy_shallow(ac->remote_req, ac->orig_req->op.mod.message);
307         if (remote_message == NULL) {
308                 return LDB_ERR_OPERATIONS_ERROR;
309         }
310         
311         /* Remove any password attributes from the remote message */
312         for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
313                 ldb_msg_remove_attr(remote_message, password_attrs[i]);
314         }
315
316         ac->remote_req->op.mod.message = remote_message;
317
318         ac->remote_req->context = NULL;
319         ac->remote_req->callback = NULL;
320
321         ac->local_req = talloc(ac, struct ldb_request);
322         if (ac->local_req == NULL) {
323                 return LDB_ERR_OPERATIONS_ERROR;
324         }
325
326         *(ac->local_req) = *(ac->orig_req);
327         local_message = ldb_msg_copy_shallow(ac->local_req, ac->orig_req->op.mod.message);
328         if (local_message == NULL) {
329                 return LDB_ERR_OPERATIONS_ERROR;
330         }
331
332         /* Remove anything seen in the remote message from the local
333          * message (leaving only password attributes) */
334         for (i=0;i<ac->remote_req->op.mod.message->num_elements;i++) {
335                 ldb_msg_remove_attr(local_message, ac->remote_req->op.mod.message->elements[i].name);
336         }
337
338         ac->local_req->op.mod.message = local_message;
339         ac->local_message = local_message;
340
341         ac->local_req->context = NULL;
342         ac->local_req->callback = NULL;
343
344         ac->step = LPDB_MOD_REMOTE;
345
346         /* Return our own handle do deal with this call */
347         req->handle = h;
348
349         return ldb_next_request(module, ac->remote_req);
350 }
351
352 /* Called when we search for our oen entry.  Stores the one entry we
353  * expect (as it is a base search) on the context pointer */
354 static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
355 {
356         struct lpdb_context *ac;
357
358         if (!context || !ares) {
359                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
360                 return LDB_ERR_OPERATIONS_ERROR;
361         }
362
363         ac = talloc_get_type(context, struct lpdb_context);
364
365         /* we are interested only in the single reply (base search) we receive here */
366         if (ares->type == LDB_REPLY_ENTRY) {
367                 if (ac->search_res != NULL) {
368                         ldb_set_errstring(ldb, "Too many results");
369                         talloc_free(ares);
370                         return LDB_ERR_OPERATIONS_ERROR;
371                 }
372
373                 ac->search_res = talloc_steal(ac, ares);
374         } else {
375                 talloc_free(ares);
376         }
377
378         return LDB_SUCCESS;
379 }
380
381 /* On a modify, we don't have the objectGUID handy, so we need to
382  * search our DN for it */
383 static int local_password_mod_search_self(struct ldb_handle *h) {
384
385         struct lpdb_context *ac;
386         static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
387
388         ac = talloc_get_type(h->private_data, struct lpdb_context);
389
390         /* prepare the search operation */
391         ac->search_req = talloc_zero(ac, struct ldb_request);
392         if (ac->search_req == NULL) {
393                 ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
394                 return LDB_ERR_OPERATIONS_ERROR;
395         }
396
397         ac->search_req->operation = LDB_SEARCH;
398         ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn;
399         ac->search_req->op.search.scope = LDB_SCOPE_BASE;
400         ac->search_req->op.search.tree = ldb_parse_tree(ac->orig_req, NULL);
401         if (ac->search_req->op.search.tree == NULL) {
402                 ldb_set_errstring(ac->module->ldb, "Invalid search filter");
403                 return LDB_ERR_OPERATIONS_ERROR;
404         }
405         ac->search_req->op.search.attrs = attrs;
406         ac->search_req->controls = NULL;
407         ac->search_req->context = ac;
408         ac->search_req->callback = get_self_callback;
409         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
410
411         ac->step = LPDB_MOD_SEARCH_SELF;
412
413         return ldb_next_request(ac->module, ac->search_req);
414 }
415
416 /* After we find out the objectGUID for the entry, modify the local
417  * password database as required */
418 static int local_password_mod_local(struct ldb_handle *h) {
419
420         struct lpdb_context *ac;
421         struct GUID objectGUID;
422         ac = talloc_get_type(h->private_data, struct lpdb_context);
423
424         /* if it is not an entry of type person this is an error */
425         /* TODO: remove this when sambaPassword will be in schema */
426         if (!ac->search_res) {
427                 ldb_asprintf_errstring(ac->module->ldb, 
428                                         "entry just modified (%s) not found!",
429                                         ldb_dn_get_linearized(ac->remote_req->op.mod.message->dn));
430                 return LDB_ERR_OPERATIONS_ERROR;
431         }
432         if (!ldb_msg_check_string_attribute(ac->search_res->message, "objectClass", "person")) {
433                 /* Not relevent to us */
434                 return LDB_SUCCESS;
435         }
436         
437         if (ldb_msg_find_ldb_val(ac->search_res->message, "objectGUID") == NULL) {
438                 ldb_set_errstring(ac->module->ldb, 
439                                   "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
440                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
441         }
442         
443         objectGUID = samdb_result_guid(ac->search_res->message, "objectGUID");
444
445         ac->local_message->dn = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
446         ldb_dn_add_child_fmt(ac->local_message->dn, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID));
447
448         h->state = LDB_ASYNC_INIT;
449         h->status = LDB_SUCCESS;
450
451         ac->step = LPDB_LOCAL;
452
453         ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
454
455         /* perform the local update */
456         return ldb_next_request(ac->module, ac->local_req);
457 }
458
459
460 static int lpdb_local_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
461 {
462         struct lpdb_local_search_context *local_context;
463
464         if (!context || !ares) {
465                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
466                 return LDB_ERR_OPERATIONS_ERROR;
467         }
468
469         local_context = talloc_get_type(context, struct lpdb_local_search_context);
470
471         /* we are interested only in the single reply (base search) we receive here */
472         switch (ares->type) {
473         case LDB_REPLY_ENTRY:
474         {
475                 int i;
476                 if (local_context->local_res != NULL) {
477                         ldb_set_errstring(ldb, "Too many results to base search for password entry!");
478                         talloc_free(ares);
479                         return LDB_ERR_OPERATIONS_ERROR;
480                 }
481                 
482                 local_context->local_res = ares;
483
484                 /* Make sure never to return the internal key attribute to the caller */
485                 ldb_msg_remove_attr(ares->message, PASSWORD_GUID_ATTR);
486
487                 talloc_steal(local_context->remote_res->message->elements, ares->message->elements);
488                 for (i=0; i < ares->message->num_elements; i++) {
489                         struct ldb_message_element *el;
490                         
491                         el = ldb_msg_find_element(local_context->remote_res->message, 
492                                                   ares->message->elements[i].name);
493                         if (!el) {
494                                 if (ldb_msg_add_empty(local_context->remote_res->message, 
495                                                       ares->message->elements[i].name, 0, &el) != LDB_SUCCESS) {
496                                         talloc_free(ares);
497                                         return LDB_ERR_OPERATIONS_ERROR;
498                                 }
499                                 *el = ares->message->elements[i];
500                         }
501                 }
502                 return local_context->ac->orig_req->callback(ldb, 
503                                                                    local_context->ac->orig_req->context,
504                                                                    local_context->remote_res);
505         } 
506         case LDB_REPLY_DONE:
507         {
508                 /* Fire off the callback if there was no local entry, so we get the rest returned */
509                 if (local_context->local_res == NULL) {
510                         return local_context->ac->orig_req->callback(ldb, 
511                                                                            local_context->ac->orig_req->context,
512                                                                            local_context->remote_res);
513                 }
514                 return LDB_SUCCESS;
515                 break;
516         }
517         default:
518         {
519                 talloc_free(ares);
520                 ldb_set_errstring(ldb, "Unexpected result type in base search for password entry!");
521                 return LDB_ERR_OPERATIONS_ERROR;
522         }
523         }
524 }
525
526 /* For each entry returned in a remote search, do a local base search,
527  * based on the objectGUID we asked for as an additional attribute */
528 static int lpdb_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
529 {
530         struct lpdb_context *ac;
531
532         if (!context || !ares) {
533                 ldb_set_errstring(ldb, "NULL Context or Result in callback");
534                 goto error;
535         }
536
537         ac = talloc_get_type(context, struct lpdb_context);
538
539         if (ares->type == LDB_REPLY_ENTRY) {
540                 struct ldb_request *req;
541                 struct lpdb_local_search_context *local_context;
542                 struct GUID objectGUID;
543
544                 /* No point searching further if it's not a 'person' entry */
545                 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
546
547                         /* Make sure to remove anything we added */
548                         if (ac->added_objectGUID) {
549                                 ldb_msg_remove_attr(ares->message, "objectGUID");
550                         }
551                         
552                         if (ac->added_objectClass) {
553                                 ldb_msg_remove_attr(ares->message, "objectClass");
554                         }
555                         
556                         return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
557                 }
558
559                 if (ldb_msg_find_ldb_val(ares->message, "objectGUID") == NULL) {
560                         ldb_set_errstring(ac->module->ldb, 
561                                           "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
562                         return LDB_ERR_OPERATIONS_ERROR;
563                 }
564         
565                 objectGUID = samdb_result_guid(ares->message, "objectGUID");
566
567                 if (ac->added_objectGUID) {
568                         ldb_msg_remove_attr(ares->message, "objectGUID");
569                 }
570
571                 if (ac->added_objectClass) {
572                         ldb_msg_remove_attr(ares->message, "objectClass");
573                 }
574
575                 req = talloc_zero(ac, struct ldb_request);
576                 if (!req) {
577                         return LDB_ERR_OPERATIONS_ERROR;
578                 }
579
580                 local_context = talloc(ac, struct lpdb_local_search_context);
581                 if (!local_context) {
582                         return LDB_ERR_OPERATIONS_ERROR;
583                 }
584                 local_context->ac = ac;
585                 local_context->remote_res = ares;
586                 local_context->local_res = NULL;
587
588                 req->op.search.base = ldb_dn_new(ac, ac->module->ldb, LOCAL_BASE);
589                 if ( ! ldb_dn_add_child_fmt(req->op.search.base, PASSWORD_GUID_ATTR "=%s", GUID_string(ac, &objectGUID))) {
590                         return LDB_ERR_OPERATIONS_ERROR;
591                 }
592                 req->operation = LDB_SEARCH;
593                 req->op.search.scope = LDB_SCOPE_BASE;
594                 req->op.search.tree = ldb_parse_tree(req, NULL);
595                 if (req->op.search.tree == NULL) {
596                         ldb_set_errstring(ac->module->ldb, "Out of Memory");
597                         return LDB_ERR_OPERATIONS_ERROR;
598                 }
599                 req->op.search.attrs = ac->orig_req->op.search.attrs;
600                 req->controls = NULL;
601                 req->context = ac;
602                 req->callback = get_self_callback;
603
604                 ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
605                 
606                 req->context = local_context;
607                 req->callback = lpdb_local_search_callback;
608
609                 return ldb_next_request(ac->module, req);
610         } else {
611                 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
612         }
613 error:
614         talloc_free(ares);
615         return LDB_ERR_OPERATIONS_ERROR;
616 }
617
618 /* Search for passwords and other attributes.  The passwords are
619  * local, but the other attributes are remote, and we need to glue the
620  * two search spaces back togeather */
621
622 static int local_password_search(struct ldb_module *module, struct ldb_request *req)
623 {
624         struct ldb_handle *h;
625         struct lpdb_context *ac;
626         int i;
627         int ret;
628         const char * const *search_attrs = NULL;
629
630         ldb_debug(module->ldb, LDB_DEBUG_TRACE, "local_password_search\n");
631
632         if (ldb_dn_is_special(req->op.search.base)) { /* do not manipulate our control entries */
633                 return ldb_next_request(module, req);
634         }
635
636         /* If the caller is searching for the local passwords directly, let them pass */
637         if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, LOCAL_BASE),
638                                 req->op.search.base) == 0) {
639                 return ldb_next_request(module, req);
640         }
641
642         if (req->op.search.attrs && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
643                 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
644                         if (ldb_attr_in_list(req->op.search.attrs, password_attrs[i])) {
645                                 break;
646                         }
647                 }
648                 
649                 /* It didn't match any of our password attributes, go on */
650                 if (i == ARRAY_SIZE(password_attrs)) {
651                         return ldb_next_request(module, req);
652                 }
653         }
654
655         h = lpdb_init_handle(req, module, LPDB_SEARCH);
656         if (!h) {
657                 return LDB_ERR_OPERATIONS_ERROR;
658         }
659         
660         ac = talloc_get_type(h->private_data, struct lpdb_context);
661
662         ac->orig_req = req;
663
664         ac->remote_req = talloc(ac, struct ldb_request);
665         if (ac->remote_req == NULL) {
666                 return LDB_ERR_OPERATIONS_ERROR;
667         }
668
669         /* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
670         *(ac->remote_req) = *(ac->orig_req);
671
672         /* Return our own handle do deal with this call */
673         ac->remote_req->handle = h;
674         
675         ac->remote_req->context = ac;
676         ac->remote_req->callback = lpdb_remote_search_callback;
677
678         if (req->op.search.attrs && !ldb_attr_in_list(req->op.search.attrs, "*")) {
679                 if (!ldb_attr_in_list(req->op.search.attrs, "objectGUID")) {
680                         search_attrs = ldb_attr_list_copy_add(req, req->op.search.attrs, "objectGUID");
681                         ac->added_objectGUID = True;
682                         if (!search_attrs) {
683                                 return LDB_ERR_OPERATIONS_ERROR;
684                         }
685                 } else {
686                         search_attrs = req->op.search.attrs;
687                 }
688                 if (!ldb_attr_in_list(search_attrs, "objectClass")) {
689                         search_attrs = ldb_attr_list_copy_add(req, search_attrs, "objectClass");
690                         ac->added_objectClass = True;
691                         if (!search_attrs) {
692                                 return LDB_ERR_OPERATIONS_ERROR;
693                         }
694                 }
695         } else {
696                 search_attrs = req->op.search.attrs;
697         }
698
699         ac->remote_req->op.search.attrs = search_attrs;
700
701         ldb_set_timeout_from_prev_req(module->ldb, ac->orig_req, ac->remote_req);
702
703         h->state = LDB_ASYNC_INIT;
704         h->status = LDB_SUCCESS;
705
706         ac->step = LPDB_SEARCH_REMOTE;
707
708         /* perform the search */
709         ret = ldb_next_request(module, ac->remote_req);
710
711         if (ret == LDB_SUCCESS) {
712                 req->handle = ac->remote_req->handle;
713         }
714
715         return ret;
716 }
717
718 static int lpdb_wait(struct ldb_handle *handle) {
719         struct lpdb_context *ac;
720         int ret;
721     
722         if (!handle || !handle->private_data) {
723                 return LDB_ERR_OPERATIONS_ERROR;
724         }
725
726         if (handle->state == LDB_ASYNC_DONE) {
727                 return handle->status;
728         }
729
730         handle->state = LDB_ASYNC_PENDING;
731         handle->status = LDB_SUCCESS;
732
733         ac = talloc_get_type(handle->private_data, struct lpdb_context);
734
735         switch (ac->step) {
736         case LPDB_ADD_REMOTE:
737                 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
738
739                 if (ret != LDB_SUCCESS) {
740                         handle->status = ret;
741                         goto done;
742                 }
743                 if (ac->remote_req->handle->status != LDB_SUCCESS) {
744                         handle->status = ac->remote_req->handle->status;
745                         goto done;
746                 }
747
748                 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
749                         return LDB_SUCCESS;
750                 }
751
752                 /* original request done, go on */
753                 return local_password_add_local(handle);
754                 
755         case LPDB_MOD_REMOTE:
756                 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
757
758                 if (ret != LDB_SUCCESS) {
759                         handle->status = ret;
760                         goto done;
761                 }
762                 if (ac->remote_req->handle->status != LDB_SUCCESS) {
763                         handle->status = ac->remote_req->handle->status;
764                         goto done;
765                 }
766
767                 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
768                         return LDB_SUCCESS;
769                 }
770
771                 /* original request done, go on */
772                 return local_password_mod_search_self(handle);
773                 
774         case LPDB_MOD_SEARCH_SELF:
775                 ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
776
777                 if (ret != LDB_SUCCESS) {
778                         handle->status = ret;
779                         goto done;
780                 }
781                 if (ac->search_req->handle->status != LDB_SUCCESS) {
782                         handle->status = ac->search_req->handle->status;
783                         goto done;
784                 }
785
786                 if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
787                         return LDB_SUCCESS;
788                 }
789
790                 /* original request done, go on */
791                 return local_password_mod_local(handle);
792                 
793         case LPDB_LOCAL:
794                 ret = ldb_wait(ac->local_req->handle, LDB_WAIT_NONE);
795
796                 if (ret != LDB_SUCCESS) {
797                         handle->status = ret;
798                         goto done;
799                 }
800                 if (ac->local_req->handle->status != LDB_SUCCESS) {
801                         handle->status = ac->local_req->handle->status;
802                         goto done;
803                 }
804
805                 if (ac->local_req->handle->state != LDB_ASYNC_DONE) {
806                         return LDB_SUCCESS;
807                 }
808
809                 break;
810                 
811         case LPDB_SEARCH_REMOTE:
812                 ret = ldb_wait(ac->remote_req->handle, LDB_WAIT_NONE);
813
814                 if (ret != LDB_SUCCESS) {
815                         handle->status = ret;
816                         goto done;
817                 }
818                 if (ac->remote_req->handle->status != LDB_SUCCESS) {
819                         handle->status = ac->remote_req->handle->status;
820                         goto done;
821                 }
822
823                 if (ac->remote_req->handle->state != LDB_ASYNC_DONE) {
824                         return LDB_SUCCESS;
825                 }
826
827                 break;
828                 
829         default:
830                 ret = LDB_ERR_OPERATIONS_ERROR;
831                 goto done;
832         }
833
834         ret = LDB_SUCCESS;
835
836 done:
837         handle->state = LDB_ASYNC_DONE;
838         return ret;
839 }
840
841 static int lpdb_wait_all(struct ldb_handle *handle) {
842
843         int ret;
844
845         while (handle->state != LDB_ASYNC_DONE) {
846                 ret = lpdb_wait(handle);
847                 if (ret != LDB_SUCCESS) {
848                         return ret;
849                 }
850         }
851
852         return handle->status;
853 }
854
855 static int local_password_wait(struct ldb_handle *handle, enum ldb_wait_type type)
856 {
857         if (type == LDB_WAIT_ALL) {
858                 return lpdb_wait_all(handle);
859         } else {
860                 return lpdb_wait(handle);
861         }
862 }
863
864 static const struct ldb_module_ops local_password_ops = {
865         .name          = "local_password",
866         .add           = local_password_add,
867         .modify        = local_password_modify,
868         .search        = local_password_search,
869         .wait          = local_password_wait
870 };
871
872
873 int local_password_module_init(void)
874 {
875         return ldb_register_module(&local_password_ops);
876 }