Fix the mess with ldb includes.
[Samba/ekacnet.git] / source4 / dsdb / samdb / ldb_modules / update_keytab.c
blobe178ebb9dc15674c0c099e12ac091aa15c511b75
1 /*
2 ldb database library
4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
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 update_keytabs module
25 * Description: Update keytabs whenever their matching secret record changes
27 * Author: Andrew Bartlett
30 #include "includes.h"
31 #include "ldb_module.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/credentials/credentials_krb5.h"
34 #include "system/kerberos.h"
36 struct dn_list {
37 struct cli_credentials *creds;
38 struct dn_list *prev, *next;
41 struct update_kt_private {
42 struct dn_list *changed_dns;
45 struct update_kt_ctx {
46 struct ldb_module *module;
47 struct ldb_request *req;
49 struct ldb_dn *dn;
50 bool delete;
52 struct ldb_reply *op_reply;
53 bool found;
56 static struct update_kt_ctx *update_kt_ctx_init(struct ldb_module *module,
57 struct ldb_request *req)
59 struct update_kt_ctx *ac;
61 ac = talloc_zero(req, struct update_kt_ctx);
62 if (ac == NULL) {
63 ldb_oom(ldb_module_get_ctx(module));
64 return NULL;
67 ac->module = module;
68 ac->req = req;
70 return ac;
73 /* FIXME: too many semi-async searches here for my taste, direct and indirect as
74 * cli_credentials_set_secrets() performs a sync ldb search.
75 * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
76 * of async issues). -SSS
78 static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool delete) {
79 struct ldb_context *ldb = ldb_module_get_ctx(module);
80 struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
81 struct dn_list *item;
82 char *filter;
83 struct ldb_result *res;
84 const char *attrs[] = { NULL };
85 int ret;
86 NTSTATUS status;
88 filter = talloc_asprintf(data, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
89 ldb_dn_get_linearized(dn));
90 if (!filter) {
91 ldb_oom(ldb);
92 return LDB_ERR_OPERATIONS_ERROR;
95 ret = ldb_search(ldb, data, &res,
96 dn, LDB_SCOPE_BASE, attrs, "%s", filter);
97 if (ret != LDB_SUCCESS) {
98 talloc_free(filter);
99 return ret;
102 if (res->count != 1) {
103 /* if it's not a kerberosSecret then we don't have anything to update */
104 talloc_free(res);
105 talloc_free(filter);
106 return LDB_SUCCESS;
108 talloc_free(res);
110 item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
111 if (!item) {
112 talloc_free(filter);
113 ldb_oom(ldb);
114 return LDB_ERR_OPERATIONS_ERROR;
117 item->creds = cli_credentials_init(item);
118 if (!item->creds) {
119 DEBUG(1, ("cli_credentials_init failed!"));
120 talloc_free(filter);
121 ldb_oom(ldb);
122 return LDB_ERR_OPERATIONS_ERROR;
125 cli_credentials_set_conf(item->creds, ldb_get_opaque(ldb, "loadparm"));
126 status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), ldb, NULL, filter);
127 talloc_free(filter);
128 if (NT_STATUS_IS_OK(status)) {
129 if (delete) {
130 /* Ensure we don't helpfully keep an old keytab entry */
131 cli_credentials_set_kvno(item->creds, cli_credentials_get_kvno(item->creds)+2);
132 /* Wipe passwords */
133 cli_credentials_set_nt_hash(item->creds, NULL,
134 CRED_SPECIFIED);
136 DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
138 return LDB_SUCCESS;
141 static int ukt_search_modified(struct update_kt_ctx *ac);
143 static int update_kt_op_callback(struct ldb_request *req,
144 struct ldb_reply *ares)
146 struct ldb_context *ldb;
147 struct update_kt_ctx *ac;
148 int ret;
150 ac = talloc_get_type(req->context, struct update_kt_ctx);
151 ldb = ldb_module_get_ctx(ac->module);
153 if (!ares) {
154 return ldb_module_done(ac->req, NULL, NULL,
155 LDB_ERR_OPERATIONS_ERROR);
157 if (ares->error != LDB_SUCCESS) {
158 return ldb_module_done(ac->req, ares->controls,
159 ares->response, ares->error);
162 if (ares->type != LDB_REPLY_DONE) {
163 ldb_set_errstring(ldb, "Invalid request type!\n");
164 return ldb_module_done(ac->req, NULL, NULL,
165 LDB_ERR_OPERATIONS_ERROR);
168 if (ac->delete) {
169 return ldb_module_done(ac->req, ares->controls,
170 ares->response, LDB_SUCCESS);
173 ac->op_reply = talloc_steal(ac, ares);
175 ret = ukt_search_modified(ac);
176 if (ret != LDB_SUCCESS) {
177 return ldb_module_done(ac->req, NULL, NULL, ret);
180 return LDB_SUCCESS;
183 static int ukt_del_op(struct update_kt_ctx *ac)
185 struct ldb_context *ldb;
186 struct ldb_request *down_req;
187 int ret;
189 ldb = ldb_module_get_ctx(ac->module);
191 ret = ldb_build_del_req(&down_req, ldb, ac,
192 ac->dn,
193 ac->req->controls,
194 ac, update_kt_op_callback,
195 ac->req);
196 if (ret != LDB_SUCCESS) {
197 return ret;
199 return ldb_next_request(ac->module, down_req);
202 static int ukt_search_modified_callback(struct ldb_request *req,
203 struct ldb_reply *ares)
205 struct update_kt_ctx *ac;
206 int ret;
208 ac = talloc_get_type(req->context, struct update_kt_ctx);
210 if (!ares) {
211 return ldb_module_done(ac->req, NULL, NULL,
212 LDB_ERR_OPERATIONS_ERROR);
214 if (ares->error != LDB_SUCCESS) {
215 return ldb_module_done(ac->req, ares->controls,
216 ares->response, ares->error);
219 switch (ares->type) {
220 case LDB_REPLY_ENTRY:
222 ac->found = true;
223 break;
225 case LDB_REPLY_REFERRAL:
226 /* ignore */
227 break;
229 case LDB_REPLY_DONE:
231 if (ac->found) {
232 /* do the dirty sync job here :/ */
233 ret = add_modified(ac->module, ac->dn, ac->delete);
236 if (ac->delete) {
237 ret = ukt_del_op(ac);
238 if (ret != LDB_SUCCESS) {
239 return ldb_module_done(ac->req,
240 NULL, NULL, ret);
242 break;
245 return ldb_module_done(ac->req, ac->op_reply->controls,
246 ac->op_reply->response, LDB_SUCCESS);
249 talloc_free(ares);
250 return LDB_SUCCESS;
253 static int ukt_search_modified(struct update_kt_ctx *ac)
255 struct ldb_context *ldb;
256 static const char * const attrs[] = { "distinguishedName", NULL };
257 struct ldb_request *search_req;
258 int ret;
260 ldb = ldb_module_get_ctx(ac->module);
262 ret = ldb_build_search_req(&search_req, ldb, ac,
263 ac->dn, LDB_SCOPE_BASE,
264 "(&(objectClass=kerberosSecret)"
265 "(privateKeytab=*))", attrs,
266 NULL,
267 ac, ukt_search_modified_callback,
268 ac->req);
269 if (ret != LDB_SUCCESS) {
270 return ret;
272 return ldb_next_request(ac->module, search_req);
276 /* add */
277 static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
279 struct ldb_context *ldb;
280 struct update_kt_ctx *ac;
281 struct ldb_request *down_req;
282 int ret;
284 ldb = ldb_module_get_ctx(module);
286 ac = update_kt_ctx_init(module, req);
287 if (ac == NULL) {
288 return LDB_ERR_OPERATIONS_ERROR;
291 ac->dn = req->op.add.message->dn;
293 ret = ldb_build_add_req(&down_req, ldb, ac,
294 req->op.add.message,
295 req->controls,
296 ac, update_kt_op_callback,
297 req);
298 if (ret != LDB_SUCCESS) {
299 return ret;
302 return ldb_next_request(module, down_req);
305 /* modify */
306 static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
308 struct ldb_context *ldb;
309 struct update_kt_ctx *ac;
310 struct ldb_request *down_req;
311 int ret;
313 ldb = ldb_module_get_ctx(module);
315 ac = update_kt_ctx_init(module, req);
316 if (ac == NULL) {
317 return LDB_ERR_OPERATIONS_ERROR;
320 ac->dn = req->op.mod.message->dn;
322 ret = ldb_build_mod_req(&down_req, ldb, ac,
323 req->op.mod.message,
324 req->controls,
325 ac, update_kt_op_callback,
326 req);
327 if (ret != LDB_SUCCESS) {
328 return ret;
331 return ldb_next_request(module, down_req);
334 /* delete */
335 static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
337 struct update_kt_ctx *ac;
339 ac = update_kt_ctx_init(module, req);
340 if (ac == NULL) {
341 return LDB_ERR_OPERATIONS_ERROR;
344 ac->dn = req->op.del.dn;
345 ac->delete = true;
347 return ukt_search_modified(ac);
350 /* rename */
351 static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
353 struct ldb_context *ldb;
354 struct update_kt_ctx *ac;
355 struct ldb_request *down_req;
356 int ret;
358 ldb = ldb_module_get_ctx(module);
360 ac = update_kt_ctx_init(module, req);
361 if (ac == NULL) {
362 return LDB_ERR_OPERATIONS_ERROR;
365 ac->dn = req->op.rename.newdn;
367 ret = ldb_build_rename_req(&down_req, ldb, ac,
368 req->op.rename.olddn,
369 req->op.rename.newdn,
370 req->controls,
371 ac, update_kt_op_callback,
372 req);
373 if (ret != LDB_SUCCESS) {
374 return ret;
377 return ldb_next_request(module, down_req);
380 /* end a transaction */
381 static int update_kt_end_trans(struct ldb_module *module)
383 struct ldb_context *ldb;
384 struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
385 struct dn_list *p;
387 ldb = ldb_module_get_ctx(module);
389 for (p=data->changed_dns; p; p = p->next) {
390 int kret;
391 kret = cli_credentials_update_keytab(p->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"));
392 if (kret != 0) {
393 talloc_free(data->changed_dns);
394 data->changed_dns = NULL;
395 ldb_asprintf_errstring(ldb, "Failed to update keytab: %s", error_message(kret));
396 return LDB_ERR_OPERATIONS_ERROR;
400 talloc_free(data->changed_dns);
401 data->changed_dns = NULL;
403 return ldb_next_end_trans(module);
406 /* end a transaction */
407 static int update_kt_del_trans(struct ldb_module *module)
409 struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
411 talloc_free(data->changed_dns);
412 data->changed_dns = NULL;
414 return ldb_next_del_trans(module);
417 static int update_kt_init(struct ldb_module *module)
419 struct ldb_context *ldb;
420 struct update_kt_private *data;
422 ldb = ldb_module_get_ctx(module);
424 data = talloc(module, struct update_kt_private);
425 if (data == NULL) {
426 ldb_oom(ldb);
427 return LDB_ERR_OPERATIONS_ERROR;
430 data->changed_dns = NULL;
432 ldb_module_set_private(module, data);
434 return ldb_next_init(module);
437 _PUBLIC_ const struct ldb_module_ops ldb_update_keytab_module_ops = {
438 .name = "update_keytab",
439 .init_context = update_kt_init,
440 .add = update_kt_add,
441 .modify = update_kt_modify,
442 .rename = update_kt_rename,
443 .del = update_kt_delete,
444 .end_transaction = update_kt_end_trans,
445 .del_transaction = update_kt_del_trans,