4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2012
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Component: ldb secrets_tdb_sync module
25 * Description: Update secrets.tdb whenever the matching secret record changes
27 * Author: Andrew Bartlett
31 #include "ldb_module.h"
32 #include "lib/util/dlinklist.h"
33 #include "auth/credentials/credentials.h"
34 #include "auth/credentials/credentials_krb5.h"
35 #include "system/kerberos.h"
36 #include "auth/kerberos/kerberos.h"
37 #include "auth/kerberos/kerberos_srv_keytab.h"
38 #include "dsdb/samdb/ldb_modules/util.h"
39 #include "param/secrets.h"
40 #include "source3/include/secrets.h"
41 #include "lib/dbwrap/dbwrap.h"
42 #include "dsdb/samdb/samdb.h"
45 struct ldb_message
*msg
;
47 struct dn_list
*prev
, *next
;
50 struct secrets_tdb_sync_private
{
51 struct dn_list
*changed_dns
;
52 struct db_context
*secrets_tdb
;
55 struct secrets_tdb_sync_ctx
{
56 struct ldb_module
*module
;
57 struct ldb_request
*req
;
62 struct ldb_reply
*op_reply
;
66 static struct secrets_tdb_sync_ctx
*secrets_tdb_sync_ctx_init(struct ldb_module
*module
,
67 struct ldb_request
*req
)
69 struct secrets_tdb_sync_ctx
*ac
;
71 ac
= talloc_zero(req
, struct secrets_tdb_sync_ctx
);
73 ldb_oom(ldb_module_get_ctx(module
));
83 /* FIXME: too many semi-async searches here for my taste, direct and indirect as
84 * cli_credentials_set_secrets() performs a sync ldb search.
85 * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
86 * of async issues). -SSS
88 static int add_modified(struct ldb_module
*module
, struct ldb_dn
*dn
, bool do_delete
,
89 struct ldb_request
*parent
)
91 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
92 struct secrets_tdb_sync_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct secrets_tdb_sync_private
);
95 struct ldb_result
*res
;
98 filter
= talloc_asprintf(data
,
99 "(&(objectClass=primaryDomain)(flatname=*))");
104 ret
= dsdb_module_search(module
, data
, &res
,
105 dn
, LDB_SCOPE_BASE
, NULL
,
106 DSDB_FLAG_NEXT_MODULE
, parent
,
109 if (ret
!= LDB_SUCCESS
) {
113 if (res
->count
!= 1) {
114 /* if it's not a primaryDomain then we don't have anything to update */
119 item
= talloc(data
->changed_dns
? (void *)data
->changed_dns
: (void *)data
, struct dn_list
);
125 item
->msg
= talloc_steal(item
, res
->msgs
[0]);
126 item
->do_delete
= do_delete
;
129 DLIST_ADD_END(data
->changed_dns
, item
, struct dn_list
*);
133 static int ust_search_modified(struct secrets_tdb_sync_ctx
*ac
);
135 static int secrets_tdb_sync_op_callback(struct ldb_request
*req
,
136 struct ldb_reply
*ares
)
138 struct ldb_context
*ldb
;
139 struct secrets_tdb_sync_ctx
*ac
;
142 ac
= talloc_get_type(req
->context
, struct secrets_tdb_sync_ctx
);
143 ldb
= ldb_module_get_ctx(ac
->module
);
146 return ldb_module_done(ac
->req
, NULL
, NULL
,
147 LDB_ERR_OPERATIONS_ERROR
);
149 if (ares
->error
!= LDB_SUCCESS
) {
150 return ldb_module_done(ac
->req
, ares
->controls
,
151 ares
->response
, ares
->error
);
154 if (ares
->type
!= LDB_REPLY_DONE
) {
155 ldb_set_errstring(ldb
, "Invalid request type!\n");
156 return ldb_module_done(ac
->req
, NULL
, NULL
,
157 LDB_ERR_OPERATIONS_ERROR
);
161 return ldb_module_done(ac
->req
, ares
->controls
,
162 ares
->response
, LDB_SUCCESS
);
165 ac
->op_reply
= talloc_steal(ac
, ares
);
167 ret
= ust_search_modified(ac
);
168 if (ret
!= LDB_SUCCESS
) {
169 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
175 static int ust_del_op(struct secrets_tdb_sync_ctx
*ac
)
177 struct ldb_context
*ldb
;
178 struct ldb_request
*down_req
;
181 ldb
= ldb_module_get_ctx(ac
->module
);
183 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
186 ac
, secrets_tdb_sync_op_callback
,
188 LDB_REQ_SET_LOCATION(down_req
);
189 if (ret
!= LDB_SUCCESS
) {
192 return ldb_next_request(ac
->module
, down_req
);
195 static int ust_search_modified_callback(struct ldb_request
*req
,
196 struct ldb_reply
*ares
)
198 struct secrets_tdb_sync_ctx
*ac
;
201 ac
= talloc_get_type(req
->context
, struct secrets_tdb_sync_ctx
);
204 return ldb_module_done(ac
->req
, NULL
, NULL
,
205 LDB_ERR_OPERATIONS_ERROR
);
207 if (ares
->error
!= LDB_SUCCESS
) {
208 return ldb_module_done(ac
->req
, ares
->controls
,
209 ares
->response
, ares
->error
);
212 switch (ares
->type
) {
213 case LDB_REPLY_ENTRY
:
218 case LDB_REPLY_REFERRAL
:
225 /* do the dirty sync job here :/ */
226 ret
= add_modified(ac
->module
, ac
->dn
, ac
->do_delete
, ac
->req
);
230 ret
= ust_del_op(ac
);
231 if (ret
!= LDB_SUCCESS
) {
232 return ldb_module_done(ac
->req
,
238 return ldb_module_done(ac
->req
, ac
->op_reply
->controls
,
239 ac
->op_reply
->response
, LDB_SUCCESS
);
246 static int ust_search_modified(struct secrets_tdb_sync_ctx
*ac
)
248 struct ldb_context
*ldb
;
249 static const char * const no_attrs
[] = { NULL
};
250 struct ldb_request
*search_req
;
253 ldb
= ldb_module_get_ctx(ac
->module
);
255 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
256 ac
->dn
, LDB_SCOPE_BASE
,
257 "(&(objectClass=kerberosSecret)"
258 "(privateKeytab=*))", no_attrs
,
260 ac
, ust_search_modified_callback
,
262 LDB_REQ_SET_LOCATION(search_req
);
263 if (ret
!= LDB_SUCCESS
) {
266 return ldb_next_request(ac
->module
, search_req
);
271 static int secrets_tdb_sync_add(struct ldb_module
*module
, struct ldb_request
*req
)
273 struct ldb_context
*ldb
;
274 struct secrets_tdb_sync_ctx
*ac
;
275 struct ldb_request
*down_req
;
278 ldb
= ldb_module_get_ctx(module
);
280 ac
= secrets_tdb_sync_ctx_init(module
, req
);
282 return ldb_operr(ldb
);
285 ac
->dn
= req
->op
.add
.message
->dn
;
287 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
290 ac
, secrets_tdb_sync_op_callback
,
292 LDB_REQ_SET_LOCATION(down_req
);
293 if (ret
!= LDB_SUCCESS
) {
297 return ldb_next_request(module
, down_req
);
301 static int secrets_tdb_sync_modify(struct ldb_module
*module
, struct ldb_request
*req
)
303 struct ldb_context
*ldb
;
304 struct secrets_tdb_sync_ctx
*ac
;
305 struct ldb_request
*down_req
;
308 ldb
= ldb_module_get_ctx(module
);
310 ac
= secrets_tdb_sync_ctx_init(module
, req
);
312 return ldb_operr(ldb
);
315 ac
->dn
= req
->op
.mod
.message
->dn
;
317 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
320 ac
, secrets_tdb_sync_op_callback
,
322 LDB_REQ_SET_LOCATION(down_req
);
323 if (ret
!= LDB_SUCCESS
) {
327 return ldb_next_request(module
, down_req
);
331 static int secrets_tdb_sync_delete(struct ldb_module
*module
, struct ldb_request
*req
)
333 struct secrets_tdb_sync_ctx
*ac
;
335 ac
= secrets_tdb_sync_ctx_init(module
, req
);
337 return ldb_operr(ldb_module_get_ctx(module
));
340 ac
->dn
= req
->op
.del
.dn
;
341 ac
->do_delete
= true;
343 return ust_search_modified(ac
);
347 static int secrets_tdb_sync_rename(struct ldb_module
*module
, struct ldb_request
*req
)
349 struct ldb_context
*ldb
;
350 struct secrets_tdb_sync_ctx
*ac
;
351 struct ldb_request
*down_req
;
354 ldb
= ldb_module_get_ctx(module
);
356 ac
= secrets_tdb_sync_ctx_init(module
, req
);
358 return ldb_operr(ldb
);
361 ac
->dn
= req
->op
.rename
.newdn
;
363 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
364 req
->op
.rename
.olddn
,
365 req
->op
.rename
.newdn
,
367 ac
, secrets_tdb_sync_op_callback
,
369 LDB_REQ_SET_LOCATION(down_req
);
370 if (ret
!= LDB_SUCCESS
) {
374 return ldb_next_request(module
, down_req
);
377 /* prepare for a commit */
378 static int secrets_tdb_sync_prepare_commit(struct ldb_module
*module
)
380 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
381 struct secrets_tdb_sync_private
*data
= talloc_get_type(ldb_module_get_private(module
),
382 struct secrets_tdb_sync_private
);
386 tmp_ctx
= talloc_new(data
);
392 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
393 const struct ldb_val
*whenChanged
= ldb_msg_find_ldb_val(p
->msg
, "whenChanged");
398 ldb_val_to_time(whenChanged
, &lct
);
401 ret
= secrets_store_machine_pw_sync(ldb_msg_find_attr_as_string(p
->msg
, "secret", NULL
),
402 ldb_msg_find_attr_as_string(p
->msg
, "priorSecret", NULL
),
404 ldb_msg_find_attr_as_string(p
->msg
, "flatname", NULL
),
405 ldb_msg_find_attr_as_string(p
->msg
, "realm", NULL
),
406 ldb_msg_find_attr_as_string(p
->msg
, "saltPrincipal", NULL
),
407 (uint32_t)ldb_msg_find_attr_as_int(p
->msg
, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES
),
408 samdb_result_dom_sid(tmp_ctx
, p
->msg
, "objectSid"),
411 (uint32_t)ldb_msg_find_attr_as_int(p
->msg
, "secureChannelType", 0),
414 ldb_asprintf_errstring(ldb
, "Failed to update secrets.tdb from entry %s in %s",
415 ldb_dn_get_linearized(p
->msg
->dn
),
416 (const char *)ldb_get_opaque(ldb
, "ldb_url"));
421 talloc_free(data
->changed_dns
);
422 data
->changed_dns
= NULL
;
423 talloc_free(tmp_ctx
);
425 return ldb_next_prepare_commit(module
);
428 dbwrap_transaction_cancel(data
->secrets_tdb
);
429 talloc_free(data
->changed_dns
);
430 data
->changed_dns
= NULL
;
431 talloc_free(tmp_ctx
);
432 return LDB_ERR_OPERATIONS_ERROR
;
435 /* start a transaction */
436 static int secrets_tdb_sync_start_transaction(struct ldb_module
*module
)
438 struct secrets_tdb_sync_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct secrets_tdb_sync_private
);
440 if (dbwrap_transaction_start(data
->secrets_tdb
) != 0) {
441 return ldb_module_operr(module
);
444 return ldb_next_start_trans(module
);
447 /* end a transaction */
448 static int secrets_tdb_sync_end_transaction(struct ldb_module
*module
)
450 struct secrets_tdb_sync_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct secrets_tdb_sync_private
);
452 if (dbwrap_transaction_commit(data
->secrets_tdb
) != 0) {
453 return ldb_module_operr(module
);
456 return ldb_next_end_trans(module
);
459 /* abandon a transaction */
460 static int secrets_tdb_sync_del_transaction(struct ldb_module
*module
)
462 struct secrets_tdb_sync_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct secrets_tdb_sync_private
);
464 talloc_free(data
->changed_dns
);
465 data
->changed_dns
= NULL
;
466 if (dbwrap_transaction_cancel(data
->secrets_tdb
) != 0) {
467 return ldb_module_operr(module
);
470 return ldb_next_del_trans(module
);
473 static int secrets_tdb_sync_init(struct ldb_module
*module
)
475 struct ldb_context
*ldb
;
476 struct secrets_tdb_sync_private
*data
;
477 char *private_dir
, *p
;
478 const char *secrets_ldb
;
480 ldb
= ldb_module_get_ctx(module
);
482 data
= talloc(module
, struct secrets_tdb_sync_private
);
487 data
->changed_dns
= NULL
;
489 ldb_module_set_private(module
, data
);
491 secrets_ldb
= (const char *)ldb_get_opaque(ldb
, "ldb_url");
493 return ldb_operr(ldb
);
495 if (strncmp("tdb://", secrets_ldb
, 6) == 0) {
498 private_dir
= talloc_strdup(data
, secrets_ldb
);
499 p
= strrchr(private_dir
, '/');
503 private_dir
= talloc_strdup(data
, ".");
506 secrets_init_path(private_dir
, false);
508 TALLOC_FREE(private_dir
);
510 data
->secrets_tdb
= secrets_db_ctx();
512 return ldb_next_init(module
);
515 static const struct ldb_module_ops ldb_secrets_tdb_sync_module_ops
= {
516 .name
= "secrets_tdb_sync",
517 .init_context
= secrets_tdb_sync_init
,
518 .add
= secrets_tdb_sync_add
,
519 .modify
= secrets_tdb_sync_modify
,
520 .rename
= secrets_tdb_sync_rename
,
521 .del
= secrets_tdb_sync_delete
,
522 .start_transaction
= secrets_tdb_sync_start_transaction
,
523 .prepare_commit
= secrets_tdb_sync_prepare_commit
,
524 .end_transaction
= secrets_tdb_sync_end_transaction
,
525 .del_transaction
= secrets_tdb_sync_del_transaction
,
528 int ldb_secrets_tdb_sync_module_init(const char *version
)
530 LDB_MODULE_CHECK_VERSION(version
);
531 return ldb_register_module(&ldb_secrets_tdb_sync_module_ops
);