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"
37 #include "dsdb/samdb/ldb_modules/util.h"
38 #include "dsdb/common/util.h"
40 #define PASSWORD_GUID_ATTR "masterGUID"
42 /* This module maintains a local password database, separate from the main LDAP
45 This allows the password database to be synchronised 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
52 We maintain a list of attributes that are kept locally - perhaps
53 this should use the @KLUDGE_ACL list of passwordAttribute
56 static const char * const password_attrs
[] = {
58 DSDB_SECRET_ATTRIBUTES
61 /* And we merge them back into search requests when asked to do so */
64 struct lpdb_reply
*next
;
65 struct ldb_reply
*remote
;
66 struct ldb_dn
*local_dn
;
71 struct ldb_module
*module
;
72 struct ldb_request
*req
;
74 struct ldb_message
*local_message
;
76 struct lpdb_reply
*list
;
77 struct lpdb_reply
*current
;
78 struct ldb_reply
*remote_done
;
79 struct ldb_reply
*remote
;
81 bool added_objectGUID
;
82 bool added_objectClass
;
86 static struct lpdb_context
*lpdb_init_context(struct ldb_module
*module
,
87 struct ldb_request
*req
)
89 struct ldb_context
*ldb
;
90 struct lpdb_context
*ac
;
92 ldb
= ldb_module_get_ctx(module
);
94 ac
= talloc_zero(req
, struct lpdb_context
);
96 ldb_set_errstring(ldb
, "Out of Memory");
106 static int lpdb_local_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
108 struct ldb_context
*ldb
;
109 struct lpdb_context
*ac
;
111 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
112 ldb
= ldb_module_get_ctx(ac
->module
);
115 return ldb_module_done(ac
->req
, NULL
, NULL
,
116 LDB_ERR_OPERATIONS_ERROR
);
118 if (ares
->error
!= LDB_SUCCESS
) {
119 return ldb_module_done(ac
->req
, ares
->controls
,
120 ares
->response
, ares
->error
);
123 if (ares
->type
!= LDB_REPLY_DONE
) {
124 ldb_set_errstring(ldb
, "Unexpected reply type");
126 return ldb_module_done(ac
->req
, NULL
, NULL
,
127 LDB_ERR_OPERATIONS_ERROR
);
131 return ldb_module_done(ac
->req
,
132 ac
->remote_done
->controls
,
133 ac
->remote_done
->response
,
134 ac
->remote_done
->error
);
137 /*****************************************************************************
139 ****************************************************************************/
141 static int lpdb_add_callback(struct ldb_request
*req
,
142 struct ldb_reply
*ares
);
144 static int local_password_add(struct ldb_module
*module
, struct ldb_request
*req
)
146 struct ldb_context
*ldb
;
147 struct ldb_message
*remote_message
;
148 struct ldb_request
*remote_req
;
149 struct lpdb_context
*ac
;
150 struct GUID objectGUID
;
154 ldb
= ldb_module_get_ctx(module
);
155 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_add\n");
157 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
158 return ldb_next_request(module
, req
);
161 /* If the caller is manipulating the local passwords directly, let them pass */
162 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
163 req
->op
.add
.message
->dn
) == 0) {
164 return ldb_next_request(module
, req
);
167 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
168 if (ldb_msg_find_element(req
->op
.add
.message
, password_attrs
[i
])) {
173 /* It didn't match any of our password attributes, go on */
174 if (i
== ARRAY_SIZE(password_attrs
)) {
175 return ldb_next_request(module
, req
);
178 /* From here, we assume we have password attributes to split off */
179 ac
= lpdb_init_context(module
, req
);
181 return ldb_operr(ldb
);
184 remote_message
= ldb_msg_copy_shallow(remote_req
, req
->op
.add
.message
);
185 if (remote_message
== NULL
) {
186 return ldb_operr(ldb
);
189 /* Remove any password attributes from the remote message */
190 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
191 ldb_msg_remove_attr(remote_message
, password_attrs
[i
]);
194 /* Find the objectGUID to use as the key */
195 objectGUID
= samdb_result_guid(ac
->req
->op
.add
.message
, "objectGUID");
197 ac
->local_message
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
198 if (ac
->local_message
== NULL
) {
199 return ldb_operr(ldb
);
202 /* Remove anything seen in the remote message from the local
203 * message (leaving only password attributes) */
204 for (i
=0; i
< remote_message
->num_elements
; i
++) {
205 ldb_msg_remove_attr(ac
->local_message
, remote_message
->elements
[i
].name
);
208 /* We must have an objectGUID already, or we don't know where
209 * to add the password. This may be changed to an 'add and
210 * search', to allow the directory to create the objectGUID */
211 if (ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectGUID") == NULL
) {
212 ldb_set_errstring(ldb
,
213 "no objectGUID found in search: "
214 "local_password module must be "
215 "onfigured below objectGUID module!\n");
216 return LDB_ERR_CONSTRAINT_VIOLATION
;
219 ac
->local_message
->dn
= ldb_dn_new(ac
->local_message
,
221 if ((ac
->local_message
->dn
== NULL
) ||
222 ( ! ldb_dn_add_child_fmt(ac
->local_message
->dn
,
223 PASSWORD_GUID_ATTR
"=%s",
224 GUID_string(ac
->local_message
,
226 return ldb_operr(ldb
);
229 ret
= ldb_build_add_req(&remote_req
, ldb
, ac
,
232 ac
, lpdb_add_callback
,
234 LDB_REQ_SET_LOCATION(remote_req
);
235 if (ret
!= LDB_SUCCESS
) {
239 return ldb_next_request(module
, remote_req
);
242 /* Add a record, splitting password attributes from the user's main
244 static int lpdb_add_callback(struct ldb_request
*req
,
245 struct ldb_reply
*ares
)
247 struct ldb_context
*ldb
;
248 struct ldb_request
*local_req
;
249 struct lpdb_context
*ac
;
252 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
253 ldb
= ldb_module_get_ctx(ac
->module
);
256 return ldb_module_done(ac
->req
, NULL
, NULL
,
257 LDB_ERR_OPERATIONS_ERROR
);
259 if (ares
->error
!= LDB_SUCCESS
) {
260 return ldb_module_done(ac
->req
, ares
->controls
,
261 ares
->response
, ares
->error
);
264 if (ares
->type
!= LDB_REPLY_DONE
) {
265 ldb_set_errstring(ldb
, "Unexpected reply type");
267 return ldb_module_done(ac
->req
, NULL
, NULL
,
268 LDB_ERR_OPERATIONS_ERROR
);
271 ac
->remote_done
= talloc_steal(ac
, ares
);
273 ret
= ldb_build_add_req(&local_req
, ldb
, ac
,
276 ac
, lpdb_local_callback
,
278 LDB_REQ_SET_LOCATION(local_req
);
279 if (ret
!= LDB_SUCCESS
) {
280 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
283 ret
= ldb_next_request(ac
->module
, local_req
);
284 if (ret
!= LDB_SUCCESS
) {
285 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
290 /*****************************************************************************
292 ****************************************************************************/
294 static int lpdb_modify_callback(struct ldb_request
*req
,
295 struct ldb_reply
*ares
);
296 static int lpdb_mod_search_callback(struct ldb_request
*req
,
297 struct ldb_reply
*ares
);
299 static int local_password_modify(struct ldb_module
*module
, struct ldb_request
*req
)
301 struct ldb_context
*ldb
;
302 struct lpdb_context
*ac
;
303 struct ldb_message
*remote_message
;
304 struct ldb_request
*remote_req
;
308 ldb
= ldb_module_get_ctx(module
);
309 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_modify\n");
311 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
312 return ldb_next_request(module
, req
);
315 /* If the caller is manipulating the local passwords directly, let them pass */
316 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
317 req
->op
.mod
.message
->dn
) == 0) {
318 return ldb_next_request(module
, req
);
321 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
322 if (ldb_msg_find_element(req
->op
.add
.message
, password_attrs
[i
])) {
327 /* It didn't match any of our password attributes, then we have nothing to do here */
328 if (i
== ARRAY_SIZE(password_attrs
)) {
329 return ldb_next_request(module
, req
);
332 /* From here, we assume we have password attributes to split off */
333 ac
= lpdb_init_context(module
, req
);
335 return ldb_operr(ldb
);
338 remote_message
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.mod
.message
);
339 if (remote_message
== NULL
) {
340 return ldb_operr(ldb
);
343 /* Remove any password attributes from the remote message */
344 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
345 ldb_msg_remove_attr(remote_message
, password_attrs
[i
]);
348 ac
->local_message
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.mod
.message
);
349 if (ac
->local_message
== NULL
) {
350 return ldb_operr(ldb
);
353 /* Remove anything seen in the remote message from the local
354 * message (leaving only password attributes) */
355 for (i
=0; i
< remote_message
->num_elements
;i
++) {
356 ldb_msg_remove_attr(ac
->local_message
, remote_message
->elements
[i
].name
);
359 ret
= ldb_build_mod_req(&remote_req
, ldb
, ac
,
362 ac
, lpdb_modify_callback
,
364 LDB_REQ_SET_LOCATION(remote_req
);
365 if (ret
!= LDB_SUCCESS
) {
369 return ldb_next_request(module
, remote_req
);
372 /* On a modify, we don't have the objectGUID handy, so we need to
373 * search our DN for it */
374 static int lpdb_modify_callback(struct ldb_request
*req
,
375 struct ldb_reply
*ares
)
377 struct ldb_context
*ldb
;
378 static const char * const attrs
[] = { "objectGUID", "objectClass", NULL
};
379 struct ldb_request
*search_req
;
380 struct lpdb_context
*ac
;
383 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
384 ldb
= ldb_module_get_ctx(ac
->module
);
387 return ldb_module_done(ac
->req
, NULL
, NULL
,
388 LDB_ERR_OPERATIONS_ERROR
);
390 if (ares
->error
!= LDB_SUCCESS
) {
391 return ldb_module_done(ac
->req
, ares
->controls
,
392 ares
->response
, ares
->error
);
395 if (ares
->type
!= LDB_REPLY_DONE
) {
396 ldb_set_errstring(ldb
, "Unexpected reply type");
398 return ldb_module_done(ac
->req
, NULL
, NULL
,
399 LDB_ERR_OPERATIONS_ERROR
);
402 ac
->remote_done
= talloc_steal(ac
, ares
);
404 /* prepare the search operation */
405 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
406 ac
->req
->op
.mod
.message
->dn
, LDB_SCOPE_BASE
,
407 "(objectclass=*)", attrs
,
409 ac
, lpdb_mod_search_callback
,
411 LDB_REQ_SET_LOCATION(search_req
);
412 if (ret
!= LDB_SUCCESS
) {
413 return ldb_module_done(ac
->req
, NULL
, NULL
,
414 LDB_ERR_OPERATIONS_ERROR
);
417 ret
= ldb_next_request(ac
->module
, search_req
);
418 if (ret
!= LDB_SUCCESS
) {
419 return ldb_module_done(ac
->req
, NULL
, NULL
,
420 LDB_ERR_OPERATIONS_ERROR
);
425 /* Called when we search for our own entry. Stores the one entry we
426 * expect (as it is a base search) on the context pointer */
427 static int lpdb_mod_search_callback(struct ldb_request
*req
,
428 struct ldb_reply
*ares
)
430 struct ldb_context
*ldb
;
431 struct ldb_request
*local_req
;
432 struct lpdb_context
*ac
;
433 struct ldb_dn
*local_dn
;
434 struct GUID objectGUID
;
435 int ret
= LDB_SUCCESS
;
437 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
438 ldb
= ldb_module_get_ctx(ac
->module
);
441 return ldb_module_done(ac
->req
, NULL
, NULL
,
442 LDB_ERR_OPERATIONS_ERROR
);
444 if (ares
->error
!= LDB_SUCCESS
) {
445 return ldb_module_done(ac
->req
, ares
->controls
,
446 ares
->response
, ares
->error
);
449 switch (ares
->type
) {
450 case LDB_REPLY_ENTRY
:
451 if (ac
->remote
!= NULL
) {
452 ldb_set_errstring(ldb
, "Too many results");
454 return ldb_module_done(ac
->req
, NULL
, NULL
,
455 LDB_ERR_OPERATIONS_ERROR
);
458 ac
->remote
= talloc_steal(ac
, ares
);
461 case LDB_REPLY_REFERRAL
:
468 /* After we find out the objectGUID for the entry, modify the local
469 * password database as required */
473 /* if it is not an entry of type person this is an error */
474 /* TODO: remove this when sambaPassword will be in schema */
475 if (ac
->remote
== NULL
) {
476 ldb_asprintf_errstring(ldb
,
477 "entry just modified (%s) not found!",
478 ldb_dn_get_linearized(req
->op
.search
.base
));
479 return ldb_module_done(ac
->req
, NULL
, NULL
,
480 LDB_ERR_OPERATIONS_ERROR
);
482 if (!ldb_msg_check_string_attribute(ac
->remote
->message
,
483 "objectClass", "person")) {
484 /* Not relevent to us */
485 return ldb_module_done(ac
->req
,
486 ac
->remote_done
->controls
,
487 ac
->remote_done
->response
,
488 ac
->remote_done
->error
);
491 if (ldb_msg_find_ldb_val(ac
->remote
->message
,
492 "objectGUID") == NULL
) {
493 ldb_set_errstring(ldb
,
494 "no objectGUID found in search: "
495 "local_password module must be "
496 "configured below objectGUID "
498 return ldb_module_done(ac
->req
, NULL
, NULL
,
499 LDB_ERR_OBJECT_CLASS_VIOLATION
);
502 objectGUID
= samdb_result_guid(ac
->remote
->message
,
505 local_dn
= ldb_dn_new(ac
, ldb
, LOCAL_BASE
);
506 if ((local_dn
== NULL
) ||
507 ( ! ldb_dn_add_child_fmt(local_dn
,
508 PASSWORD_GUID_ATTR
"=%s",
509 GUID_string(ac
, &objectGUID
)))) {
510 return ldb_module_done(ac
->req
, NULL
, NULL
,
511 LDB_ERR_OPERATIONS_ERROR
);
513 ac
->local_message
->dn
= local_dn
;
515 ret
= ldb_build_mod_req(&local_req
, ldb
, ac
,
518 ac
, lpdb_local_callback
,
520 LDB_REQ_SET_LOCATION(local_req
);
521 if (ret
!= LDB_SUCCESS
) {
522 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
525 /* perform the local update */
526 ret
= ldb_next_request(ac
->module
, local_req
);
527 if (ret
!= LDB_SUCCESS
) {
528 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
535 /*****************************************************************************
537 ****************************************************************************/
539 static int lpdb_delete_callback(struct ldb_request
*req
,
540 struct ldb_reply
*ares
);
541 static int lpdb_del_search_callback(struct ldb_request
*req
,
542 struct ldb_reply
*ares
);
544 static int local_password_delete(struct ldb_module
*module
,
545 struct ldb_request
*req
)
547 struct ldb_context
*ldb
;
548 struct ldb_request
*remote_req
;
549 struct lpdb_context
*ac
;
552 ldb
= ldb_module_get_ctx(module
);
553 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_delete\n");
555 /* do not manipulate our control entries */
556 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
557 return ldb_next_request(module
, req
);
560 /* If the caller is manipulating the local passwords directly,
562 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
563 req
->op
.del
.dn
) == 0) {
564 return ldb_next_request(module
, req
);
567 /* From here, we assume we have password attributes to split off */
568 ac
= lpdb_init_context(module
, req
);
570 return ldb_operr(ldb
);
573 ret
= ldb_build_del_req(&remote_req
, ldb
, ac
,
576 ac
, lpdb_delete_callback
,
578 LDB_REQ_SET_LOCATION(remote_req
);
579 if (ret
!= LDB_SUCCESS
) {
583 return ldb_next_request(module
, remote_req
);
586 /* On a modify, we don't have the objectGUID handy, so we need to
587 * search our DN for it */
588 static int lpdb_delete_callback(struct ldb_request
*req
,
589 struct ldb_reply
*ares
)
591 struct ldb_context
*ldb
;
592 static const char * const attrs
[] = { "objectGUID", "objectClass", NULL
};
593 struct ldb_request
*search_req
;
594 struct lpdb_context
*ac
;
597 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
598 ldb
= ldb_module_get_ctx(ac
->module
);
601 return ldb_module_done(ac
->req
, NULL
, NULL
,
602 LDB_ERR_OPERATIONS_ERROR
);
604 if (ares
->error
!= LDB_SUCCESS
) {
605 return ldb_module_done(ac
->req
, ares
->controls
,
606 ares
->response
, ares
->error
);
609 if (ares
->type
!= LDB_REPLY_DONE
) {
610 ldb_set_errstring(ldb
, "Unexpected reply type");
612 return ldb_module_done(ac
->req
, NULL
, NULL
,
613 LDB_ERR_OPERATIONS_ERROR
);
616 ac
->remote_done
= talloc_steal(ac
, ares
);
618 /* prepare the search operation */
619 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
620 ac
->req
->op
.del
.dn
, LDB_SCOPE_BASE
,
621 "(objectclass=*)", attrs
,
623 ac
, lpdb_del_search_callback
,
625 LDB_REQ_SET_LOCATION(search_req
);
626 if (ret
!= LDB_SUCCESS
) {
627 return ldb_module_done(ac
->req
, NULL
, NULL
,
628 LDB_ERR_OPERATIONS_ERROR
);
631 ret
= ldb_next_request(ac
->module
, search_req
);
632 if (ret
!= LDB_SUCCESS
) {
633 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
638 /* Called when we search for our own entry. Stores the one entry we
639 * expect (as it is a base search) on the context pointer */
640 static int lpdb_del_search_callback(struct ldb_request
*req
,
641 struct ldb_reply
*ares
)
643 struct ldb_context
*ldb
;
644 struct ldb_request
*local_req
;
645 struct lpdb_context
*ac
;
646 struct ldb_dn
*local_dn
;
647 struct GUID objectGUID
;
648 int ret
= LDB_SUCCESS
;
650 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
651 ldb
= ldb_module_get_ctx(ac
->module
);
654 return ldb_module_done(ac
->req
, NULL
, NULL
,
655 LDB_ERR_OPERATIONS_ERROR
);
657 if (ares
->error
!= LDB_SUCCESS
) {
658 return ldb_module_done(ac
->req
, ares
->controls
,
659 ares
->response
, ares
->error
);
662 switch (ares
->type
) {
663 case LDB_REPLY_ENTRY
:
664 if (ac
->remote
!= NULL
) {
665 ldb_set_errstring(ldb
, "Too many results");
667 return ldb_module_done(ac
->req
, NULL
, NULL
,
668 LDB_ERR_OPERATIONS_ERROR
);
671 ac
->remote
= talloc_steal(ac
, ares
);
674 case LDB_REPLY_REFERRAL
:
681 /* After we find out the objectGUID for the entry, modify the local
682 * password database as required */
686 /* if it is not an entry of type person this is NOT an error */
687 /* TODO: remove this when sambaPassword will be in schema */
688 if (ac
->remote
== NULL
) {
689 return ldb_module_done(ac
->req
,
690 ac
->remote_done
->controls
,
691 ac
->remote_done
->response
,
692 ac
->remote_done
->error
);
694 if (!ldb_msg_check_string_attribute(ac
->remote
->message
,
695 "objectClass", "person")) {
696 /* Not relevent to us */
697 return ldb_module_done(ac
->req
,
698 ac
->remote_done
->controls
,
699 ac
->remote_done
->response
,
700 ac
->remote_done
->error
);
703 if (ldb_msg_find_ldb_val(ac
->remote
->message
,
704 "objectGUID") == NULL
) {
705 ldb_set_errstring(ldb
,
706 "no objectGUID found in search: "
707 "local_password module must be "
708 "configured below objectGUID "
710 return ldb_module_done(ac
->req
, NULL
, NULL
,
711 LDB_ERR_OBJECT_CLASS_VIOLATION
);
714 objectGUID
= samdb_result_guid(ac
->remote
->message
,
717 local_dn
= ldb_dn_new(ac
, ldb
, LOCAL_BASE
);
718 if ((local_dn
== NULL
) ||
719 ( ! ldb_dn_add_child_fmt(local_dn
,
720 PASSWORD_GUID_ATTR
"=%s",
721 GUID_string(ac
, &objectGUID
)))) {
722 return ldb_module_done(ac
->req
, NULL
, NULL
,
723 LDB_ERR_OPERATIONS_ERROR
);
726 ret
= ldb_build_del_req(&local_req
, ldb
, ac
,
729 ac
, lpdb_local_callback
,
731 LDB_REQ_SET_LOCATION(local_req
);
732 if (ret
!= LDB_SUCCESS
) {
733 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
736 /* perform the local update */
737 ret
= ldb_next_request(ac
->module
, local_req
);
738 if (ret
!= LDB_SUCCESS
) {
739 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
747 /*****************************************************************************
749 ****************************************************************************/
751 static int lpdb_local_search_callback(struct ldb_request
*req
,
752 struct ldb_reply
*ares
);
754 static int lpdb_local_search(struct lpdb_context
*ac
)
756 struct ldb_context
*ldb
;
757 struct ldb_request
*local_req
;
760 ldb
= ldb_module_get_ctx(ac
->module
);
762 ret
= ldb_build_search_req(&local_req
, ldb
, ac
,
763 ac
->current
->local_dn
,
766 ac
->req
->op
.search
.attrs
,
768 ac
, lpdb_local_search_callback
,
770 LDB_REQ_SET_LOCATION(local_req
);
771 if (ret
!= LDB_SUCCESS
) {
772 return ldb_operr(ldb
);
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_operr(ldb
);
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_operr(ldb
);
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_operr(ldb
);
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 LDB_REQ_SET_LOCATION(remote_req
);
1083 if (ret
!= LDB_SUCCESS
) {
1087 /* perform the search */
1088 return ldb_next_request(module
, remote_req
);
1091 static const struct ldb_module_ops ldb_local_password_module_ops
= {
1092 .name
= "local_password",
1093 .add
= local_password_add
,
1094 .modify
= local_password_modify
,
1095 .del
= local_password_delete
,
1096 .search
= local_password_search
1099 int ldb_local_password_module_init(const char *version
)
1101 LDB_MODULE_CHECK_VERSION(version
);
1102 return ldb_register_module(&ldb_local_password_module_ops
);