dsdb-acl: attr is not optional to acl_check_access_on_attribute()
[Samba/gebeck_regimport.git] / source4 / dsdb / samdb / ldb_modules / secrets_tdb_sync.c
blobe90fc77068f0424e4882d1478fb2f2a0b251b22d
1 /*
2 ldb database library
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/>.
21 * Name: ldb
23 * Component: ldb secrets_tdb_sync module
25 * Description: Update secrets.tdb whenever the matching secret record changes
27 * Author: Andrew Bartlett
30 #include "includes.h"
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"
44 struct dn_list {
45 struct ldb_message *msg;
46 bool do_delete;
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;
59 struct ldb_dn *dn;
60 bool do_delete;
62 struct ldb_reply *op_reply;
63 bool found;
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);
72 if (ac == NULL) {
73 ldb_oom(ldb_module_get_ctx(module));
74 return NULL;
77 ac->module = module;
78 ac->req = req;
80 return ac;
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);
93 struct dn_list *item;
94 char *filter;
95 struct ldb_result *res;
96 int ret;
98 filter = talloc_asprintf(data,
99 "(&(objectClass=primaryDomain)(flatname=*))");
100 if (!filter) {
101 return ldb_oom(ldb);
104 ret = dsdb_module_search(module, data, &res,
105 dn, LDB_SCOPE_BASE, NULL,
106 DSDB_FLAG_NEXT_MODULE, parent,
107 "%s", filter);
108 talloc_free(filter);
109 if (ret != LDB_SUCCESS) {
110 return ret;
113 if (res->count != 1) {
114 /* if it's not a primaryDomain then we don't have anything to update */
115 talloc_free(res);
116 return LDB_SUCCESS;
119 item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
120 if (!item) {
121 talloc_free(res);
122 return ldb_oom(ldb);
125 item->msg = talloc_steal(item, res->msgs[0]);
126 item->do_delete = do_delete;
127 talloc_free(res);
129 DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
130 return LDB_SUCCESS;
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;
140 int ret;
142 ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
143 ldb = ldb_module_get_ctx(ac->module);
145 if (!ares) {
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);
160 if (ac->do_delete) {
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);
172 return LDB_SUCCESS;
175 static int ust_del_op(struct secrets_tdb_sync_ctx *ac)
177 struct ldb_context *ldb;
178 struct ldb_request *down_req;
179 int ret;
181 ldb = ldb_module_get_ctx(ac->module);
183 ret = ldb_build_del_req(&down_req, ldb, ac,
184 ac->dn,
185 ac->req->controls,
186 ac, secrets_tdb_sync_op_callback,
187 ac->req);
188 LDB_REQ_SET_LOCATION(down_req);
189 if (ret != LDB_SUCCESS) {
190 return ret;
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;
199 int ret;
201 ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
203 if (!ares) {
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:
215 ac->found = true;
216 break;
218 case LDB_REPLY_REFERRAL:
219 /* ignore */
220 break;
222 case LDB_REPLY_DONE:
224 if (ac->found) {
225 /* do the dirty sync job here :/ */
226 ret = add_modified(ac->module, ac->dn, ac->do_delete, ac->req);
229 if (ac->do_delete) {
230 ret = ust_del_op(ac);
231 if (ret != LDB_SUCCESS) {
232 return ldb_module_done(ac->req,
233 NULL, NULL, ret);
235 break;
238 return ldb_module_done(ac->req, ac->op_reply->controls,
239 ac->op_reply->response, LDB_SUCCESS);
242 talloc_free(ares);
243 return 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;
251 int ret;
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,
259 NULL,
260 ac, ust_search_modified_callback,
261 ac->req);
262 LDB_REQ_SET_LOCATION(search_req);
263 if (ret != LDB_SUCCESS) {
264 return ret;
266 return ldb_next_request(ac->module, search_req);
270 /* add */
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;
276 int ret;
278 ldb = ldb_module_get_ctx(module);
280 ac = secrets_tdb_sync_ctx_init(module, req);
281 if (ac == NULL) {
282 return ldb_operr(ldb);
285 ac->dn = req->op.add.message->dn;
287 ret = ldb_build_add_req(&down_req, ldb, ac,
288 req->op.add.message,
289 req->controls,
290 ac, secrets_tdb_sync_op_callback,
291 req);
292 LDB_REQ_SET_LOCATION(down_req);
293 if (ret != LDB_SUCCESS) {
294 return ret;
297 return ldb_next_request(module, down_req);
300 /* modify */
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;
306 int ret;
308 ldb = ldb_module_get_ctx(module);
310 ac = secrets_tdb_sync_ctx_init(module, req);
311 if (ac == NULL) {
312 return ldb_operr(ldb);
315 ac->dn = req->op.mod.message->dn;
317 ret = ldb_build_mod_req(&down_req, ldb, ac,
318 req->op.mod.message,
319 req->controls,
320 ac, secrets_tdb_sync_op_callback,
321 req);
322 LDB_REQ_SET_LOCATION(down_req);
323 if (ret != LDB_SUCCESS) {
324 return ret;
327 return ldb_next_request(module, down_req);
330 /* delete */
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);
336 if (ac == NULL) {
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);
346 /* rename */
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;
352 int ret;
354 ldb = ldb_module_get_ctx(module);
356 ac = secrets_tdb_sync_ctx_init(module, req);
357 if (ac == NULL) {
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,
366 req->controls,
367 ac, secrets_tdb_sync_op_callback,
368 req);
369 LDB_REQ_SET_LOCATION(down_req);
370 if (ret != LDB_SUCCESS) {
371 return ret;
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);
383 struct dn_list *p;
384 TALLOC_CTX *tmp_ctx;
386 tmp_ctx = talloc_new(data);
387 if (!tmp_ctx) {
388 ldb_oom(ldb);
389 goto fail;
392 for (p=data->changed_dns; p; p = p->next) {
393 const struct ldb_val *whenChanged = ldb_msg_find_ldb_val(p->msg, "whenChanged");
394 time_t lct = 0;
395 bool ret;
397 if (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"),
410 lct,
411 p->do_delete);
412 if (ret == false) {
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"));
416 goto fail;
420 talloc_free(data->changed_dns);
421 data->changed_dns = NULL;
422 talloc_free(tmp_ctx);
424 return ldb_next_prepare_commit(module);
426 fail:
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);
482 if (data == NULL) {
483 return ldb_oom(ldb);
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) {
492 secrets_ldb += 6;
494 if (!secrets_ldb) {
495 return ldb_operr(ldb);
497 private_dir = talloc_strdup(data, secrets_ldb);
498 p = strrchr(private_dir, '/');
499 if (p) {
500 *p = '\0';
501 secrets_init_path(private_dir);
502 } else {
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);