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/>.
23 * Component: ldb update_keytabs module
25 * Description: Update keytabs whenever their matching secret record changes
27 * Author: Andrew Bartlett
31 #include "ldb_module.h"
32 #include "auth/credentials/credentials.h"
33 #include "auth/credentials/credentials_krb5.h"
34 #include "system/kerberos.h"
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
;
52 struct ldb_reply
*op_reply
;
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
);
63 ldb_oom(ldb_module_get_ctx(module
));
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
);
83 struct ldb_result
*res
;
84 const char *attrs
[] = { NULL
};
88 filter
= talloc_asprintf(data
, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
89 ldb_dn_get_linearized(dn
));
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
) {
102 if (res
->count
!= 1) {
103 /* if it's not a kerberosSecret then we don't have anything to update */
110 item
= talloc(data
->changed_dns
? (void *)data
->changed_dns
: (void *)data
, struct dn_list
);
114 return LDB_ERR_OPERATIONS_ERROR
;
117 item
->creds
= cli_credentials_init(item
);
119 DEBUG(1, ("cli_credentials_init failed!"));
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
);
128 if (NT_STATUS_IS_OK(status
)) {
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);
133 cli_credentials_set_nt_hash(item
->creds
, NULL
,
136 DLIST_ADD_END(data
->changed_dns
, item
, struct dn_list
*);
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
;
150 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
151 ldb
= ldb_module_get_ctx(ac
->module
);
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
);
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
);
183 static int ukt_del_op(struct update_kt_ctx
*ac
)
185 struct ldb_context
*ldb
;
186 struct ldb_request
*down_req
;
189 ldb
= ldb_module_get_ctx(ac
->module
);
191 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
194 ac
, update_kt_op_callback
,
196 if (ret
!= LDB_SUCCESS
) {
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
;
208 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
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
:
225 case LDB_REPLY_REFERRAL
:
232 /* do the dirty sync job here :/ */
233 ret
= add_modified(ac
->module
, ac
->dn
, ac
->delete);
237 ret
= ukt_del_op(ac
);
238 if (ret
!= LDB_SUCCESS
) {
239 return ldb_module_done(ac
->req
,
245 return ldb_module_done(ac
->req
, ac
->op_reply
->controls
,
246 ac
->op_reply
->response
, 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
;
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
,
267 ac
, ukt_search_modified_callback
,
269 if (ret
!= LDB_SUCCESS
) {
272 return ldb_next_request(ac
->module
, search_req
);
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
;
284 ldb
= ldb_module_get_ctx(module
);
286 ac
= update_kt_ctx_init(module
, req
);
288 return LDB_ERR_OPERATIONS_ERROR
;
291 ac
->dn
= req
->op
.add
.message
->dn
;
293 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
296 ac
, update_kt_op_callback
,
298 if (ret
!= LDB_SUCCESS
) {
302 return ldb_next_request(module
, down_req
);
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
;
313 ldb
= ldb_module_get_ctx(module
);
315 ac
= update_kt_ctx_init(module
, req
);
317 return LDB_ERR_OPERATIONS_ERROR
;
320 ac
->dn
= req
->op
.mod
.message
->dn
;
322 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
325 ac
, update_kt_op_callback
,
327 if (ret
!= LDB_SUCCESS
) {
331 return ldb_next_request(module
, down_req
);
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
);
341 return LDB_ERR_OPERATIONS_ERROR
;
344 ac
->dn
= req
->op
.del
.dn
;
347 return ukt_search_modified(ac
);
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
;
358 ldb
= ldb_module_get_ctx(module
);
360 ac
= update_kt_ctx_init(module
, req
);
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
,
371 ac
, update_kt_op_callback
,
373 if (ret
!= LDB_SUCCESS
) {
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
);
387 ldb
= ldb_module_get_ctx(module
);
389 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
391 kret
= cli_credentials_update_keytab(p
->creds
, ldb_get_event_context(ldb
), ldb_get_opaque(ldb
, "loadparm"));
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
);
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
,