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"),
413 ldb_asprintf_errstring(ldb, "Failed to update secrets.tdb from entry %s in %s",
414 ldb_dn_get_linearized(p->msg->dn),
415 (const char *)ldb_get_opaque(ldb, "ldb_url"));
420 talloc_free(data->changed_dns);
421 data->changed_dns = NULL;
422 talloc_free(tmp_ctx);
424 return ldb_next_prepare_commit(module);
427 dbwrap_transaction_cancel(data->secrets_tdb);
428 talloc_free(data->changed_dns);
429 data->changed_dns = NULL;
430 talloc_free(tmp_ctx);
431 return LDB_ERR_OPERATIONS_ERROR;
434 /* start a transaction */
435 static int secrets_tdb_sync_start_transaction(struct ldb_module *module)
437 struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
439 if (dbwrap_transaction_start(data->secrets_tdb) != 0) {
440 return ldb_module_operr(module);
443 return ldb_next_start_trans(module);
446 /* end a transaction */
447 static int secrets_tdb_sync_end_transaction(struct ldb_module *module)
449 struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
451 if (dbwrap_transaction_commit(data->secrets_tdb) != 0) {
452 return ldb_module_operr(module);
455 return ldb_next_end_trans(module);
458 /* abandon a transaction */
459 static int secrets_tdb_sync_del_transaction(struct ldb_module *module)
461 struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
463 talloc_free(data->changed_dns);
464 data->changed_dns = NULL;
465 if (dbwrap_transaction_cancel(data->secrets_tdb) != 0) {
466 return ldb_module_operr(module);
469 return ldb_next_del_trans(module);
472 static int secrets_tdb_sync_init(struct ldb_module *module)
474 struct ldb_context *ldb;
475 struct secrets_tdb_sync_private *data;
476 char *private_dir, *p;
477 const char *secrets_ldb;
479 ldb = ldb_module_get_ctx(module);
481 data = talloc(module, struct secrets_tdb_sync_private);
486 data->changed_dns = NULL;
488 ldb_module_set_private(module, data);
490 secrets_ldb = (const char *)ldb_get_opaque(ldb, "ldb_url");
491 if (strncmp("tdb://", secrets_ldb, 6) == 0) {
495 return ldb_operr(ldb);
497 private_dir = talloc_strdup(data, secrets_ldb);
498 p = strrchr(private_dir, '/');
501 secrets_init_path(private_dir);
503 secrets_init_path(".");
506 TALLOC_FREE(private_dir);
508 data->secrets_tdb = secrets_db_ctx();
510 return ldb_next_init(module);
513 static const struct ldb_module_ops ldb_secrets_tdb_sync_module_ops = {
514 .name = "secrets_tdb_sync",
515 .init_context = secrets_tdb_sync_init,
516 .add = secrets_tdb_sync_add,
517 .modify = secrets_tdb_sync_modify,
518 .rename = secrets_tdb_sync_rename,
519 .del = secrets_tdb_sync_delete,
520 .start_transaction = secrets_tdb_sync_start_transaction,
521 .prepare_commit = secrets_tdb_sync_prepare_commit,
522 .end_transaction = secrets_tdb_sync_end_transaction,
523 .del_transaction = secrets_tdb_sync_del_transaction,
526 int ldb_secrets_tdb_sync_module_init(const char *version)
528 LDB_MODULE_CHECK_VERSION(version);
529 return ldb_register_module(&ldb_secrets_tdb_sync_module_ops);