Line data Source code
1 : /*
2 : ldb database library
3 :
4 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007-2012
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : /*
21 : * Name: ldb
22 : *
23 : * Component: ldb secrets_tdb_sync module
24 : *
25 : * Description: Update secrets.tdb whenever the matching secret record changes
26 : *
27 : * Author: Andrew Bartlett
28 : */
29 :
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"
43 :
44 : struct dn_list {
45 : struct ldb_message *msg;
46 : bool do_delete;
47 : struct dn_list *prev, *next;
48 : };
49 :
50 : struct secrets_tdb_sync_private {
51 : struct dn_list *changed_dns;
52 : struct db_context *secrets_tdb;
53 : };
54 :
55 : struct secrets_tdb_sync_ctx {
56 : struct ldb_module *module;
57 : struct ldb_request *req;
58 :
59 : struct ldb_dn *dn;
60 : bool do_delete;
61 :
62 : struct ldb_reply *op_reply;
63 : bool found;
64 : };
65 :
66 5181 : static struct secrets_tdb_sync_ctx *secrets_tdb_sync_ctx_init(struct ldb_module *module,
67 : struct ldb_request *req)
68 : {
69 83 : struct secrets_tdb_sync_ctx *ac;
70 :
71 5181 : ac = talloc_zero(req, struct secrets_tdb_sync_ctx);
72 5181 : if (ac == NULL) {
73 0 : ldb_oom(ldb_module_get_ctx(module));
74 0 : return NULL;
75 : }
76 :
77 5181 : ac->module = module;
78 5181 : ac->req = req;
79 :
80 5181 : return ac;
81 : }
82 :
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
87 : */
88 251 : static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_delete,
89 : struct ldb_request *parent)
90 : {
91 251 : struct ldb_context *ldb = ldb_module_get_ctx(module);
92 251 : struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
93 26 : struct dn_list *item;
94 26 : char *filter;
95 26 : struct ldb_result *res;
96 26 : int ret;
97 :
98 251 : filter = talloc_asprintf(data,
99 : "(&(objectClass=primaryDomain)(flatname=*))");
100 251 : if (!filter) {
101 0 : return ldb_oom(ldb);
102 : }
103 :
104 251 : ret = dsdb_module_search(module, data, &res,
105 : dn, LDB_SCOPE_BASE, NULL,
106 : DSDB_FLAG_NEXT_MODULE, parent,
107 : "%s", filter);
108 251 : talloc_free(filter);
109 251 : if (ret != LDB_SUCCESS) {
110 0 : return ret;
111 : }
112 :
113 251 : if (res->count != 1) {
114 : /* if it's not a primaryDomain then we don't have anything to update */
115 9 : talloc_free(res);
116 9 : return LDB_SUCCESS;
117 : }
118 :
119 244 : item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
120 242 : if (!item) {
121 0 : talloc_free(res);
122 0 : return ldb_oom(ldb);
123 : }
124 :
125 242 : item->msg = talloc_steal(item, res->msgs[0]);
126 242 : item->do_delete = do_delete;
127 242 : talloc_free(res);
128 :
129 242 : DLIST_ADD_END(data->changed_dns, item);
130 217 : return LDB_SUCCESS;
131 : }
132 :
133 : static int ust_search_modified(struct secrets_tdb_sync_ctx *ac);
134 :
135 5181 : static int secrets_tdb_sync_op_callback(struct ldb_request *req,
136 : struct ldb_reply *ares)
137 : {
138 83 : struct ldb_context *ldb;
139 83 : struct secrets_tdb_sync_ctx *ac;
140 83 : int ret;
141 :
142 5181 : ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
143 5181 : ldb = ldb_module_get_ctx(ac->module);
144 :
145 5181 : if (!ares) {
146 0 : return ldb_module_done(ac->req, NULL, NULL,
147 : LDB_ERR_OPERATIONS_ERROR);
148 : }
149 5181 : if (ares->error != LDB_SUCCESS) {
150 9 : return ldb_module_done(ac->req, ares->controls,
151 : ares->response, ares->error);
152 : }
153 :
154 5172 : if (ares->type != LDB_REPLY_DONE) {
155 0 : ldb_set_errstring(ldb, "Invalid request type!\n");
156 0 : return ldb_module_done(ac->req, NULL, NULL,
157 : LDB_ERR_OPERATIONS_ERROR);
158 : }
159 :
160 5172 : if (ac->do_delete) {
161 1643 : return ldb_module_done(ac->req, ares->controls,
162 : ares->response, LDB_SUCCESS);
163 : }
164 :
165 3529 : ac->op_reply = talloc_steal(ac, ares);
166 :
167 3529 : ret = ust_search_modified(ac);
168 3529 : if (ret != LDB_SUCCESS) {
169 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
170 : }
171 :
172 3446 : return LDB_SUCCESS;
173 : }
174 :
175 1652 : static int ust_del_op(struct secrets_tdb_sync_ctx *ac)
176 : {
177 0 : struct ldb_context *ldb;
178 0 : struct ldb_request *down_req;
179 0 : int ret;
180 :
181 1652 : ldb = ldb_module_get_ctx(ac->module);
182 :
183 1652 : ret = ldb_build_del_req(&down_req, ldb, ac,
184 : ac->dn,
185 1652 : ac->req->controls,
186 : ac, secrets_tdb_sync_op_callback,
187 : ac->req);
188 1652 : LDB_REQ_SET_LOCATION(down_req);
189 1652 : if (ret != LDB_SUCCESS) {
190 0 : return ret;
191 : }
192 1652 : return ldb_next_request(ac->module, down_req);
193 : }
194 :
195 5432 : static int ust_search_modified_callback(struct ldb_request *req,
196 : struct ldb_reply *ares)
197 : {
198 109 : struct secrets_tdb_sync_ctx *ac;
199 109 : int ret;
200 :
201 5432 : ac = talloc_get_type(req->context, struct secrets_tdb_sync_ctx);
202 :
203 5432 : if (!ares) {
204 0 : return ldb_module_done(ac->req, NULL, NULL,
205 : LDB_ERR_OPERATIONS_ERROR);
206 : }
207 5432 : if (ares->error != LDB_SUCCESS) {
208 0 : return ldb_module_done(ac->req, ares->controls,
209 : ares->response, ares->error);
210 : }
211 :
212 5432 : switch (ares->type) {
213 251 : case LDB_REPLY_ENTRY:
214 :
215 251 : ac->found = true;
216 251 : break;
217 :
218 0 : case LDB_REPLY_REFERRAL:
219 : /* ignore */
220 0 : break;
221 :
222 5181 : case LDB_REPLY_DONE:
223 :
224 5181 : if (ac->found) {
225 : /* do the dirty sync job here :/ */
226 251 : ret = add_modified(ac->module, ac->dn, ac->do_delete, ac->req);
227 : }
228 :
229 5181 : if (ac->do_delete) {
230 1652 : ret = ust_del_op(ac);
231 1652 : if (ret != LDB_SUCCESS) {
232 0 : return ldb_module_done(ac->req,
233 : NULL, NULL, ret);
234 : }
235 1652 : break;
236 : }
237 :
238 3529 : return ldb_module_done(ac->req, ac->op_reply->controls,
239 3529 : ac->op_reply->response, LDB_SUCCESS);
240 : }
241 :
242 1903 : talloc_free(ares);
243 1903 : return LDB_SUCCESS;
244 : }
245 :
246 5181 : static int ust_search_modified(struct secrets_tdb_sync_ctx *ac)
247 : {
248 83 : struct ldb_context *ldb;
249 83 : static const char * const no_attrs[] = { NULL };
250 83 : struct ldb_request *search_req;
251 83 : int ret;
252 :
253 5181 : ldb = ldb_module_get_ctx(ac->module);
254 :
255 5181 : 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 5181 : LDB_REQ_SET_LOCATION(search_req);
263 5181 : if (ret != LDB_SUCCESS) {
264 0 : return ret;
265 : }
266 5181 : return ldb_next_request(ac->module, search_req);
267 : }
268 :
269 :
270 : /* add */
271 2272 : static int secrets_tdb_sync_add(struct ldb_module *module, struct ldb_request *req)
272 : {
273 76 : struct ldb_context *ldb;
274 76 : struct secrets_tdb_sync_ctx *ac;
275 76 : struct ldb_request *down_req;
276 76 : int ret;
277 :
278 2272 : ldb = ldb_module_get_ctx(module);
279 :
280 2272 : ac = secrets_tdb_sync_ctx_init(module, req);
281 2272 : if (ac == NULL) {
282 0 : return ldb_operr(ldb);
283 : }
284 :
285 2272 : ac->dn = req->op.add.message->dn;
286 :
287 2272 : 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 2272 : LDB_REQ_SET_LOCATION(down_req);
293 2272 : if (ret != LDB_SUCCESS) {
294 0 : return ret;
295 : }
296 :
297 2272 : return ldb_next_request(module, down_req);
298 : }
299 :
300 : /* modify */
301 1232 : static int secrets_tdb_sync_modify(struct ldb_module *module, struct ldb_request *req)
302 : {
303 5 : struct ldb_context *ldb;
304 5 : struct secrets_tdb_sync_ctx *ac;
305 5 : struct ldb_request *down_req;
306 5 : int ret;
307 :
308 1232 : ldb = ldb_module_get_ctx(module);
309 :
310 1232 : ac = secrets_tdb_sync_ctx_init(module, req);
311 1232 : if (ac == NULL) {
312 0 : return ldb_operr(ldb);
313 : }
314 :
315 1232 : ac->dn = req->op.mod.message->dn;
316 :
317 1232 : 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 1232 : LDB_REQ_SET_LOCATION(down_req);
323 1232 : if (ret != LDB_SUCCESS) {
324 0 : return ret;
325 : }
326 :
327 1232 : return ldb_next_request(module, down_req);
328 : }
329 :
330 : /* delete */
331 1652 : static int secrets_tdb_sync_delete(struct ldb_module *module, struct ldb_request *req)
332 : {
333 0 : struct secrets_tdb_sync_ctx *ac;
334 :
335 1652 : ac = secrets_tdb_sync_ctx_init(module, req);
336 1652 : if (ac == NULL) {
337 0 : return ldb_operr(ldb_module_get_ctx(module));
338 : }
339 :
340 1652 : ac->dn = req->op.del.dn;
341 1652 : ac->do_delete = true;
342 :
343 1652 : return ust_search_modified(ac);
344 : }
345 :
346 : /* rename */
347 25 : static int secrets_tdb_sync_rename(struct ldb_module *module, struct ldb_request *req)
348 : {
349 2 : struct ldb_context *ldb;
350 2 : struct secrets_tdb_sync_ctx *ac;
351 2 : struct ldb_request *down_req;
352 2 : int ret;
353 :
354 25 : ldb = ldb_module_get_ctx(module);
355 :
356 25 : ac = secrets_tdb_sync_ctx_init(module, req);
357 25 : if (ac == NULL) {
358 0 : return ldb_operr(ldb);
359 : }
360 :
361 25 : ac->dn = req->op.rename.newdn;
362 :
363 25 : 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 25 : LDB_REQ_SET_LOCATION(down_req);
370 25 : if (ret != LDB_SUCCESS) {
371 0 : return ret;
372 : }
373 :
374 25 : return ldb_next_request(module, down_req);
375 : }
376 :
377 : /* prepare for a commit */
378 4815 : static int secrets_tdb_sync_prepare_commit(struct ldb_module *module)
379 : {
380 4815 : struct ldb_context *ldb = ldb_module_get_ctx(module);
381 4815 : struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module),
382 : struct secrets_tdb_sync_private);
383 32 : struct dn_list *p;
384 32 : TALLOC_CTX *tmp_ctx;
385 :
386 4815 : tmp_ctx = talloc_new(data);
387 4815 : if (!tmp_ctx) {
388 0 : ldb_oom(ldb);
389 0 : goto fail;
390 : }
391 :
392 5057 : for (p=data->changed_dns; p; p = p->next) {
393 242 : const struct ldb_val *whenChanged = ldb_msg_find_ldb_val(p->msg, "whenChanged");
394 242 : time_t lct = 0;
395 25 : bool ret;
396 :
397 242 : if (whenChanged) {
398 242 : ldb_val_to_time(whenChanged, &lct);
399 : }
400 :
401 242 : ret = secrets_store_machine_pw_sync(ldb_msg_find_attr_as_string(p->msg, "secret", NULL),
402 242 : ldb_msg_find_attr_as_string(p->msg, "priorSecret", NULL),
403 :
404 242 : ldb_msg_find_attr_as_string(p->msg, "flatname", NULL),
405 242 : ldb_msg_find_attr_as_string(p->msg, "realm", NULL),
406 242 : ldb_msg_find_attr_as_string(p->msg, "saltPrincipal", NULL),
407 242 : (uint32_t)ldb_msg_find_attr_as_int(p->msg, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES),
408 242 : samdb_result_dom_sid(tmp_ctx, p->msg, "objectSid"),
409 :
410 : lct,
411 242 : (uint32_t)ldb_msg_find_attr_as_int(p->msg, "secureChannelType", 0),
412 242 : p->do_delete);
413 242 : if (ret == false) {
414 0 : ldb_asprintf_errstring(ldb, "Failed to update secrets.tdb from entry %s in %s",
415 0 : ldb_dn_get_linearized(p->msg->dn),
416 0 : (const char *)ldb_get_opaque(ldb, "ldb_url"));
417 0 : goto fail;
418 : }
419 : }
420 :
421 4815 : talloc_free(data->changed_dns);
422 4815 : data->changed_dns = NULL;
423 4815 : talloc_free(tmp_ctx);
424 :
425 4815 : return ldb_next_prepare_commit(module);
426 :
427 0 : fail:
428 0 : dbwrap_transaction_cancel(data->secrets_tdb);
429 0 : talloc_free(data->changed_dns);
430 0 : data->changed_dns = NULL;
431 0 : talloc_free(tmp_ctx);
432 0 : return LDB_ERR_OPERATIONS_ERROR;
433 : }
434 :
435 : /* start a transaction */
436 4854 : static int secrets_tdb_sync_start_transaction(struct ldb_module *module)
437 : {
438 4854 : struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
439 :
440 4854 : if (dbwrap_transaction_start(data->secrets_tdb) != 0) {
441 0 : return ldb_module_operr(module);
442 : }
443 :
444 4854 : return ldb_next_start_trans(module);
445 : }
446 :
447 : /* end a transaction */
448 4815 : static int secrets_tdb_sync_end_transaction(struct ldb_module *module)
449 : {
450 4815 : struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
451 :
452 4815 : if (dbwrap_transaction_commit(data->secrets_tdb) != 0) {
453 0 : return ldb_module_operr(module);
454 : }
455 :
456 4815 : return ldb_next_end_trans(module);
457 : }
458 :
459 : /* abandon a transaction */
460 38 : static int secrets_tdb_sync_del_transaction(struct ldb_module *module)
461 : {
462 38 : struct secrets_tdb_sync_private *data = talloc_get_type(ldb_module_get_private(module), struct secrets_tdb_sync_private);
463 :
464 38 : talloc_free(data->changed_dns);
465 38 : data->changed_dns = NULL;
466 38 : if (dbwrap_transaction_cancel(data->secrets_tdb) != 0) {
467 0 : return ldb_module_operr(module);
468 : }
469 :
470 38 : return ldb_next_del_trans(module);
471 : }
472 :
473 69623 : static int secrets_tdb_sync_init(struct ldb_module *module)
474 : {
475 2687 : struct ldb_context *ldb;
476 2687 : struct secrets_tdb_sync_private *data;
477 2687 : char *private_dir, *p;
478 2687 : const char *secrets_ldb;
479 :
480 69623 : ldb = ldb_module_get_ctx(module);
481 :
482 69623 : data = talloc(module, struct secrets_tdb_sync_private);
483 69623 : if (data == NULL) {
484 0 : return ldb_oom(ldb);
485 : }
486 :
487 69623 : data->changed_dns = NULL;
488 :
489 69623 : ldb_module_set_private(module, data);
490 :
491 69623 : secrets_ldb = (const char *)ldb_get_opaque(ldb, "ldb_url");
492 69623 : if (!secrets_ldb) {
493 0 : return ldb_operr(ldb);
494 : }
495 69623 : if (strncmp("tdb://", secrets_ldb, 6) == 0) {
496 0 : secrets_ldb += 6;
497 : }
498 69623 : private_dir = talloc_strdup(data, secrets_ldb);
499 69623 : p = strrchr(private_dir, '/');
500 69623 : if (p) {
501 69623 : *p = '\0';
502 : } else {
503 0 : private_dir = talloc_strdup(data, ".");
504 : }
505 :
506 69623 : secrets_init_path(private_dir);
507 :
508 69623 : TALLOC_FREE(private_dir);
509 :
510 69623 : data->secrets_tdb = secrets_db_ctx();
511 :
512 69623 : return ldb_next_init(module);
513 : }
514 :
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,
526 : };
527 :
528 6040 : int ldb_secrets_tdb_sync_module_init(const char *version)
529 : {
530 6040 : LDB_MODULE_CHECK_VERSION(version);
531 6040 : return ldb_register_module(&ldb_secrets_tdb_sync_module_ops);
532 : }
|