4 Copyright (C) Simo Sorce 2004-2008
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 3 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, see <http://www.gnu.org/licenses/>.
25 * Component: ldb local_password module
27 * Description: correctly update hash values based on changes to userPassword and friends
29 * Author: Andrew Bartlett
33 #include "ldb_module.h"
34 #include "dsdb/samdb/samdb.h"
35 #include "librpc/ndr/libndr.h"
36 #include "dsdb/samdb/ldb_modules/password_modules.h"
38 #define PASSWORD_GUID_ATTR "masterGUID"
40 /* This module maintains a local password database, seperate from the main LDAP server.
42 This allows the password database to be syncronised in a multi-master
43 fashion, seperate to the more difficult concerns of the main
44 database. (With passwords, the last writer always wins)
46 Each incoming add/modify is split into a remote, and a local request, done in that order.
48 We maintain a list of attributes that are kept locally - perhaps
49 this should use the @KLUDGE_ACL list of passwordAttribute
52 static const char * const password_attrs[] = {
53 "supplementalCredentials",
58 "msDS-KeyVersionNumber",
62 /* And we merge them back into search requests when asked to do so */
65 struct lpdb_reply *next;
66 struct ldb_reply *remote;
67 struct ldb_dn *local_dn;
72 struct ldb_module *module;
73 struct ldb_request *req;
75 struct ldb_message *local_message;
77 struct lpdb_reply *list;
78 struct lpdb_reply *current;
79 struct ldb_reply *remote_done;
80 struct ldb_reply *remote;
82 bool added_objectGUID;
83 bool added_objectClass;
87 static struct lpdb_context *lpdb_init_context(struct ldb_module *module,
88 struct ldb_request *req)
90 struct ldb_context *ldb;
91 struct lpdb_context *ac;
93 ldb = ldb_module_get_ctx(module);
95 ac = talloc_zero(req, struct lpdb_context);
97 ldb_set_errstring(ldb, "Out of Memory");
107 static int lpdb_local_callback(struct ldb_request *req, struct ldb_reply *ares)
109 struct ldb_context *ldb;
110 struct lpdb_context *ac;
112 ac = talloc_get_type(req->context, struct lpdb_context);
113 ldb = ldb_module_get_ctx(ac->module);
116 return ldb_module_done(ac->req, NULL, NULL,
117 LDB_ERR_OPERATIONS_ERROR);
119 if (ares->error != LDB_SUCCESS) {
120 return ldb_module_done(ac->req, ares->controls,
121 ares->response, ares->error);
124 if (ares->type != LDB_REPLY_DONE) {
125 ldb_set_errstring(ldb, "Unexpected reply type");
127 return ldb_module_done(ac->req, NULL, NULL,
128 LDB_ERR_OPERATIONS_ERROR);
132 return ldb_module_done(ac->req,
133 ac->remote_done->controls,
134 ac->remote_done->response,
135 ac->remote_done->error);
138 /*****************************************************************************
140 ****************************************************************************/
142 static int lpdb_add_callback(struct ldb_request *req,
143 struct ldb_reply *ares);
145 static int local_password_add(struct ldb_module *module, struct ldb_request *req)
147 struct ldb_context *ldb;
148 struct ldb_message *remote_message;
149 struct ldb_request *remote_req;
150 struct lpdb_context *ac;
151 struct GUID objectGUID;
155 ldb = ldb_module_get_ctx(module);
156 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_add\n");
158 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
159 return ldb_next_request(module, req);
162 /* If the caller is manipulating the local passwords directly, let them pass */
163 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
164 req->op.add.message->dn) == 0) {
165 return ldb_next_request(module, req);
168 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
169 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
174 /* It didn't match any of our password attributes, go on */
175 if (i == ARRAY_SIZE(password_attrs)) {
176 return ldb_next_request(module, req);
179 /* TODO: remove this when userPassword will be in schema */
180 if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
181 ldb_asprintf_errstring(ldb,
182 "Cannot relocate a password on entry: %s, does not have objectClass 'person'",
183 ldb_dn_get_linearized(req->op.add.message->dn));
184 return LDB_ERR_OBJECT_CLASS_VIOLATION;
187 /* From here, we assume we have password attributes to split off */
188 ac = lpdb_init_context(module, req);
190 return LDB_ERR_OPERATIONS_ERROR;
193 remote_message = ldb_msg_copy_shallow(remote_req, req->op.add.message);
194 if (remote_message == NULL) {
195 return LDB_ERR_OPERATIONS_ERROR;
198 /* Remove any password attributes from the remote message */
199 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
200 ldb_msg_remove_attr(remote_message, password_attrs[i]);
203 /* Find the objectGUID to use as the key */
204 objectGUID = samdb_result_guid(ac->req->op.add.message, "objectGUID");
206 ac->local_message = ldb_msg_copy_shallow(ac, req->op.add.message);
207 if (ac->local_message == NULL) {
208 return LDB_ERR_OPERATIONS_ERROR;
211 /* Remove anything seen in the remote message from the local
212 * message (leaving only password attributes) */
213 for (i=0; i < remote_message->num_elements; i++) {
214 ldb_msg_remove_attr(ac->local_message, remote_message->elements[i].name);
217 /* We must have an objectGUID already, or we don't know where
218 * to add the password. This may be changed to an 'add and
219 * search', to allow the directory to create the objectGUID */
220 if (ldb_msg_find_ldb_val(req->op.add.message, "objectGUID") == NULL) {
221 ldb_set_errstring(ldb,
222 "no objectGUID found in search: "
223 "local_password module must be "
224 "onfigured below objectGUID module!\n");
225 return LDB_ERR_CONSTRAINT_VIOLATION;
228 ac->local_message->dn = ldb_dn_new(ac->local_message,
230 if ((ac->local_message->dn == NULL) ||
231 ( ! ldb_dn_add_child_fmt(ac->local_message->dn,
232 PASSWORD_GUID_ATTR "=%s",
233 GUID_string(ac->local_message,
235 return LDB_ERR_OPERATIONS_ERROR;
238 ret = ldb_build_add_req(&remote_req, ldb, ac,
241 ac, lpdb_add_callback,
243 if (ret != LDB_SUCCESS) {
247 return ldb_next_request(module, remote_req);
250 /* Add a record, splitting password attributes from the user's main
252 static int lpdb_add_callback(struct ldb_request *req,
253 struct ldb_reply *ares)
255 struct ldb_context *ldb;
256 struct ldb_request *local_req;
257 struct lpdb_context *ac;
260 ac = talloc_get_type(req->context, struct lpdb_context);
261 ldb = ldb_module_get_ctx(ac->module);
264 return ldb_module_done(ac->req, NULL, NULL,
265 LDB_ERR_OPERATIONS_ERROR);
267 if (ares->error != LDB_SUCCESS) {
268 return ldb_module_done(ac->req, ares->controls,
269 ares->response, ares->error);
272 if (ares->type != LDB_REPLY_DONE) {
273 ldb_set_errstring(ldb, "Unexpected reply type");
275 return ldb_module_done(ac->req, NULL, NULL,
276 LDB_ERR_OPERATIONS_ERROR);
279 ac->remote_done = talloc_steal(ac, ares);
281 ret = ldb_build_add_req(&local_req, ldb, ac,
284 ac, lpdb_local_callback,
286 if (ret != LDB_SUCCESS) {
287 return ldb_module_done(ac->req, NULL, NULL, ret);
290 ret = ldb_next_request(ac->module, local_req);
291 if (ret != LDB_SUCCESS) {
292 return ldb_module_done(ac->req, NULL, NULL, ret);
297 /*****************************************************************************
299 ****************************************************************************/
301 static int lpdb_modify_callabck(struct ldb_request *req,
302 struct ldb_reply *ares);
303 static int lpdb_mod_search_callback(struct ldb_request *req,
304 struct ldb_reply *ares);
306 static int local_password_modify(struct ldb_module *module, struct ldb_request *req)
308 struct ldb_context *ldb;
309 struct lpdb_context *ac;
310 struct ldb_message *remote_message;
311 struct ldb_request *remote_req;
315 ldb = ldb_module_get_ctx(module);
316 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_modify\n");
318 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
319 return ldb_next_request(module, req);
322 /* If the caller is manipulating the local passwords directly, let them pass */
323 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
324 req->op.mod.message->dn) == 0) {
325 return ldb_next_request(module, req);
328 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
329 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
334 /* It didn't match any of our password attributes, then we have nothing to do here */
335 if (i == ARRAY_SIZE(password_attrs)) {
336 return ldb_next_request(module, req);
339 /* From here, we assume we have password attributes to split off */
340 ac = lpdb_init_context(module, req);
342 return LDB_ERR_OPERATIONS_ERROR;
345 remote_message = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
346 if (remote_message == NULL) {
347 return LDB_ERR_OPERATIONS_ERROR;
350 /* Remove any password attributes from the remote message */
351 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
352 ldb_msg_remove_attr(remote_message, password_attrs[i]);
355 ac->local_message = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
356 if (ac->local_message == NULL) {
357 return LDB_ERR_OPERATIONS_ERROR;
360 /* Remove anything seen in the remote message from the local
361 * message (leaving only password attributes) */
362 for (i=0; i < remote_message->num_elements;i++) {
363 ldb_msg_remove_attr(ac->local_message, remote_message->elements[i].name);
366 ret = ldb_build_mod_req(&remote_req, ldb, ac,
369 ac, lpdb_modify_callabck,
371 if (ret != LDB_SUCCESS) {
375 return ldb_next_request(module, remote_req);
378 /* On a modify, we don't have the objectGUID handy, so we need to
379 * search our DN for it */
380 static int lpdb_modify_callabck(struct ldb_request *req,
381 struct ldb_reply *ares)
383 struct ldb_context *ldb;
384 static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
385 struct ldb_request *search_req;
386 struct lpdb_context *ac;
389 ac = talloc_get_type(req->context, struct lpdb_context);
390 ldb = ldb_module_get_ctx(ac->module);
393 return ldb_module_done(ac->req, NULL, NULL,
394 LDB_ERR_OPERATIONS_ERROR);
396 if (ares->error != LDB_SUCCESS) {
397 return ldb_module_done(ac->req, ares->controls,
398 ares->response, ares->error);
401 if (ares->type != LDB_REPLY_DONE) {
402 ldb_set_errstring(ldb, "Unexpected reply type");
404 return ldb_module_done(ac->req, NULL, NULL,
405 LDB_ERR_OPERATIONS_ERROR);
408 ac->remote_done = talloc_steal(ac, ares);
410 /* prepare the search operation */
411 ret = ldb_build_search_req(&search_req, ldb, ac,
412 ac->req->op.mod.message->dn, LDB_SCOPE_BASE,
413 "(objectclass=*)", attrs,
415 ac, lpdb_mod_search_callback,
417 if (ret != LDB_SUCCESS) {
418 return ldb_module_done(ac->req, NULL, NULL,
419 LDB_ERR_OPERATIONS_ERROR);
422 ret = ldb_next_request(ac->module, search_req);
423 if (ret != LDB_SUCCESS) {
424 return ldb_module_done(ac->req, NULL, NULL,
425 LDB_ERR_OPERATIONS_ERROR);
430 /* Called when we search for our own entry. Stores the one entry we
431 * expect (as it is a base search) on the context pointer */
432 static int lpdb_mod_search_callback(struct ldb_request *req,
433 struct ldb_reply *ares)
435 struct ldb_context *ldb;
436 struct ldb_request *local_req;
437 struct lpdb_context *ac;
438 struct ldb_dn *local_dn;
439 struct GUID objectGUID;
440 int ret = LDB_SUCCESS;
442 ac = talloc_get_type(req->context, struct lpdb_context);
443 ldb = ldb_module_get_ctx(ac->module);
446 return ldb_module_done(ac->req, NULL, NULL,
447 LDB_ERR_OPERATIONS_ERROR);
449 if (ares->error != LDB_SUCCESS) {
450 return ldb_module_done(ac->req, ares->controls,
451 ares->response, ares->error);
454 switch (ares->type) {
455 case LDB_REPLY_ENTRY:
456 if (ac->remote != NULL) {
457 ldb_set_errstring(ldb, "Too many results");
459 return ldb_module_done(ac->req, NULL, NULL,
460 LDB_ERR_OPERATIONS_ERROR);
463 ac->remote = talloc_steal(ac, ares);
466 case LDB_REPLY_REFERRAL:
473 /* After we find out the objectGUID for the entry, modify the local
474 * password database as required */
478 /* if it is not an entry of type person this is an error */
479 /* TODO: remove this when sambaPassword will be in schema */
480 if (ac->remote == NULL) {
481 ldb_asprintf_errstring(ldb,
482 "entry just modified (%s) not found!",
483 ldb_dn_get_linearized(req->op.search.base));
484 return ldb_module_done(ac->req, NULL, NULL,
485 LDB_ERR_OPERATIONS_ERROR);
487 if (!ldb_msg_check_string_attribute(ac->remote->message,
488 "objectClass", "person")) {
489 /* Not relevent to us */
490 return ldb_module_done(ac->req,
491 ac->remote_done->controls,
492 ac->remote_done->response,
493 ac->remote_done->error);
496 if (ldb_msg_find_ldb_val(ac->remote->message,
497 "objectGUID") == NULL) {
498 ldb_set_errstring(ldb,
499 "no objectGUID found in search: "
500 "local_password module must be "
501 "configured below objectGUID "
503 return ldb_module_done(ac->req, NULL, NULL,
504 LDB_ERR_OBJECT_CLASS_VIOLATION);
507 objectGUID = samdb_result_guid(ac->remote->message,
510 local_dn = ldb_dn_new(ac, ldb, LOCAL_BASE);
511 if ((local_dn == NULL) ||
512 ( ! ldb_dn_add_child_fmt(local_dn,
513 PASSWORD_GUID_ATTR "=%s",
514 GUID_string(ac, &objectGUID)))) {
515 return ldb_module_done(ac->req, NULL, NULL,
516 LDB_ERR_OPERATIONS_ERROR);
518 ac->local_message->dn = local_dn;
520 ret = ldb_build_mod_req(&local_req, ldb, ac,
523 ac, lpdb_local_callback,
525 if (ret != LDB_SUCCESS) {
526 return ldb_module_done(ac->req, NULL, NULL, ret);
529 /* perform the local update */
530 ret = ldb_next_request(ac->module, local_req);
531 if (ret != LDB_SUCCESS) {
532 return ldb_module_done(ac->req, NULL, NULL, ret);
539 /*****************************************************************************
541 ****************************************************************************/
543 static int lpdb_delete_callabck(struct ldb_request *req,
544 struct ldb_reply *ares);
545 static int lpdb_del_search_callback(struct ldb_request *req,
546 struct ldb_reply *ares);
548 static int local_password_delete(struct ldb_module *module,
549 struct ldb_request *req)
551 struct ldb_context *ldb;
552 struct ldb_request *remote_req;
553 struct lpdb_context *ac;
556 ldb = ldb_module_get_ctx(module);
557 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_delete\n");
559 /* do not manipulate our control entries */
560 if (ldb_dn_is_special(req->op.mod.message->dn)) {
561 return ldb_next_request(module, req);
564 /* If the caller is manipulating the local passwords directly,
566 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
567 req->op.del.dn) == 0) {
568 return ldb_next_request(module, req);
571 /* From here, we assume we have password attributes to split off */
572 ac = lpdb_init_context(module, req);
574 return LDB_ERR_OPERATIONS_ERROR;
577 ret = ldb_build_del_req(&remote_req, ldb, ac,
580 ac, lpdb_delete_callabck,
582 if (ret != LDB_SUCCESS) {
586 return ldb_next_request(module, remote_req);
589 /* On a modify, we don't have the objectGUID handy, so we need to
590 * search our DN for it */
591 static int lpdb_delete_callabck(struct ldb_request *req,
592 struct ldb_reply *ares)
594 struct ldb_context *ldb;
595 static const char * const attrs[] = { "objectGUID", "objectClass", NULL };
596 struct ldb_request *search_req;
597 struct lpdb_context *ac;
600 ac = talloc_get_type(req->context, struct lpdb_context);
601 ldb = ldb_module_get_ctx(ac->module);
604 return ldb_module_done(ac->req, NULL, NULL,
605 LDB_ERR_OPERATIONS_ERROR);
607 if (ares->error != LDB_SUCCESS) {
608 return ldb_module_done(ac->req, ares->controls,
609 ares->response, ares->error);
612 if (ares->type != LDB_REPLY_DONE) {
613 ldb_set_errstring(ldb, "Unexpected reply type");
615 return ldb_module_done(ac->req, NULL, NULL,
616 LDB_ERR_OPERATIONS_ERROR);
619 ac->remote_done = talloc_steal(ac, ares);
621 /* prepare the search operation */
622 ret = ldb_build_search_req(&search_req, ldb, ac,
623 ac->req->op.del.dn, LDB_SCOPE_BASE,
624 "(objectclass=*)", attrs,
626 ac, lpdb_del_search_callback,
628 if (ret != LDB_SUCCESS) {
629 return ldb_module_done(ac->req, NULL, NULL,
630 LDB_ERR_OPERATIONS_ERROR);
633 ret = ldb_next_request(ac->module, search_req);
634 if (ret != LDB_SUCCESS) {
635 return ldb_module_done(ac->req, NULL, NULL, ret);
640 /* Called when we search for our own entry. Stores the one entry we
641 * expect (as it is a base search) on the context pointer */
642 static int lpdb_del_search_callback(struct ldb_request *req,
643 struct ldb_reply *ares)
645 struct ldb_context *ldb;
646 struct ldb_request *local_req;
647 struct lpdb_context *ac;
648 struct ldb_dn *local_dn;
649 struct GUID objectGUID;
650 int ret = LDB_SUCCESS;
652 ac = talloc_get_type(req->context, struct lpdb_context);
653 ldb = ldb_module_get_ctx(ac->module);
656 return ldb_module_done(ac->req, NULL, NULL,
657 LDB_ERR_OPERATIONS_ERROR);
659 if (ares->error != LDB_SUCCESS) {
660 return ldb_module_done(ac->req, ares->controls,
661 ares->response, ares->error);
664 switch (ares->type) {
665 case LDB_REPLY_ENTRY:
666 if (ac->remote != NULL) {
667 ldb_set_errstring(ldb, "Too many results");
669 return ldb_module_done(ac->req, NULL, NULL,
670 LDB_ERR_OPERATIONS_ERROR);
673 ac->remote = talloc_steal(ac, ares);
676 case LDB_REPLY_REFERRAL:
683 /* After we find out the objectGUID for the entry, modify the local
684 * password database as required */
688 /* if it is not an entry of type person this is NOT an error */
689 /* TODO: remove this when sambaPassword will be in schema */
690 if (ac->remote == NULL) {
691 return ldb_module_done(ac->req,
692 ac->remote_done->controls,
693 ac->remote_done->response,
694 ac->remote_done->error);
696 if (!ldb_msg_check_string_attribute(ac->remote->message,
697 "objectClass", "person")) {
698 /* Not relevent to us */
699 return ldb_module_done(ac->req,
700 ac->remote_done->controls,
701 ac->remote_done->response,
702 ac->remote_done->error);
705 if (ldb_msg_find_ldb_val(ac->remote->message,
706 "objectGUID") == NULL) {
707 ldb_set_errstring(ldb,
708 "no objectGUID found in search: "
709 "local_password module must be "
710 "configured below objectGUID "
712 return ldb_module_done(ac->req, NULL, NULL,
713 LDB_ERR_OBJECT_CLASS_VIOLATION);
716 objectGUID = samdb_result_guid(ac->remote->message,
719 local_dn = ldb_dn_new(ac, ldb, LOCAL_BASE);
720 if ((local_dn == NULL) ||
721 ( ! ldb_dn_add_child_fmt(local_dn,
722 PASSWORD_GUID_ATTR "=%s",
723 GUID_string(ac, &objectGUID)))) {
724 return ldb_module_done(ac->req, NULL, NULL,
725 LDB_ERR_OPERATIONS_ERROR);
728 ret = ldb_build_del_req(&local_req, ldb, ac,
731 ac, lpdb_local_callback,
733 if (ret != LDB_SUCCESS) {
734 return ldb_module_done(ac->req, NULL, NULL, ret);
737 /* perform the local update */
738 ret = ldb_next_request(ac->module, local_req);
739 if (ret != LDB_SUCCESS) {
740 return ldb_module_done(ac->req, NULL, NULL, ret);
748 /*****************************************************************************
750 ****************************************************************************/
752 static int lpdb_local_search_callback(struct ldb_request *req,
753 struct ldb_reply *ares);
755 static int lpdb_local_search(struct lpdb_context *ac)
757 struct ldb_context *ldb;
758 struct ldb_request *local_req;
761 ldb = ldb_module_get_ctx(ac->module);
763 ret = ldb_build_search_req(&local_req, ldb, ac,
764 ac->current->local_dn,
767 ac->req->op.search.attrs,
769 ac, lpdb_local_search_callback,
771 if (ret != LDB_SUCCESS) {
772 return LDB_ERR_OPERATIONS_ERROR;
775 return ldb_next_request(ac->module, local_req);
778 static int lpdb_local_search_callback(struct ldb_request *req,
779 struct ldb_reply *ares)
781 struct ldb_context *ldb;
782 struct lpdb_context *ac;
783 struct ldb_reply *merge;
784 struct lpdb_reply *lr;
788 ac = talloc_get_type(req->context, struct lpdb_context);
789 ldb = ldb_module_get_ctx(ac->module);
792 return ldb_module_done(ac->req, NULL, NULL,
793 LDB_ERR_OPERATIONS_ERROR);
795 if (ares->error != LDB_SUCCESS) {
796 return ldb_module_done(ac->req, ares->controls,
797 ares->response, ares->error);
802 /* we are interested only in a single reply (base search) */
803 switch (ares->type) {
804 case LDB_REPLY_ENTRY:
806 if (lr->remote == NULL) {
807 ldb_set_errstring(ldb,
808 "Too many results for password entry search!");
810 return ldb_module_done(ac->req, NULL, NULL,
811 LDB_ERR_OPERATIONS_ERROR);
817 /* steal the local results on the remote results to be
818 * returned all together */
819 talloc_steal(merge, ares->message->elements);
821 /* Make sure never to return the internal key attribute */
822 ldb_msg_remove_attr(ares->message, PASSWORD_GUID_ATTR);
824 for (i=0; i < ares->message->num_elements; i++) {
825 struct ldb_message_element *el;
827 el = ldb_msg_find_element(merge->message,
828 ares->message->elements[i].name);
830 ret = ldb_msg_add_empty(merge->message,
831 ares->message->elements[i].name,
833 if (ret != LDB_SUCCESS) {
835 return ldb_module_done(ac->req,
837 LDB_ERR_OPERATIONS_ERROR);
839 *el = ares->message->elements[i];
846 return ldb_module_send_entry(ac->req, merge->message, merge->controls);
848 case LDB_REPLY_REFERRAL:
857 /* if this entry was not returned yet, return it now */
859 ret = ldb_module_send_entry(ac->req, ac->remote->message, ac->remote->controls);
860 if (ret != LDB_SUCCESS) {
861 return ldb_module_done(ac->req,
867 if (lr->next->remote->type == LDB_REPLY_DONE) {
868 /* this was the last one */
869 return ldb_module_done(ac->req,
870 lr->next->remote->controls,
871 lr->next->remote->response,
872 lr->next->remote->error);
875 ac->current = lr->next;
878 ret = lpdb_local_search(ac);
879 if (ret != LDB_SUCCESS) {
880 return ldb_module_done(ac->req,
889 /* For each entry returned in a remote search, do a local base search,
890 * based on the objectGUID we asked for as an additional attribute */
891 static int lpdb_remote_search_callback(struct ldb_request *req,
892 struct ldb_reply *ares)
894 struct ldb_context *ldb;
895 struct lpdb_context *ac;
896 struct ldb_dn *local_dn;
897 struct GUID objectGUID;
898 struct lpdb_reply *lr;
901 ac = talloc_get_type(req->context, struct lpdb_context);
902 ldb = ldb_module_get_ctx(ac->module);
905 return ldb_module_done(ac->req, NULL, NULL,
906 LDB_ERR_OPERATIONS_ERROR);
908 if (ares->error != LDB_SUCCESS) {
909 return ldb_module_done(ac->req, ares->controls,
910 ares->response, ares->error);
913 switch (ares->type) {
914 case LDB_REPLY_ENTRY:
915 /* No point searching further if it's not a 'person' entry */
916 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
918 /* Make sure to remove anything we added */
919 if (ac->added_objectGUID) {
920 ldb_msg_remove_attr(ares->message, "objectGUID");
923 if (ac->added_objectClass) {
924 ldb_msg_remove_attr(ares->message, "objectClass");
927 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
930 if (ldb_msg_find_ldb_val(ares->message, "objectGUID") == NULL) {
931 ldb_set_errstring(ldb,
932 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
933 return ldb_module_done(ac->req, NULL, NULL,
934 LDB_ERR_OPERATIONS_ERROR);
937 objectGUID = samdb_result_guid(ares->message, "objectGUID");
939 if (ac->added_objectGUID) {
940 ldb_msg_remove_attr(ares->message, "objectGUID");
943 if (ac->added_objectClass) {
944 ldb_msg_remove_attr(ares->message, "objectClass");
947 local_dn = ldb_dn_new(ac, ldb, LOCAL_BASE);
948 if ((local_dn == NULL) ||
949 (! ldb_dn_add_child_fmt(local_dn,
950 PASSWORD_GUID_ATTR "=%s",
951 GUID_string(ac, &objectGUID)))) {
952 return ldb_module_done(ac->req, NULL, NULL,
953 LDB_ERR_OPERATIONS_ERROR);
956 lr = talloc_zero(ac, struct lpdb_reply);
958 return ldb_module_done(ac->req, NULL, NULL,
959 LDB_ERR_OPERATIONS_ERROR);
961 lr->local_dn = talloc_steal(lr, local_dn);
962 lr->remote = talloc_steal(lr, ares);
965 ac->current->next = lr;
973 case LDB_REPLY_REFERRAL:
975 return ldb_module_send_referral(ac->req, ares->referral);
979 if (ac->list == NULL) {
981 return ldb_module_done(ac->req, ares->controls,
982 ares->response, ares->error);
985 lr = talloc_zero(ac, struct lpdb_reply);
987 return ldb_module_done(ac->req, NULL, NULL,
988 LDB_ERR_OPERATIONS_ERROR);
990 lr->remote = talloc_steal(lr, ares);
992 ac->current->next = lr;
994 /* rewind current and start local searches */
995 ac->current= ac->list;
997 ret = lpdb_local_search(ac);
998 if (ret != LDB_SUCCESS) {
999 return ldb_module_done(ac->req, NULL, NULL, ret);
1006 /* Search for passwords and other attributes. The passwords are
1007 * local, but the other attributes are remote, and we need to glue the
1008 * two search spaces back togeather */
1010 static int local_password_search(struct ldb_module *module, struct ldb_request *req)
1012 struct ldb_context *ldb;
1013 struct ldb_request *remote_req;
1014 struct lpdb_context *ac;
1017 const char * const *search_attrs = NULL;
1019 ldb = ldb_module_get_ctx(module);
1020 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_search\n");
1022 if (ldb_dn_is_special(req->op.search.base)) { /* do not manipulate our control entries */
1023 return ldb_next_request(module, req);
1026 search_attrs = NULL;
1028 /* If the caller is searching for the local passwords directly, let them pass */
1029 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1030 req->op.search.base) == 0) {
1031 return ldb_next_request(module, req);
1034 if (req->op.search.attrs && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
1035 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
1036 if (ldb_attr_in_list(req->op.search.attrs, password_attrs[i])) {
1041 /* It didn't match any of our password attributes, go on */
1042 if (i == ARRAY_SIZE(password_attrs)) {
1043 return ldb_next_request(module, req);
1047 ac = lpdb_init_context(module, req);
1049 return LDB_ERR_OPERATIONS_ERROR;
1052 /* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
1053 if (req->op.search.attrs && !ldb_attr_in_list(req->op.search.attrs, "*")) {
1054 if (!ldb_attr_in_list(req->op.search.attrs, "objectGUID")) {
1055 search_attrs = ldb_attr_list_copy_add(ac, req->op.search.attrs, "objectGUID");
1056 ac->added_objectGUID = true;
1057 if (!search_attrs) {
1058 return LDB_ERR_OPERATIONS_ERROR;
1061 search_attrs = req->op.search.attrs;
1063 if (!ldb_attr_in_list(search_attrs, "objectClass")) {
1064 search_attrs = ldb_attr_list_copy_add(ac, search_attrs, "objectClass");
1065 ac->added_objectClass = true;
1066 if (!search_attrs) {
1067 return LDB_ERR_OPERATIONS_ERROR;
1071 search_attrs = req->op.search.attrs;
1074 ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
1075 req->op.search.base,
1076 req->op.search.scope,
1077 req->op.search.tree,
1080 ac, lpdb_remote_search_callback,
1082 if (ret != LDB_SUCCESS) {
1086 /* perform the search */
1087 return ldb_next_request(module, remote_req);
1090 _PUBLIC_ const struct ldb_module_ops ldb_local_password_module_ops = {
1091 .name = "local_password",
1092 .add = local_password_add,
1093 .modify = local_password_modify,
1094 .del = local_password_delete,
1095 .search = local_password_search