• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/dsdb/samdb/ldb_modules/
1/*
2   ldb database library
3
4   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
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 update_keytabs module
24 *
25 *  Description: Update keytabs whenever their 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
37struct dn_list {
38	struct cli_credentials *creds;
39	struct dn_list *prev, *next;
40};
41
42struct update_kt_private {
43	struct dn_list *changed_dns;
44};
45
46struct update_kt_ctx {
47	struct ldb_module *module;
48	struct ldb_request *req;
49
50	struct ldb_dn *dn;
51	bool do_delete;
52
53	struct ldb_reply *op_reply;
54	bool found;
55};
56
57static struct update_kt_ctx *update_kt_ctx_init(struct ldb_module *module,
58						struct ldb_request *req)
59{
60	struct update_kt_ctx *ac;
61
62	ac = talloc_zero(req, struct update_kt_ctx);
63	if (ac == NULL) {
64		ldb_oom(ldb_module_get_ctx(module));
65		return NULL;
66	}
67
68	ac->module = module;
69	ac->req = req;
70
71	return ac;
72}
73
74/* FIXME: too many semi-async searches here for my taste, direct and indirect as
75 * cli_credentials_set_secrets() performs a sync ldb search.
76 * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
77 * of async issues). -SSS
78 */
79static int add_modified(struct ldb_module *module, struct ldb_dn *dn, bool do_delete) {
80	struct ldb_context *ldb = ldb_module_get_ctx(module);
81	struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
82	struct dn_list *item;
83	char *filter;
84	struct ldb_result *res;
85	const char *attrs[] = { NULL };
86	int ret;
87	NTSTATUS status;
88
89	filter = talloc_asprintf(data, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
90				 ldb_dn_get_linearized(dn));
91	if (!filter) {
92		ldb_oom(ldb);
93		return LDB_ERR_OPERATIONS_ERROR;
94	}
95
96	ret = ldb_search(ldb, data, &res,
97			 dn, LDB_SCOPE_BASE, attrs, "%s", filter);
98	if (ret != LDB_SUCCESS) {
99		talloc_free(filter);
100		return ret;
101	}
102
103	if (res->count != 1) {
104		/* if it's not a kerberosSecret then we don't have anything to update */
105		talloc_free(res);
106		talloc_free(filter);
107		return LDB_SUCCESS;
108	}
109	talloc_free(res);
110
111	item = talloc(data->changed_dns? (void *)data->changed_dns: (void *)data, struct dn_list);
112	if (!item) {
113		talloc_free(filter);
114		ldb_oom(ldb);
115		return LDB_ERR_OPERATIONS_ERROR;
116	}
117
118	item->creds = cli_credentials_init(item);
119	if (!item->creds) {
120		DEBUG(1, ("cli_credentials_init failed!"));
121		talloc_free(filter);
122		ldb_oom(ldb);
123		return LDB_ERR_OPERATIONS_ERROR;
124	}
125
126	cli_credentials_set_conf(item->creds, ldb_get_opaque(ldb, "loadparm"));
127	status = cli_credentials_set_secrets(item->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), ldb, NULL, filter);
128	talloc_free(filter);
129	if (NT_STATUS_IS_OK(status)) {
130		if (do_delete) {
131			/* Ensure we don't helpfully keep an old keytab entry */
132			cli_credentials_set_kvno(item->creds, cli_credentials_get_kvno(item->creds)+2);
133			/* Wipe passwords */
134			cli_credentials_set_nt_hash(item->creds, NULL,
135						    CRED_SPECIFIED);
136		}
137		DLIST_ADD_END(data->changed_dns, item, struct dn_list *);
138	}
139	return LDB_SUCCESS;
140}
141
142static int ukt_search_modified(struct update_kt_ctx *ac);
143
144static int update_kt_op_callback(struct ldb_request *req,
145				 struct ldb_reply *ares)
146{
147	struct ldb_context *ldb;
148	struct update_kt_ctx *ac;
149	int ret;
150
151	ac = talloc_get_type(req->context, struct update_kt_ctx);
152	ldb = ldb_module_get_ctx(ac->module);
153
154	if (!ares) {
155		return ldb_module_done(ac->req, NULL, NULL,
156					LDB_ERR_OPERATIONS_ERROR);
157	}
158	if (ares->error != LDB_SUCCESS) {
159		return ldb_module_done(ac->req, ares->controls,
160					ares->response, ares->error);
161	}
162
163	if (ares->type != LDB_REPLY_DONE) {
164		ldb_set_errstring(ldb, "Invalid request type!\n");
165		return ldb_module_done(ac->req, NULL, NULL,
166					LDB_ERR_OPERATIONS_ERROR);
167	}
168
169	if (ac->do_delete) {
170		return ldb_module_done(ac->req, ares->controls,
171					ares->response, LDB_SUCCESS);
172	}
173
174	ac->op_reply = talloc_steal(ac, ares);
175
176	ret = ukt_search_modified(ac);
177	if (ret != LDB_SUCCESS) {
178		return ldb_module_done(ac->req, NULL, NULL, ret);
179	}
180
181	return LDB_SUCCESS;
182}
183
184static int ukt_del_op(struct update_kt_ctx *ac)
185{
186	struct ldb_context *ldb;
187	struct ldb_request *down_req;
188	int ret;
189
190	ldb = ldb_module_get_ctx(ac->module);
191
192	ret = ldb_build_del_req(&down_req, ldb, ac,
193				ac->dn,
194				ac->req->controls,
195				ac, update_kt_op_callback,
196				ac->req);
197	if (ret != LDB_SUCCESS) {
198		return ret;
199	}
200	return ldb_next_request(ac->module, down_req);
201}
202
203static int ukt_search_modified_callback(struct ldb_request *req,
204					struct ldb_reply *ares)
205{
206	struct update_kt_ctx *ac;
207	int ret;
208
209	ac = talloc_get_type(req->context, struct update_kt_ctx);
210
211	if (!ares) {
212		return ldb_module_done(ac->req, NULL, NULL,
213					LDB_ERR_OPERATIONS_ERROR);
214	}
215	if (ares->error != LDB_SUCCESS) {
216		return ldb_module_done(ac->req, ares->controls,
217					ares->response, ares->error);
218	}
219
220	switch (ares->type) {
221	case LDB_REPLY_ENTRY:
222
223		ac->found = true;
224		break;
225
226	case LDB_REPLY_REFERRAL:
227		/* ignore */
228		break;
229
230	case LDB_REPLY_DONE:
231
232		if (ac->found) {
233			/* do the dirty sync job here :/ */
234			ret = add_modified(ac->module, ac->dn, ac->do_delete);
235		}
236
237		if (ac->do_delete) {
238			ret = ukt_del_op(ac);
239			if (ret != LDB_SUCCESS) {
240				return ldb_module_done(ac->req,
241							NULL, NULL, ret);
242			}
243			break;
244		}
245
246		return ldb_module_done(ac->req, ac->op_reply->controls,
247					ac->op_reply->response, LDB_SUCCESS);
248	}
249
250	talloc_free(ares);
251	return LDB_SUCCESS;
252}
253
254static int ukt_search_modified(struct update_kt_ctx *ac)
255{
256	struct ldb_context *ldb;
257	static const char * const attrs[] = { "distinguishedName", NULL };
258	struct ldb_request *search_req;
259	int ret;
260
261	ldb = ldb_module_get_ctx(ac->module);
262
263	ret = ldb_build_search_req(&search_req, ldb, ac,
264				   ac->dn, LDB_SCOPE_BASE,
265				   "(&(objectClass=kerberosSecret)"
266				     "(privateKeytab=*))", attrs,
267				   NULL,
268				   ac, ukt_search_modified_callback,
269				   ac->req);
270	if (ret != LDB_SUCCESS) {
271		return ret;
272	}
273	return ldb_next_request(ac->module, search_req);
274}
275
276
277/* add */
278static int update_kt_add(struct ldb_module *module, struct ldb_request *req)
279{
280	struct ldb_context *ldb;
281	struct update_kt_ctx *ac;
282	struct ldb_request *down_req;
283	int ret;
284
285	ldb = ldb_module_get_ctx(module);
286
287	ac = update_kt_ctx_init(module, req);
288	if (ac == NULL) {
289		return LDB_ERR_OPERATIONS_ERROR;
290	}
291
292	ac->dn = req->op.add.message->dn;
293
294	ret = ldb_build_add_req(&down_req, ldb, ac,
295				req->op.add.message,
296				req->controls,
297				ac, update_kt_op_callback,
298				req);
299	if (ret != LDB_SUCCESS) {
300		return ret;
301	}
302
303	return ldb_next_request(module, down_req);
304}
305
306/* modify */
307static int update_kt_modify(struct ldb_module *module, struct ldb_request *req)
308{
309	struct ldb_context *ldb;
310	struct update_kt_ctx *ac;
311	struct ldb_request *down_req;
312	int ret;
313
314	ldb = ldb_module_get_ctx(module);
315
316	ac = update_kt_ctx_init(module, req);
317	if (ac == NULL) {
318		return LDB_ERR_OPERATIONS_ERROR;
319	}
320
321	ac->dn = req->op.mod.message->dn;
322
323	ret = ldb_build_mod_req(&down_req, ldb, ac,
324				req->op.mod.message,
325				req->controls,
326				ac, update_kt_op_callback,
327				req);
328	if (ret != LDB_SUCCESS) {
329		return ret;
330	}
331
332	return ldb_next_request(module, down_req);
333}
334
335/* delete */
336static int update_kt_delete(struct ldb_module *module, struct ldb_request *req)
337{
338	struct update_kt_ctx *ac;
339
340	ac = update_kt_ctx_init(module, req);
341	if (ac == NULL) {
342		return LDB_ERR_OPERATIONS_ERROR;
343	}
344
345	ac->dn = req->op.del.dn;
346	ac->do_delete = true;
347
348	return ukt_search_modified(ac);
349}
350
351/* rename */
352static int update_kt_rename(struct ldb_module *module, struct ldb_request *req)
353{
354	struct ldb_context *ldb;
355	struct update_kt_ctx *ac;
356	struct ldb_request *down_req;
357	int ret;
358
359	ldb = ldb_module_get_ctx(module);
360
361	ac = update_kt_ctx_init(module, req);
362	if (ac == NULL) {
363		return LDB_ERR_OPERATIONS_ERROR;
364	}
365
366	ac->dn = req->op.rename.newdn;
367
368	ret = ldb_build_rename_req(&down_req, ldb, ac,
369				req->op.rename.olddn,
370				req->op.rename.newdn,
371				req->controls,
372				ac, update_kt_op_callback,
373				req);
374	if (ret != LDB_SUCCESS) {
375		return ret;
376	}
377
378	return ldb_next_request(module, down_req);
379}
380
381/* prepare for a commit */
382static int update_kt_prepare_commit(struct ldb_module *module)
383{
384	struct ldb_context *ldb;
385	struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
386	struct dn_list *p;
387
388	ldb = ldb_module_get_ctx(module);
389
390	for (p=data->changed_dns; p; p = p->next) {
391		int kret;
392		kret = cli_credentials_update_keytab(p->creds, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"));
393		if (kret != 0) {
394			talloc_free(data->changed_dns);
395			data->changed_dns = NULL;
396			ldb_asprintf_errstring(ldb, "Failed to update keytab: %s", error_message(kret));
397			return LDB_ERR_OPERATIONS_ERROR;
398		}
399	}
400
401	talloc_free(data->changed_dns);
402	data->changed_dns = NULL;
403
404	return ldb_next_prepare_commit(module);
405}
406
407/* end a transaction */
408static int update_kt_del_trans(struct ldb_module *module)
409{
410	struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private);
411
412	talloc_free(data->changed_dns);
413	data->changed_dns = NULL;
414
415	return ldb_next_del_trans(module);
416}
417
418static int update_kt_init(struct ldb_module *module)
419{
420	struct ldb_context *ldb;
421	struct update_kt_private *data;
422
423	ldb = ldb_module_get_ctx(module);
424
425	data = talloc(module, struct update_kt_private);
426	if (data == NULL) {
427		ldb_oom(ldb);
428		return LDB_ERR_OPERATIONS_ERROR;
429	}
430
431	data->changed_dns = NULL;
432
433	ldb_module_set_private(module, data);
434
435	return ldb_next_init(module);
436}
437
438_PUBLIC_ const struct ldb_module_ops ldb_update_keytab_module_ops = {
439	.name		   = "update_keytab",
440	.init_context	   = update_kt_init,
441	.add               = update_kt_add,
442	.modify            = update_kt_modify,
443	.rename            = update_kt_rename,
444	.del               = update_kt_delete,
445	.prepare_commit    = update_kt_prepare_commit,
446	.del_transaction   = update_kt_del_trans,
447};
448