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 "libcli/ldap/ldap.h"
34 #include "ldb_module.h"
35 #include "dsdb/samdb/samdb.h"
36 #include "librpc/ndr/libndr.h"
37 #include "dsdb/samdb/ldb_modules/password_modules.h"
39 #define PASSWORD_GUID_ATTR "masterGUID"
41 /* This module maintains a local password database, seperate from the main LDAP server.
43 This allows the password database to be syncronised in a multi-master
44 fashion, seperate to the more difficult concerns of the main
45 database. (With passwords, the last writer always wins)
47 Each incoming add/modify is split into a remote, and a local request, done in that order.
49 We maintain a list of attributes that are kept locally - perhaps
50 this should use the @KLUDGE_ACL list of passwordAttribute
53 static const char * const password_attrs
[] = {
54 "supplementalCredentials",
59 "msDS-KeyVersionNumber",
63 /* And we merge them back into search requests when asked to do so */
66 struct lpdb_reply
*next
;
67 struct ldb_reply
*remote
;
68 struct ldb_dn
*local_dn
;
73 struct ldb_module
*module
;
74 struct ldb_request
*req
;
76 struct ldb_message
*local_message
;
78 struct lpdb_reply
*list
;
79 struct lpdb_reply
*current
;
80 struct ldb_reply
*remote_done
;
81 struct ldb_reply
*remote
;
83 bool added_objectGUID
;
84 bool added_objectClass
;
88 static struct lpdb_context
*lpdb_init_context(struct ldb_module
*module
,
89 struct ldb_request
*req
)
91 struct ldb_context
*ldb
;
92 struct lpdb_context
*ac
;
94 ldb
= ldb_module_get_ctx(module
);
96 ac
= talloc_zero(req
, struct lpdb_context
);
98 ldb_set_errstring(ldb
, "Out of Memory");
108 static int lpdb_local_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
110 struct ldb_context
*ldb
;
111 struct lpdb_context
*ac
;
113 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
114 ldb
= ldb_module_get_ctx(ac
->module
);
117 return ldb_module_done(ac
->req
, NULL
, NULL
,
118 LDB_ERR_OPERATIONS_ERROR
);
120 if (ares
->error
!= LDB_SUCCESS
) {
121 return ldb_module_done(ac
->req
, ares
->controls
,
122 ares
->response
, ares
->error
);
125 if (ares
->type
!= LDB_REPLY_DONE
) {
126 ldb_set_errstring(ldb
, "Unexpected reply type");
128 return ldb_module_done(ac
->req
, NULL
, NULL
,
129 LDB_ERR_OPERATIONS_ERROR
);
133 return ldb_module_done(ac
->req
,
134 ac
->remote_done
->controls
,
135 ac
->remote_done
->response
,
136 ac
->remote_done
->error
);
139 /*****************************************************************************
141 ****************************************************************************/
143 static int lpdb_add_callback(struct ldb_request
*req
,
144 struct ldb_reply
*ares
);
146 static int local_password_add(struct ldb_module
*module
, struct ldb_request
*req
)
148 struct ldb_context
*ldb
;
149 struct ldb_message
*remote_message
;
150 struct ldb_request
*remote_req
;
151 struct lpdb_context
*ac
;
152 struct GUID objectGUID
;
156 ldb
= ldb_module_get_ctx(module
);
157 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_add\n");
159 if (ldb_dn_is_special(req
->op
.add
.message
->dn
)) { /* do not manipulate our control entries */
160 return ldb_next_request(module
, req
);
163 /* If the caller is manipulating the local passwords directly, let them pass */
164 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
165 req
->op
.add
.message
->dn
) == 0) {
166 return ldb_next_request(module
, req
);
169 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
170 if (ldb_msg_find_element(req
->op
.add
.message
, password_attrs
[i
])) {
175 /* It didn't match any of our password attributes, go on */
176 if (i
== ARRAY_SIZE(password_attrs
)) {
177 return ldb_next_request(module
, req
);
180 /* TODO: remove this when userPassword will be in schema */
181 if (!ldb_msg_check_string_attribute(req
->op
.add
.message
, "objectClass", "person")) {
182 ldb_asprintf_errstring(ldb
,
183 "Cannot relocate a password on entry: %s, does not have objectClass 'person'",
184 ldb_dn_get_linearized(req
->op
.add
.message
->dn
));
185 return LDB_ERR_OBJECT_CLASS_VIOLATION
;
188 /* From here, we assume we have password attributes to split off */
189 ac
= lpdb_init_context(module
, req
);
191 return LDB_ERR_OPERATIONS_ERROR
;
194 remote_message
= ldb_msg_copy_shallow(remote_req
, req
->op
.add
.message
);
195 if (remote_message
== NULL
) {
196 return LDB_ERR_OPERATIONS_ERROR
;
199 /* Remove any password attributes from the remote message */
200 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
201 ldb_msg_remove_attr(remote_message
, password_attrs
[i
]);
204 /* Find the objectGUID to use as the key */
205 objectGUID
= samdb_result_guid(ac
->req
->op
.add
.message
, "objectGUID");
207 ac
->local_message
= ldb_msg_copy_shallow(ac
, req
->op
.add
.message
);
208 if (ac
->local_message
== NULL
) {
209 return LDB_ERR_OPERATIONS_ERROR
;
212 /* Remove anything seen in the remote message from the local
213 * message (leaving only password attributes) */
214 for (i
=0; i
< remote_message
->num_elements
; i
++) {
215 ldb_msg_remove_attr(ac
->local_message
, remote_message
->elements
[i
].name
);
218 /* We must have an objectGUID already, or we don't know where
219 * to add the password. This may be changed to an 'add and
220 * search', to allow the directory to create the objectGUID */
221 if (ldb_msg_find_ldb_val(req
->op
.add
.message
, "objectGUID") == NULL
) {
222 ldb_set_errstring(ldb
,
223 "no objectGUID found in search: "
224 "local_password module must be "
225 "onfigured below objectGUID module!\n");
226 return LDB_ERR_CONSTRAINT_VIOLATION
;
229 ac
->local_message
->dn
= ldb_dn_new(ac
->local_message
,
231 if ((ac
->local_message
->dn
== NULL
) ||
232 ( ! ldb_dn_add_child_fmt(ac
->local_message
->dn
,
233 PASSWORD_GUID_ATTR
"=%s",
234 GUID_string(ac
->local_message
,
236 return LDB_ERR_OPERATIONS_ERROR
;
239 ret
= ldb_build_add_req(&remote_req
, ldb
, ac
,
242 ac
, lpdb_add_callback
,
244 if (ret
!= LDB_SUCCESS
) {
248 return ldb_next_request(module
, remote_req
);
251 /* Add a record, splitting password attributes from the user's main
253 static int lpdb_add_callback(struct ldb_request
*req
,
254 struct ldb_reply
*ares
)
256 struct ldb_context
*ldb
;
257 struct ldb_request
*local_req
;
258 struct lpdb_context
*ac
;
261 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
262 ldb
= ldb_module_get_ctx(ac
->module
);
265 return ldb_module_done(ac
->req
, NULL
, NULL
,
266 LDB_ERR_OPERATIONS_ERROR
);
268 if (ares
->error
!= LDB_SUCCESS
) {
269 return ldb_module_done(ac
->req
, ares
->controls
,
270 ares
->response
, ares
->error
);
273 if (ares
->type
!= LDB_REPLY_DONE
) {
274 ldb_set_errstring(ldb
, "Unexpected reply type");
276 return ldb_module_done(ac
->req
, NULL
, NULL
,
277 LDB_ERR_OPERATIONS_ERROR
);
280 ac
->remote_done
= talloc_steal(ac
, ares
);
282 ret
= ldb_build_add_req(&local_req
, ldb
, ac
,
285 ac
, lpdb_local_callback
,
287 if (ret
!= LDB_SUCCESS
) {
288 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
291 ret
= ldb_next_request(ac
->module
, local_req
);
292 if (ret
!= LDB_SUCCESS
) {
293 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
298 /*****************************************************************************
300 ****************************************************************************/
302 static int lpdb_modify_callabck(struct ldb_request
*req
,
303 struct ldb_reply
*ares
);
304 static int lpdb_mod_search_callback(struct ldb_request
*req
,
305 struct ldb_reply
*ares
);
307 static int local_password_modify(struct ldb_module
*module
, struct ldb_request
*req
)
309 struct ldb_context
*ldb
;
310 struct lpdb_context
*ac
;
311 struct ldb_message
*remote_message
;
312 struct ldb_request
*remote_req
;
316 ldb
= ldb_module_get_ctx(module
);
317 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_modify\n");
319 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) { /* do not manipulate our control entries */
320 return ldb_next_request(module
, req
);
323 /* If the caller is manipulating the local passwords directly, let them pass */
324 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
325 req
->op
.mod
.message
->dn
) == 0) {
326 return ldb_next_request(module
, req
);
329 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
330 if (ldb_msg_find_element(req
->op
.add
.message
, password_attrs
[i
])) {
335 /* It didn't match any of our password attributes, then we have nothing to do here */
336 if (i
== ARRAY_SIZE(password_attrs
)) {
337 return ldb_next_request(module
, req
);
340 /* From here, we assume we have password attributes to split off */
341 ac
= lpdb_init_context(module
, req
);
343 return LDB_ERR_OPERATIONS_ERROR
;
346 remote_message
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.mod
.message
);
347 if (remote_message
== NULL
) {
348 return LDB_ERR_OPERATIONS_ERROR
;
351 /* Remove any password attributes from the remote message */
352 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
353 ldb_msg_remove_attr(remote_message
, password_attrs
[i
]);
356 ac
->local_message
= ldb_msg_copy_shallow(ac
, ac
->req
->op
.mod
.message
);
357 if (ac
->local_message
== NULL
) {
358 return LDB_ERR_OPERATIONS_ERROR
;
361 /* Remove anything seen in the remote message from the local
362 * message (leaving only password attributes) */
363 for (i
=0; i
< remote_message
->num_elements
;i
++) {
364 ldb_msg_remove_attr(ac
->local_message
, remote_message
->elements
[i
].name
);
367 ret
= ldb_build_mod_req(&remote_req
, ldb
, ac
,
370 ac
, lpdb_modify_callabck
,
372 if (ret
!= LDB_SUCCESS
) {
376 return ldb_next_request(module
, remote_req
);
379 /* On a modify, we don't have the objectGUID handy, so we need to
380 * search our DN for it */
381 static int lpdb_modify_callabck(struct ldb_request
*req
,
382 struct ldb_reply
*ares
)
384 struct ldb_context
*ldb
;
385 static const char * const attrs
[] = { "objectGUID", "objectClass", NULL
};
386 struct ldb_request
*search_req
;
387 struct lpdb_context
*ac
;
390 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
391 ldb
= ldb_module_get_ctx(ac
->module
);
394 return ldb_module_done(ac
->req
, NULL
, NULL
,
395 LDB_ERR_OPERATIONS_ERROR
);
397 if (ares
->error
!= LDB_SUCCESS
) {
398 return ldb_module_done(ac
->req
, ares
->controls
,
399 ares
->response
, ares
->error
);
402 if (ares
->type
!= LDB_REPLY_DONE
) {
403 ldb_set_errstring(ldb
, "Unexpected reply type");
405 return ldb_module_done(ac
->req
, NULL
, NULL
,
406 LDB_ERR_OPERATIONS_ERROR
);
409 ac
->remote_done
= talloc_steal(ac
, ares
);
411 /* prepare the search operation */
412 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
413 ac
->req
->op
.mod
.message
->dn
, LDB_SCOPE_BASE
,
414 "(objectclass=*)", attrs
,
416 ac
, lpdb_mod_search_callback
,
418 if (ret
!= LDB_SUCCESS
) {
419 return ldb_module_done(ac
->req
, NULL
, NULL
,
420 LDB_ERR_OPERATIONS_ERROR
);
423 ret
= ldb_next_request(ac
->module
, search_req
);
424 if (ret
!= LDB_SUCCESS
) {
425 return ldb_module_done(ac
->req
, NULL
, NULL
,
426 LDB_ERR_OPERATIONS_ERROR
);
431 /* Called when we search for our own entry. Stores the one entry we
432 * expect (as it is a base search) on the context pointer */
433 static int lpdb_mod_search_callback(struct ldb_request
*req
,
434 struct ldb_reply
*ares
)
436 struct ldb_context
*ldb
;
437 struct ldb_request
*local_req
;
438 struct lpdb_context
*ac
;
439 struct ldb_dn
*local_dn
;
440 struct GUID objectGUID
;
441 int ret
= LDB_SUCCESS
;
443 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
444 ldb
= ldb_module_get_ctx(ac
->module
);
447 return ldb_module_done(ac
->req
, NULL
, NULL
,
448 LDB_ERR_OPERATIONS_ERROR
);
450 if (ares
->error
!= LDB_SUCCESS
) {
451 return ldb_module_done(ac
->req
, ares
->controls
,
452 ares
->response
, ares
->error
);
455 switch (ares
->type
) {
456 case LDB_REPLY_ENTRY
:
457 if (ac
->remote
!= NULL
) {
458 ldb_set_errstring(ldb
, "Too many results");
460 return ldb_module_done(ac
->req
, NULL
, NULL
,
461 LDB_ERR_OPERATIONS_ERROR
);
464 ac
->remote
= talloc_steal(ac
, ares
);
467 case LDB_REPLY_REFERRAL
:
474 /* After we find out the objectGUID for the entry, modify the local
475 * password database as required */
479 /* if it is not an entry of type person this is an error */
480 /* TODO: remove this when sambaPassword will be in schema */
481 if (ac
->remote
== NULL
) {
482 ldb_asprintf_errstring(ldb
,
483 "entry just modified (%s) not found!",
484 ldb_dn_get_linearized(req
->op
.search
.base
));
485 return ldb_module_done(ac
->req
, NULL
, NULL
,
486 LDB_ERR_OPERATIONS_ERROR
);
488 if (!ldb_msg_check_string_attribute(ac
->remote
->message
,
489 "objectClass", "person")) {
490 /* Not relevent to us */
491 return ldb_module_done(ac
->req
,
492 ac
->remote_done
->controls
,
493 ac
->remote_done
->response
,
494 ac
->remote_done
->error
);
497 if (ldb_msg_find_ldb_val(ac
->remote
->message
,
498 "objectGUID") == NULL
) {
499 ldb_set_errstring(ldb
,
500 "no objectGUID found in search: "
501 "local_password module must be "
502 "configured below objectGUID "
504 return ldb_module_done(ac
->req
, NULL
, NULL
,
505 LDB_ERR_OBJECT_CLASS_VIOLATION
);
508 objectGUID
= samdb_result_guid(ac
->remote
->message
,
511 local_dn
= ldb_dn_new(ac
, ldb
, LOCAL_BASE
);
512 if ((local_dn
== NULL
) ||
513 ( ! ldb_dn_add_child_fmt(local_dn
,
514 PASSWORD_GUID_ATTR
"=%s",
515 GUID_string(ac
, &objectGUID
)))) {
516 return ldb_module_done(ac
->req
, NULL
, NULL
,
517 LDB_ERR_OPERATIONS_ERROR
);
519 ac
->local_message
->dn
= local_dn
;
521 ret
= ldb_build_mod_req(&local_req
, ldb
, ac
,
524 ac
, lpdb_local_callback
,
526 if (ret
!= LDB_SUCCESS
) {
527 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
530 /* perform the local update */
531 ret
= ldb_next_request(ac
->module
, local_req
);
532 if (ret
!= LDB_SUCCESS
) {
533 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
540 /*****************************************************************************
542 ****************************************************************************/
544 static int lpdb_delete_callabck(struct ldb_request
*req
,
545 struct ldb_reply
*ares
);
546 static int lpdb_del_search_callback(struct ldb_request
*req
,
547 struct ldb_reply
*ares
);
549 static int local_password_delete(struct ldb_module
*module
,
550 struct ldb_request
*req
)
552 struct ldb_context
*ldb
;
553 struct ldb_request
*remote_req
;
554 struct lpdb_context
*ac
;
557 ldb
= ldb_module_get_ctx(module
);
558 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_delete\n");
560 /* do not manipulate our control entries */
561 if (ldb_dn_is_special(req
->op
.mod
.message
->dn
)) {
562 return ldb_next_request(module
, req
);
565 /* If the caller is manipulating the local passwords directly,
567 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
568 req
->op
.del
.dn
) == 0) {
569 return ldb_next_request(module
, req
);
572 /* From here, we assume we have password attributes to split off */
573 ac
= lpdb_init_context(module
, req
);
575 return LDB_ERR_OPERATIONS_ERROR
;
578 ret
= ldb_build_del_req(&remote_req
, ldb
, ac
,
581 ac
, lpdb_delete_callabck
,
583 if (ret
!= LDB_SUCCESS
) {
587 return ldb_next_request(module
, remote_req
);
590 /* On a modify, we don't have the objectGUID handy, so we need to
591 * search our DN for it */
592 static int lpdb_delete_callabck(struct ldb_request
*req
,
593 struct ldb_reply
*ares
)
595 struct ldb_context
*ldb
;
596 static const char * const attrs
[] = { "objectGUID", "objectClass", NULL
};
597 struct ldb_request
*search_req
;
598 struct lpdb_context
*ac
;
601 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
602 ldb
= ldb_module_get_ctx(ac
->module
);
605 return ldb_module_done(ac
->req
, NULL
, NULL
,
606 LDB_ERR_OPERATIONS_ERROR
);
608 if (ares
->error
!= LDB_SUCCESS
) {
609 return ldb_module_done(ac
->req
, ares
->controls
,
610 ares
->response
, ares
->error
);
613 if (ares
->type
!= LDB_REPLY_DONE
) {
614 ldb_set_errstring(ldb
, "Unexpected reply type");
616 return ldb_module_done(ac
->req
, NULL
, NULL
,
617 LDB_ERR_OPERATIONS_ERROR
);
620 ac
->remote_done
= talloc_steal(ac
, ares
);
622 /* prepare the search operation */
623 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
624 ac
->req
->op
.del
.dn
, LDB_SCOPE_BASE
,
625 "(objectclass=*)", attrs
,
627 ac
, lpdb_del_search_callback
,
629 if (ret
!= LDB_SUCCESS
) {
630 return ldb_module_done(ac
->req
, NULL
, NULL
,
631 LDB_ERR_OPERATIONS_ERROR
);
634 ret
= ldb_next_request(ac
->module
, search_req
);
635 if (ret
!= LDB_SUCCESS
) {
636 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
641 /* Called when we search for our own entry. Stores the one entry we
642 * expect (as it is a base search) on the context pointer */
643 static int lpdb_del_search_callback(struct ldb_request
*req
,
644 struct ldb_reply
*ares
)
646 struct ldb_context
*ldb
;
647 struct ldb_request
*local_req
;
648 struct lpdb_context
*ac
;
649 struct ldb_dn
*local_dn
;
650 struct GUID objectGUID
;
651 int ret
= LDB_SUCCESS
;
653 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
654 ldb
= ldb_module_get_ctx(ac
->module
);
657 return ldb_module_done(ac
->req
, NULL
, NULL
,
658 LDB_ERR_OPERATIONS_ERROR
);
660 if (ares
->error
!= LDB_SUCCESS
) {
661 return ldb_module_done(ac
->req
, ares
->controls
,
662 ares
->response
, ares
->error
);
665 switch (ares
->type
) {
666 case LDB_REPLY_ENTRY
:
667 if (ac
->remote
!= NULL
) {
668 ldb_set_errstring(ldb
, "Too many results");
670 return ldb_module_done(ac
->req
, NULL
, NULL
,
671 LDB_ERR_OPERATIONS_ERROR
);
674 ac
->remote
= talloc_steal(ac
, ares
);
677 case LDB_REPLY_REFERRAL
:
684 /* After we find out the objectGUID for the entry, modify the local
685 * password database as required */
689 /* if it is not an entry of type person this is NOT an error */
690 /* TODO: remove this when sambaPassword will be in schema */
691 if (ac
->remote
== NULL
) {
692 return ldb_module_done(ac
->req
,
693 ac
->remote_done
->controls
,
694 ac
->remote_done
->response
,
695 ac
->remote_done
->error
);
697 if (!ldb_msg_check_string_attribute(ac
->remote
->message
,
698 "objectClass", "person")) {
699 /* Not relevent to us */
700 return ldb_module_done(ac
->req
,
701 ac
->remote_done
->controls
,
702 ac
->remote_done
->response
,
703 ac
->remote_done
->error
);
706 if (ldb_msg_find_ldb_val(ac
->remote
->message
,
707 "objectGUID") == NULL
) {
708 ldb_set_errstring(ldb
,
709 "no objectGUID found in search: "
710 "local_password module must be "
711 "configured below objectGUID "
713 return ldb_module_done(ac
->req
, NULL
, NULL
,
714 LDB_ERR_OBJECT_CLASS_VIOLATION
);
717 objectGUID
= samdb_result_guid(ac
->remote
->message
,
720 local_dn
= ldb_dn_new(ac
, ldb
, LOCAL_BASE
);
721 if ((local_dn
== NULL
) ||
722 ( ! ldb_dn_add_child_fmt(local_dn
,
723 PASSWORD_GUID_ATTR
"=%s",
724 GUID_string(ac
, &objectGUID
)))) {
725 return ldb_module_done(ac
->req
, NULL
, NULL
,
726 LDB_ERR_OPERATIONS_ERROR
);
729 ret
= ldb_build_del_req(&local_req
, ldb
, ac
,
732 ac
, lpdb_local_callback
,
734 if (ret
!= LDB_SUCCESS
) {
735 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
738 /* perform the local update */
739 ret
= ldb_next_request(ac
->module
, local_req
);
740 if (ret
!= LDB_SUCCESS
) {
741 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
749 /*****************************************************************************
751 ****************************************************************************/
753 static int lpdb_local_search_callback(struct ldb_request
*req
,
754 struct ldb_reply
*ares
);
756 static int lpdb_local_search(struct lpdb_context
*ac
)
758 struct ldb_context
*ldb
;
759 struct ldb_request
*local_req
;
762 ldb
= ldb_module_get_ctx(ac
->module
);
764 ret
= ldb_build_search_req(&local_req
, ldb
, ac
,
765 ac
->current
->local_dn
,
768 ac
->req
->op
.search
.attrs
,
770 ac
, lpdb_local_search_callback
,
772 if (ret
!= LDB_SUCCESS
) {
773 return LDB_ERR_OPERATIONS_ERROR
;
776 return ldb_next_request(ac
->module
, local_req
);
779 static int lpdb_local_search_callback(struct ldb_request
*req
,
780 struct ldb_reply
*ares
)
782 struct ldb_context
*ldb
;
783 struct lpdb_context
*ac
;
784 struct ldb_reply
*merge
;
785 struct lpdb_reply
*lr
;
789 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
790 ldb
= ldb_module_get_ctx(ac
->module
);
793 return ldb_module_done(ac
->req
, NULL
, NULL
,
794 LDB_ERR_OPERATIONS_ERROR
);
796 if (ares
->error
!= LDB_SUCCESS
) {
797 return ldb_module_done(ac
->req
, ares
->controls
,
798 ares
->response
, ares
->error
);
803 /* we are interested only in a single reply (base search) */
804 switch (ares
->type
) {
805 case LDB_REPLY_ENTRY
:
807 if (lr
->remote
== NULL
) {
808 ldb_set_errstring(ldb
,
809 "Too many results for password entry search!");
811 return ldb_module_done(ac
->req
, NULL
, NULL
,
812 LDB_ERR_OPERATIONS_ERROR
);
818 /* steal the local results on the remote results to be
819 * returned all together */
820 talloc_steal(merge
, ares
->message
->elements
);
822 /* Make sure never to return the internal key attribute */
823 ldb_msg_remove_attr(ares
->message
, PASSWORD_GUID_ATTR
);
825 for (i
=0; i
< ares
->message
->num_elements
; i
++) {
826 struct ldb_message_element
*el
;
828 el
= ldb_msg_find_element(merge
->message
,
829 ares
->message
->elements
[i
].name
);
831 ret
= ldb_msg_add_empty(merge
->message
,
832 ares
->message
->elements
[i
].name
,
834 if (ret
!= LDB_SUCCESS
) {
836 return ldb_module_done(ac
->req
,
838 LDB_ERR_OPERATIONS_ERROR
);
840 *el
= ares
->message
->elements
[i
];
847 return ldb_module_send_entry(ac
->req
, merge
->message
, merge
->controls
);
849 case LDB_REPLY_REFERRAL
:
858 /* if this entry was not returned yet, return it now */
860 ret
= ldb_module_send_entry(ac
->req
, ac
->remote
->message
, ac
->remote
->controls
);
861 if (ret
!= LDB_SUCCESS
) {
862 return ldb_module_done(ac
->req
,
868 if (lr
->next
->remote
->type
== LDB_REPLY_DONE
) {
869 /* this was the last one */
870 return ldb_module_done(ac
->req
,
871 lr
->next
->remote
->controls
,
872 lr
->next
->remote
->response
,
873 lr
->next
->remote
->error
);
876 ac
->current
= lr
->next
;
879 ret
= lpdb_local_search(ac
);
880 if (ret
!= LDB_SUCCESS
) {
881 return ldb_module_done(ac
->req
,
890 /* For each entry returned in a remote search, do a local base search,
891 * based on the objectGUID we asked for as an additional attribute */
892 static int lpdb_remote_search_callback(struct ldb_request
*req
,
893 struct ldb_reply
*ares
)
895 struct ldb_context
*ldb
;
896 struct lpdb_context
*ac
;
897 struct ldb_dn
*local_dn
;
898 struct GUID objectGUID
;
899 struct lpdb_reply
*lr
;
902 ac
= talloc_get_type(req
->context
, struct lpdb_context
);
903 ldb
= ldb_module_get_ctx(ac
->module
);
906 return ldb_module_done(ac
->req
, NULL
, NULL
,
907 LDB_ERR_OPERATIONS_ERROR
);
909 if (ares
->error
!= LDB_SUCCESS
) {
910 return ldb_module_done(ac
->req
, ares
->controls
,
911 ares
->response
, ares
->error
);
914 switch (ares
->type
) {
915 case LDB_REPLY_ENTRY
:
916 /* No point searching further if it's not a 'person' entry */
917 if (!ldb_msg_check_string_attribute(ares
->message
, "objectClass", "person")) {
919 /* Make sure to remove anything we added */
920 if (ac
->added_objectGUID
) {
921 ldb_msg_remove_attr(ares
->message
, "objectGUID");
924 if (ac
->added_objectClass
) {
925 ldb_msg_remove_attr(ares
->message
, "objectClass");
928 return ldb_module_send_entry(ac
->req
, ares
->message
, ares
->controls
);
931 if (ldb_msg_find_ldb_val(ares
->message
, "objectGUID") == NULL
) {
932 ldb_set_errstring(ldb
,
933 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
934 return ldb_module_done(ac
->req
, NULL
, NULL
,
935 LDB_ERR_OPERATIONS_ERROR
);
938 objectGUID
= samdb_result_guid(ares
->message
, "objectGUID");
940 if (ac
->added_objectGUID
) {
941 ldb_msg_remove_attr(ares
->message
, "objectGUID");
944 if (ac
->added_objectClass
) {
945 ldb_msg_remove_attr(ares
->message
, "objectClass");
948 local_dn
= ldb_dn_new(ac
, ldb
, LOCAL_BASE
);
949 if ((local_dn
== NULL
) ||
950 (! ldb_dn_add_child_fmt(local_dn
,
951 PASSWORD_GUID_ATTR
"=%s",
952 GUID_string(ac
, &objectGUID
)))) {
953 return ldb_module_done(ac
->req
, NULL
, NULL
,
954 LDB_ERR_OPERATIONS_ERROR
);
957 lr
= talloc_zero(ac
, struct lpdb_reply
);
959 return ldb_module_done(ac
->req
, NULL
, NULL
,
960 LDB_ERR_OPERATIONS_ERROR
);
962 lr
->local_dn
= talloc_steal(lr
, local_dn
);
963 lr
->remote
= talloc_steal(lr
, ares
);
966 ac
->current
->next
= lr
;
974 case LDB_REPLY_REFERRAL
:
976 return ldb_module_send_referral(ac
->req
, ares
->referral
);
980 if (ac
->list
== NULL
) {
982 return ldb_module_done(ac
->req
, ares
->controls
,
983 ares
->response
, ares
->error
);
986 lr
= talloc_zero(ac
, struct lpdb_reply
);
988 return ldb_module_done(ac
->req
, NULL
, NULL
,
989 LDB_ERR_OPERATIONS_ERROR
);
991 lr
->remote
= talloc_steal(lr
, ares
);
993 ac
->current
->next
= lr
;
995 /* rewind current and start local searches */
996 ac
->current
= ac
->list
;
998 ret
= lpdb_local_search(ac
);
999 if (ret
!= LDB_SUCCESS
) {
1000 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
1007 /* Search for passwords and other attributes. The passwords are
1008 * local, but the other attributes are remote, and we need to glue the
1009 * two search spaces back togeather */
1011 static int local_password_search(struct ldb_module
*module
, struct ldb_request
*req
)
1013 struct ldb_context
*ldb
;
1014 struct ldb_request
*remote_req
;
1015 struct lpdb_context
*ac
;
1018 const char * const *search_attrs
= NULL
;
1020 ldb
= ldb_module_get_ctx(module
);
1021 ldb_debug(ldb
, LDB_DEBUG_TRACE
, "local_password_search\n");
1023 if (ldb_dn_is_special(req
->op
.search
.base
)) { /* do not manipulate our control entries */
1024 return ldb_next_request(module
, req
);
1027 search_attrs
= NULL
;
1029 /* If the caller is searching for the local passwords directly, let them pass */
1030 if (ldb_dn_compare_base(ldb_dn_new(req
, ldb
, LOCAL_BASE
),
1031 req
->op
.search
.base
) == 0) {
1032 return ldb_next_request(module
, req
);
1035 if (req
->op
.search
.attrs
&& (!ldb_attr_in_list(req
->op
.search
.attrs
, "*"))) {
1036 for (i
=0; i
< ARRAY_SIZE(password_attrs
); i
++) {
1037 if (ldb_attr_in_list(req
->op
.search
.attrs
, password_attrs
[i
])) {
1042 /* It didn't match any of our password attributes, go on */
1043 if (i
== ARRAY_SIZE(password_attrs
)) {
1044 return ldb_next_request(module
, req
);
1048 ac
= lpdb_init_context(module
, req
);
1050 return LDB_ERR_OPERATIONS_ERROR
;
1053 /* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
1054 if (req
->op
.search
.attrs
&& !ldb_attr_in_list(req
->op
.search
.attrs
, "*")) {
1055 if (!ldb_attr_in_list(req
->op
.search
.attrs
, "objectGUID")) {
1056 search_attrs
= ldb_attr_list_copy_add(ac
, req
->op
.search
.attrs
, "objectGUID");
1057 ac
->added_objectGUID
= true;
1058 if (!search_attrs
) {
1059 return LDB_ERR_OPERATIONS_ERROR
;
1062 search_attrs
= req
->op
.search
.attrs
;
1064 if (!ldb_attr_in_list(search_attrs
, "objectClass")) {
1065 search_attrs
= ldb_attr_list_copy_add(ac
, search_attrs
, "objectClass");
1066 ac
->added_objectClass
= true;
1067 if (!search_attrs
) {
1068 return LDB_ERR_OPERATIONS_ERROR
;
1072 search_attrs
= req
->op
.search
.attrs
;
1075 ret
= ldb_build_search_req_ex(&remote_req
, ldb
, ac
,
1076 req
->op
.search
.base
,
1077 req
->op
.search
.scope
,
1078 req
->op
.search
.tree
,
1081 ac
, lpdb_remote_search_callback
,
1083 if (ret
!= LDB_SUCCESS
) {
1087 /* perform the search */
1088 return ldb_next_request(module
, remote_req
);
1091 _PUBLIC_
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