/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- lpdb_init_context
- lpdb_local_callback
- local_password_add
- lpdb_add_callback
- local_password_modify
- lpdb_modify_callabck
- lpdb_mod_search_callback
- local_password_delete
- lpdb_delete_callabck
- lpdb_del_search_callback
- lpdb_local_search
- lpdb_local_search_callback
- lpdb_remote_search_callback
- local_password_search
1 /*
2 ldb database module
3
4 Copyright (C) Simo Sorce 2004-2008
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 userPassword and friends
28 *
29 * Author: Andrew Bartlett
30 */
31
32 #include "includes.h"
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"
38
39 #define PASSWORD_GUID_ATTR "masterGUID"
40
41 /* This module maintains a local password database, seperate from the main LDAP server.
42
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)
46
47 Each incoming add/modify is split into a remote, and a local request, done in that order.
48
49 We maintain a list of attributes that are kept locally - perhaps
50 this should use the @KLUDGE_ACL list of passwordAttribute
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_reply {
66 struct lpdb_reply *next;
67 struct ldb_reply *remote;
68 struct ldb_dn *local_dn;
69 };
70
71 struct lpdb_context {
72
73 struct ldb_module *module;
74 struct ldb_request *req;
75
76 struct ldb_message *local_message;
77
78 struct lpdb_reply *list;
79 struct lpdb_reply *current;
80 struct ldb_reply *remote_done;
81 struct ldb_reply *remote;
82
83 bool added_objectGUID;
84 bool added_objectClass;
85
86 };
87
88 static struct lpdb_context *lpdb_init_context(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
89 struct ldb_request *req)
90 {
91 struct ldb_context *ldb;
92 struct lpdb_context *ac;
93
94 ldb = ldb_module_get_ctx(module);
95
96 ac = talloc_zero(req, struct lpdb_context);
97 if (ac == NULL) {
98 ldb_set_errstring(ldb, "Out of Memory");
99 return NULL;
100 }
101
102 ac->module = module;
103 ac->req = req;
104
105 return ac;
106 }
107
108 static int lpdb_local_callback(struct ldb_request *req, struct ldb_reply *ares)
/* [<][>][^][v][top][bottom][index][help] */
109 {
110 struct ldb_context *ldb;
111 struct lpdb_context *ac;
112
113 ac = talloc_get_type(req->context, struct lpdb_context);
114 ldb = ldb_module_get_ctx(ac->module);
115
116 if (!ares) {
117 return ldb_module_done(ac->req, NULL, NULL,
118 LDB_ERR_OPERATIONS_ERROR);
119 }
120 if (ares->error != LDB_SUCCESS) {
121 return ldb_module_done(ac->req, ares->controls,
122 ares->response, ares->error);
123 }
124
125 if (ares->type != LDB_REPLY_DONE) {
126 ldb_set_errstring(ldb, "Unexpected reply type");
127 talloc_free(ares);
128 return ldb_module_done(ac->req, NULL, NULL,
129 LDB_ERR_OPERATIONS_ERROR);
130 }
131
132 talloc_free(ares);
133 return ldb_module_done(ac->req,
134 ac->remote_done->controls,
135 ac->remote_done->response,
136 ac->remote_done->error);
137 }
138
139 /*****************************************************************************
140 * ADD
141 ****************************************************************************/
142
143 static int lpdb_add_callback(struct ldb_request *req,
144 struct ldb_reply *ares);
145
146 static int local_password_add(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
147 {
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;
153 int ret;
154 int i;
155
156 ldb = ldb_module_get_ctx(module);
157 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_add\n");
158
159 if (ldb_dn_is_special(req->op.add.message->dn)) { /* do not manipulate our control entries */
160 return ldb_next_request(module, req);
161 }
162
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);
167 }
168
169 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
170 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
171 break;
172 }
173 }
174
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);
178 }
179
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;
186 }
187
188 /* From here, we assume we have password attributes to split off */
189 ac = lpdb_init_context(module, req);
190 if (!ac) {
191 return LDB_ERR_OPERATIONS_ERROR;
192 }
193
194 remote_message = ldb_msg_copy_shallow(remote_req, req->op.add.message);
195 if (remote_message == NULL) {
196 return LDB_ERR_OPERATIONS_ERROR;
197 }
198
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]);
202 }
203
204 /* Find the objectGUID to use as the key */
205 objectGUID = samdb_result_guid(ac->req->op.add.message, "objectGUID");
206
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;
210 }
211
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);
216 }
217
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;
227 }
228
229 ac->local_message->dn = ldb_dn_new(ac->local_message,
230 ldb, LOCAL_BASE);
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,
235 &objectGUID)))) {
236 return LDB_ERR_OPERATIONS_ERROR;
237 }
238
239 ret = ldb_build_add_req(&remote_req, ldb, ac,
240 remote_message,
241 req->controls,
242 ac, lpdb_add_callback,
243 req);
244 if (ret != LDB_SUCCESS) {
245 return ret;
246 }
247
248 return ldb_next_request(module, remote_req);
249 }
250
251 /* Add a record, splitting password attributes from the user's main
252 * record */
253 static int lpdb_add_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
254 struct ldb_reply *ares)
255 {
256 struct ldb_context *ldb;
257 struct ldb_request *local_req;
258 struct lpdb_context *ac;
259 int ret;
260
261 ac = talloc_get_type(req->context, struct lpdb_context);
262 ldb = ldb_module_get_ctx(ac->module);
263
264 if (!ares) {
265 return ldb_module_done(ac->req, NULL, NULL,
266 LDB_ERR_OPERATIONS_ERROR);
267 }
268 if (ares->error != LDB_SUCCESS) {
269 return ldb_module_done(ac->req, ares->controls,
270 ares->response, ares->error);
271 }
272
273 if (ares->type != LDB_REPLY_DONE) {
274 ldb_set_errstring(ldb, "Unexpected reply type");
275 talloc_free(ares);
276 return ldb_module_done(ac->req, NULL, NULL,
277 LDB_ERR_OPERATIONS_ERROR);
278 }
279
280 ac->remote_done = talloc_steal(ac, ares);
281
282 ret = ldb_build_add_req(&local_req, ldb, ac,
283 ac->local_message,
284 NULL,
285 ac, lpdb_local_callback,
286 ac->req);
287 if (ret != LDB_SUCCESS) {
288 return ldb_module_done(ac->req, NULL, NULL, ret);
289 }
290
291 ret = ldb_next_request(ac->module, local_req);
292 if (ret != LDB_SUCCESS) {
293 return ldb_module_done(ac->req, NULL, NULL, ret);
294 }
295 return LDB_SUCCESS;
296 }
297
298 /*****************************************************************************
299 * MODIFY
300 ****************************************************************************/
301
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);
306
307 static int local_password_modify(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
308 {
309 struct ldb_context *ldb;
310 struct lpdb_context *ac;
311 struct ldb_message *remote_message;
312 struct ldb_request *remote_req;
313 int ret;
314 int i;
315
316 ldb = ldb_module_get_ctx(module);
317 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_modify\n");
318
319 if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */
320 return ldb_next_request(module, req);
321 }
322
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);
327 }
328
329 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
330 if (ldb_msg_find_element(req->op.add.message, password_attrs[i])) {
331 break;
332 }
333 }
334
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);
338 }
339
340 /* From here, we assume we have password attributes to split off */
341 ac = lpdb_init_context(module, req);
342 if (!ac) {
343 return LDB_ERR_OPERATIONS_ERROR;
344 }
345
346 remote_message = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
347 if (remote_message == NULL) {
348 return LDB_ERR_OPERATIONS_ERROR;
349 }
350
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]);
354 }
355
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;
359 }
360
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);
365 }
366
367 ret = ldb_build_mod_req(&remote_req, ldb, ac,
368 remote_message,
369 req->controls,
370 ac, lpdb_modify_callabck,
371 req);
372 if (ret != LDB_SUCCESS) {
373 return ret;
374 }
375
376 return ldb_next_request(module, remote_req);
377 }
378
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,
/* [<][>][^][v][top][bottom][index][help] */
382 struct ldb_reply *ares)
383 {
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;
388 int ret;
389
390 ac = talloc_get_type(req->context, struct lpdb_context);
391 ldb = ldb_module_get_ctx(ac->module);
392
393 if (!ares) {
394 return ldb_module_done(ac->req, NULL, NULL,
395 LDB_ERR_OPERATIONS_ERROR);
396 }
397 if (ares->error != LDB_SUCCESS) {
398 return ldb_module_done(ac->req, ares->controls,
399 ares->response, ares->error);
400 }
401
402 if (ares->type != LDB_REPLY_DONE) {
403 ldb_set_errstring(ldb, "Unexpected reply type");
404 talloc_free(ares);
405 return ldb_module_done(ac->req, NULL, NULL,
406 LDB_ERR_OPERATIONS_ERROR);
407 }
408
409 ac->remote_done = talloc_steal(ac, ares);
410
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,
415 NULL,
416 ac, lpdb_mod_search_callback,
417 ac->req);
418 if (ret != LDB_SUCCESS) {
419 return ldb_module_done(ac->req, NULL, NULL,
420 LDB_ERR_OPERATIONS_ERROR);
421 }
422
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);
427 }
428 return LDB_SUCCESS;
429 }
430
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,
/* [<][>][^][v][top][bottom][index][help] */
434 struct ldb_reply *ares)
435 {
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;
442
443 ac = talloc_get_type(req->context, struct lpdb_context);
444 ldb = ldb_module_get_ctx(ac->module);
445
446 if (!ares) {
447 return ldb_module_done(ac->req, NULL, NULL,
448 LDB_ERR_OPERATIONS_ERROR);
449 }
450 if (ares->error != LDB_SUCCESS) {
451 return ldb_module_done(ac->req, ares->controls,
452 ares->response, ares->error);
453 }
454
455 switch (ares->type) {
456 case LDB_REPLY_ENTRY:
457 if (ac->remote != NULL) {
458 ldb_set_errstring(ldb, "Too many results");
459 talloc_free(ares);
460 return ldb_module_done(ac->req, NULL, NULL,
461 LDB_ERR_OPERATIONS_ERROR);
462 }
463
464 ac->remote = talloc_steal(ac, ares);
465 break;
466
467 case LDB_REPLY_REFERRAL:
468
469 /* ignore */
470 talloc_free(ares);
471 break;
472
473 case LDB_REPLY_DONE:
474 /* After we find out the objectGUID for the entry, modify the local
475 * password database as required */
476
477 talloc_free(ares);
478
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);
487 }
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);
495 }
496
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 "
503 "module!\n");
504 return ldb_module_done(ac->req, NULL, NULL,
505 LDB_ERR_OBJECT_CLASS_VIOLATION);
506 }
507
508 objectGUID = samdb_result_guid(ac->remote->message,
509 "objectGUID");
510
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);
518 }
519 ac->local_message->dn = local_dn;
520
521 ret = ldb_build_mod_req(&local_req, ldb, ac,
522 ac->local_message,
523 NULL,
524 ac, lpdb_local_callback,
525 ac->req);
526 if (ret != LDB_SUCCESS) {
527 return ldb_module_done(ac->req, NULL, NULL, ret);
528 }
529
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);
534 }
535 }
536
537 return LDB_SUCCESS;
538 }
539
540 /*****************************************************************************
541 * DELETE
542 ****************************************************************************/
543
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);
548
549 static int local_password_delete(struct ldb_module *module,
/* [<][>][^][v][top][bottom][index][help] */
550 struct ldb_request *req)
551 {
552 struct ldb_context *ldb;
553 struct ldb_request *remote_req;
554 struct lpdb_context *ac;
555 int ret;
556
557 ldb = ldb_module_get_ctx(module);
558 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_delete\n");
559
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);
563 }
564
565 /* If the caller is manipulating the local passwords directly,
566 * let them pass */
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);
570 }
571
572 /* From here, we assume we have password attributes to split off */
573 ac = lpdb_init_context(module, req);
574 if (!ac) {
575 return LDB_ERR_OPERATIONS_ERROR;
576 }
577
578 ret = ldb_build_del_req(&remote_req, ldb, ac,
579 req->op.del.dn,
580 req->controls,
581 ac, lpdb_delete_callabck,
582 req);
583 if (ret != LDB_SUCCESS) {
584 return ret;
585 }
586
587 return ldb_next_request(module, remote_req);
588 }
589
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,
/* [<][>][^][v][top][bottom][index][help] */
593 struct ldb_reply *ares)
594 {
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;
599 int ret;
600
601 ac = talloc_get_type(req->context, struct lpdb_context);
602 ldb = ldb_module_get_ctx(ac->module);
603
604 if (!ares) {
605 return ldb_module_done(ac->req, NULL, NULL,
606 LDB_ERR_OPERATIONS_ERROR);
607 }
608 if (ares->error != LDB_SUCCESS) {
609 return ldb_module_done(ac->req, ares->controls,
610 ares->response, ares->error);
611 }
612
613 if (ares->type != LDB_REPLY_DONE) {
614 ldb_set_errstring(ldb, "Unexpected reply type");
615 talloc_free(ares);
616 return ldb_module_done(ac->req, NULL, NULL,
617 LDB_ERR_OPERATIONS_ERROR);
618 }
619
620 ac->remote_done = talloc_steal(ac, ares);
621
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,
626 NULL,
627 ac, lpdb_del_search_callback,
628 ac->req);
629 if (ret != LDB_SUCCESS) {
630 return ldb_module_done(ac->req, NULL, NULL,
631 LDB_ERR_OPERATIONS_ERROR);
632 }
633
634 ret = ldb_next_request(ac->module, search_req);
635 if (ret != LDB_SUCCESS) {
636 return ldb_module_done(ac->req, NULL, NULL,
637 LDB_ERR_OPERATIONS_ERROR);
638 }
639 return LDB_SUCCESS;
640 }
641
642 /* Called when we search for our own entry. Stores the one entry we
643 * expect (as it is a base search) on the context pointer */
644 static int lpdb_del_search_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
645 struct ldb_reply *ares)
646 {
647 struct ldb_context *ldb;
648 struct ldb_request *local_req;
649 struct lpdb_context *ac;
650 struct ldb_dn *local_dn;
651 struct GUID objectGUID;
652 int ret = LDB_SUCCESS;
653
654 ac = talloc_get_type(req->context, struct lpdb_context);
655 ldb = ldb_module_get_ctx(ac->module);
656
657 if (!ares) {
658 return ldb_module_done(ac->req, NULL, NULL,
659 LDB_ERR_OPERATIONS_ERROR);
660 }
661 if (ares->error != LDB_SUCCESS) {
662 return ldb_module_done(ac->req, ares->controls,
663 ares->response, ares->error);
664 }
665
666 switch (ares->type) {
667 case LDB_REPLY_ENTRY:
668 if (ac->remote != NULL) {
669 ldb_set_errstring(ldb, "Too many results");
670 talloc_free(ares);
671 return ldb_module_done(ac->req, NULL, NULL,
672 LDB_ERR_OPERATIONS_ERROR);
673 }
674
675 ac->remote = talloc_steal(ac, ares);
676 break;
677
678 case LDB_REPLY_REFERRAL:
679
680 /* ignore */
681 talloc_free(ares);
682 break;
683
684 case LDB_REPLY_DONE:
685 /* After we find out the objectGUID for the entry, modify the local
686 * password database as required */
687
688 talloc_free(ares);
689
690 /* if it is not an entry of type person this is NOT an error */
691 /* TODO: remove this when sambaPassword will be in schema */
692 if (ac->remote == NULL) {
693 return ldb_module_done(ac->req,
694 ac->remote_done->controls,
695 ac->remote_done->response,
696 ac->remote_done->error);
697 }
698 if (!ldb_msg_check_string_attribute(ac->remote->message,
699 "objectClass", "person")) {
700 /* Not relevent to us */
701 return ldb_module_done(ac->req,
702 ac->remote_done->controls,
703 ac->remote_done->response,
704 ac->remote_done->error);
705 }
706
707 if (ldb_msg_find_ldb_val(ac->remote->message,
708 "objectGUID") == NULL) {
709 ldb_set_errstring(ldb,
710 "no objectGUID found in search: "
711 "local_password module must be "
712 "configured below objectGUID "
713 "module!\n");
714 return ldb_module_done(ac->req, NULL, NULL,
715 LDB_ERR_OBJECT_CLASS_VIOLATION);
716 }
717
718 objectGUID = samdb_result_guid(ac->remote->message,
719 "objectGUID");
720
721 local_dn = ldb_dn_new(ac, ldb, LOCAL_BASE);
722 if ((local_dn == NULL) ||
723 ( ! ldb_dn_add_child_fmt(local_dn,
724 PASSWORD_GUID_ATTR "=%s",
725 GUID_string(ac, &objectGUID)))) {
726 return ldb_module_done(ac->req, NULL, NULL,
727 LDB_ERR_OPERATIONS_ERROR);
728 }
729
730 ret = ldb_build_del_req(&local_req, ldb, ac,
731 local_dn,
732 NULL,
733 ac, lpdb_local_callback,
734 ac->req);
735 if (ret != LDB_SUCCESS) {
736 return ldb_module_done(ac->req, NULL, NULL, ret);
737 }
738
739 /* perform the local update */
740 ret = ldb_next_request(ac->module, local_req);
741 if (ret != LDB_SUCCESS) {
742 return ldb_module_done(ac->req, NULL, NULL, ret);
743 }
744 }
745
746 return LDB_SUCCESS;
747 }
748
749
750 /*****************************************************************************
751 * SEARCH
752 ****************************************************************************/
753
754 static int lpdb_local_search_callback(struct ldb_request *req,
755 struct ldb_reply *ares);
756
757 static int lpdb_local_search(struct lpdb_context *ac)
/* [<][>][^][v][top][bottom][index][help] */
758 {
759 struct ldb_context *ldb;
760 struct ldb_request *local_req;
761 int ret;
762
763 ldb = ldb_module_get_ctx(ac->module);
764
765 ret = ldb_build_search_req(&local_req, ldb, ac,
766 ac->current->local_dn,
767 LDB_SCOPE_BASE,
768 "(objectclass=*)",
769 ac->req->op.search.attrs,
770 NULL,
771 ac, lpdb_local_search_callback,
772 ac->req);
773 if (ret != LDB_SUCCESS) {
774 return LDB_ERR_OPERATIONS_ERROR;
775 }
776
777 return ldb_next_request(ac->module, local_req);
778 }
779
780 static int lpdb_local_search_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
781 struct ldb_reply *ares)
782 {
783 struct ldb_context *ldb;
784 struct lpdb_context *ac;
785 struct ldb_reply *merge;
786 struct lpdb_reply *lr;
787 int ret;
788 int i;
789
790 ac = talloc_get_type(req->context, struct lpdb_context);
791 ldb = ldb_module_get_ctx(ac->module);
792
793 if (!ares) {
794 return ldb_module_done(ac->req, NULL, NULL,
795 LDB_ERR_OPERATIONS_ERROR);
796 }
797 if (ares->error != LDB_SUCCESS) {
798 return ldb_module_done(ac->req, ares->controls,
799 ares->response, ares->error);
800 }
801
802 lr = ac->current;
803
804 /* we are interested only in a single reply (base search) */
805 switch (ares->type) {
806 case LDB_REPLY_ENTRY:
807
808 if (lr->remote == NULL) {
809 ldb_set_errstring(ldb,
810 "Too many results for password entry search!");
811 talloc_free(ares);
812 return ldb_module_done(ac->req, NULL, NULL,
813 LDB_ERR_OPERATIONS_ERROR);
814 }
815
816 merge = lr->remote;
817 lr->remote = NULL;
818
819 /* steal the local results on the remote results to be
820 * returned all together */
821 talloc_steal(merge, ares->message->elements);
822
823 /* Make sure never to return the internal key attribute */
824 ldb_msg_remove_attr(ares->message, PASSWORD_GUID_ATTR);
825
826 for (i=0; i < ares->message->num_elements; i++) {
827 struct ldb_message_element *el;
828
829 el = ldb_msg_find_element(merge->message,
830 ares->message->elements[i].name);
831 if (!el) {
832 ret = ldb_msg_add_empty(merge->message,
833 ares->message->elements[i].name,
834 0, &el);
835 if (ret != LDB_SUCCESS) {
836 talloc_free(ares);
837 return ldb_module_done(ac->req,
838 NULL, NULL,
839 LDB_ERR_OPERATIONS_ERROR);
840 }
841 *el = ares->message->elements[i];
842 }
843 }
844
845 /* free the rest */
846 talloc_free(ares);
847
848 return ldb_module_send_entry(ac->req, merge->message, merge->controls);
849
850 case LDB_REPLY_REFERRAL:
851 /* ignore */
852 talloc_free(ares);
853 break;
854
855 case LDB_REPLY_DONE:
856
857 talloc_free(ares);
858
859 /* if this entry was not returned yet, return it now */
860 if (lr->remote) {
861 ret = ldb_module_send_entry(ac->req, ac->remote->message, ac->remote->controls);
862 if (ret != LDB_SUCCESS) {
863 return ldb_module_done(ac->req,
864 NULL, NULL, ret);
865 }
866 lr->remote = NULL;
867 }
868
869 if (lr->next->remote->type == LDB_REPLY_DONE) {
870 /* this was the last one */
871 return ldb_module_done(ac->req,
872 lr->next->remote->controls,
873 lr->next->remote->response,
874 lr->next->remote->error);
875 } else {
876 /* next one */
877 ac->current = lr->next;
878 talloc_free(lr);
879
880 ret = lpdb_local_search(ac);
881 if (ret != LDB_SUCCESS) {
882 return ldb_module_done(ac->req,
883 NULL, NULL, ret);
884 }
885 }
886 }
887
888 return LDB_SUCCESS;
889 }
890
891 /* For each entry returned in a remote search, do a local base search,
892 * based on the objectGUID we asked for as an additional attribute */
893 static int lpdb_remote_search_callback(struct ldb_request *req,
/* [<][>][^][v][top][bottom][index][help] */
894 struct ldb_reply *ares)
895 {
896 struct ldb_context *ldb;
897 struct lpdb_context *ac;
898 struct ldb_dn *local_dn;
899 struct GUID objectGUID;
900 struct lpdb_reply *lr;
901 int ret;
902
903 ac = talloc_get_type(req->context, struct lpdb_context);
904 ldb = ldb_module_get_ctx(ac->module);
905
906 if (!ares) {
907 return ldb_module_done(ac->req, NULL, NULL,
908 LDB_ERR_OPERATIONS_ERROR);
909 }
910 if (ares->error != LDB_SUCCESS) {
911 return ldb_module_done(ac->req, ares->controls,
912 ares->response, ares->error);
913 }
914
915 switch (ares->type) {
916 case LDB_REPLY_ENTRY:
917 /* No point searching further if it's not a 'person' entry */
918 if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
919
920 /* Make sure to remove anything we added */
921 if (ac->added_objectGUID) {
922 ldb_msg_remove_attr(ares->message, "objectGUID");
923 }
924
925 if (ac->added_objectClass) {
926 ldb_msg_remove_attr(ares->message, "objectClass");
927 }
928
929 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
930 }
931
932 if (ldb_msg_find_ldb_val(ares->message, "objectGUID") == NULL) {
933 ldb_set_errstring(ldb,
934 "no objectGUID found in search: local_password module must be configured below objectGUID module!\n");
935 return ldb_module_done(ac->req, NULL, NULL,
936 LDB_ERR_OPERATIONS_ERROR);
937 }
938
939 objectGUID = samdb_result_guid(ares->message, "objectGUID");
940
941 if (ac->added_objectGUID) {
942 ldb_msg_remove_attr(ares->message, "objectGUID");
943 }
944
945 if (ac->added_objectClass) {
946 ldb_msg_remove_attr(ares->message, "objectClass");
947 }
948
949 local_dn = ldb_dn_new(ac, ldb, LOCAL_BASE);
950 if ((local_dn == NULL) ||
951 (! ldb_dn_add_child_fmt(local_dn,
952 PASSWORD_GUID_ATTR "=%s",
953 GUID_string(ac, &objectGUID)))) {
954 return ldb_module_done(ac->req, NULL, NULL,
955 LDB_ERR_OPERATIONS_ERROR);
956 }
957
958 lr = talloc_zero(ac, struct lpdb_reply);
959 if (lr == NULL) {
960 return ldb_module_done(ac->req, NULL, NULL,
961 LDB_ERR_OPERATIONS_ERROR);
962 }
963 lr->local_dn = talloc_steal(lr, local_dn);
964 lr->remote = talloc_steal(lr, ares);
965
966 if (ac->list) {
967 ac->current->next = lr;
968 } else {
969 ac->list = lr;
970 }
971 ac->current= lr;
972
973 break;
974
975 case LDB_REPLY_REFERRAL:
976
977 return ldb_module_send_referral(ac->req, ares->referral);
978
979 case LDB_REPLY_DONE:
980
981 if (ac->list == NULL) {
982 /* found nothing */
983 return ldb_module_done(ac->req, ares->controls,
984 ares->response, ares->error);
985 }
986
987 lr = talloc_zero(ac, struct lpdb_reply);
988 if (lr == NULL) {
989 return ldb_module_done(ac->req, NULL, NULL,
990 LDB_ERR_OPERATIONS_ERROR);
991 }
992 lr->remote = talloc_steal(lr, ares);
993
994 ac->current->next = lr;
995
996 /* rewind current and start local searches */
997 ac->current= ac->list;
998
999 ret = lpdb_local_search(ac);
1000 if (ret != LDB_SUCCESS) {
1001 return ldb_module_done(ac->req, NULL, NULL, ret);
1002 }
1003 }
1004
1005 return LDB_SUCCESS;
1006 }
1007
1008 /* Search for passwords and other attributes. The passwords are
1009 * local, but the other attributes are remote, and we need to glue the
1010 * two search spaces back togeather */
1011
1012 static int local_password_search(struct ldb_module *module, struct ldb_request *req)
/* [<][>][^][v][top][bottom][index][help] */
1013 {
1014 struct ldb_context *ldb;
1015 struct ldb_request *remote_req;
1016 struct lpdb_context *ac;
1017 int i;
1018 int ret;
1019 const char * const *search_attrs = NULL;
1020
1021 ldb = ldb_module_get_ctx(module);
1022 ldb_debug(ldb, LDB_DEBUG_TRACE, "local_password_search\n");
1023
1024 if (ldb_dn_is_special(req->op.search.base)) { /* do not manipulate our control entries */
1025 return ldb_next_request(module, req);
1026 }
1027
1028 search_attrs = NULL;
1029
1030 /* If the caller is searching for the local passwords directly, let them pass */
1031 if (ldb_dn_compare_base(ldb_dn_new(req, ldb, LOCAL_BASE),
1032 req->op.search.base) == 0) {
1033 return ldb_next_request(module, req);
1034 }
1035
1036 if (req->op.search.attrs && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
1037 for (i=0; i < ARRAY_SIZE(password_attrs); i++) {
1038 if (ldb_attr_in_list(req->op.search.attrs, password_attrs[i])) {
1039 break;
1040 }
1041 }
1042
1043 /* It didn't match any of our password attributes, go on */
1044 if (i == ARRAY_SIZE(password_attrs)) {
1045 return ldb_next_request(module, req);
1046 }
1047 }
1048
1049 ac = lpdb_init_context(module, req);
1050 if (!ac) {
1051 return LDB_ERR_OPERATIONS_ERROR;
1052 }
1053
1054 /* Remote search is for all attributes: if the remote LDAP server has these attributes, then it overrides the local database */
1055 if (req->op.search.attrs && !ldb_attr_in_list(req->op.search.attrs, "*")) {
1056 if (!ldb_attr_in_list(req->op.search.attrs, "objectGUID")) {
1057 search_attrs = ldb_attr_list_copy_add(ac, req->op.search.attrs, "objectGUID");
1058 ac->added_objectGUID = true;
1059 if (!search_attrs) {
1060 return LDB_ERR_OPERATIONS_ERROR;
1061 }
1062 } else {
1063 search_attrs = req->op.search.attrs;
1064 }
1065 if (!ldb_attr_in_list(search_attrs, "objectClass")) {
1066 search_attrs = ldb_attr_list_copy_add(ac, search_attrs, "objectClass");
1067 ac->added_objectClass = true;
1068 if (!search_attrs) {
1069 return LDB_ERR_OPERATIONS_ERROR;
1070 }
1071 }
1072 } else {
1073 search_attrs = req->op.search.attrs;
1074 }
1075
1076 ret = ldb_build_search_req_ex(&remote_req, ldb, ac,
1077 req->op.search.base,
1078 req->op.search.scope,
1079 req->op.search.tree,
1080 search_attrs,
1081 req->controls,
1082 ac, lpdb_remote_search_callback,
1083 req);
1084 if (ret != LDB_SUCCESS) {
1085 return LDB_ERR_OPERATIONS_ERROR;
1086 }
1087
1088 /* perform the search */
1089 return ldb_next_request(module, remote_req);
1090 }
1091
1092 _PUBLIC_ const struct ldb_module_ops ldb_local_password_module_ops = {
1093 .name = "local_password",
1094 .add = local_password_add,
1095 .modify = local_password_modify,
1096 .del = local_password_delete,
1097 .search = local_password_search
1098 };