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 "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 "dsdb/samdb/ldb_modules/util.h"
40 struct ldb_message
*msg
;
42 struct dn_list
*prev
, *next
;
45 struct update_kt_private
{
46 struct dn_list
*changed_dns
;
49 struct update_kt_ctx
{
50 struct ldb_module
*module
;
51 struct ldb_request
*req
;
56 struct ldb_reply
*op_reply
;
60 static struct update_kt_ctx
*update_kt_ctx_init(struct ldb_module
*module
,
61 struct ldb_request
*req
)
63 struct update_kt_ctx
*ac
;
65 ac
= talloc_zero(req
, struct update_kt_ctx
);
67 ldb_oom(ldb_module_get_ctx(module
));
77 /* FIXME: too many semi-async searches here for my taste, direct and indirect as
78 * cli_credentials_set_secrets() performs a sync ldb search.
79 * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
80 * of async issues). -SSS
82 static int add_modified(struct ldb_module
*module
, struct ldb_dn
*dn
, bool do_delete
,
83 struct ldb_request
*parent
)
85 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
86 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
89 struct ldb_result
*res
;
92 filter
= talloc_asprintf(data
,
93 "(&(objectClass=kerberosSecret)(privateKeytab=*))");
98 ret
= dsdb_module_search(module
, data
, &res
,
99 dn
, LDB_SCOPE_BASE
, NULL
,
100 DSDB_FLAG_NEXT_MODULE
, parent
,
103 if (ret
!= LDB_SUCCESS
) {
107 if (res
->count
!= 1) {
108 /* if it's not a kerberosSecret then we don't have anything to update */
114 item
= talloc(data
->changed_dns
? (void *)data
->changed_dns
: (void *)data
, struct dn_list
);
121 item
->msg
= talloc_steal(item
, res
->msgs
[0]);
122 item
->do_delete
= do_delete
;
125 DLIST_ADD_END(data
->changed_dns
, item
, struct dn_list
*);
129 static int ukt_search_modified(struct update_kt_ctx
*ac
);
131 static int update_kt_op_callback(struct ldb_request
*req
,
132 struct ldb_reply
*ares
)
134 struct ldb_context
*ldb
;
135 struct update_kt_ctx
*ac
;
138 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
139 ldb
= ldb_module_get_ctx(ac
->module
);
142 return ldb_module_done(ac
->req
, NULL
, NULL
,
143 LDB_ERR_OPERATIONS_ERROR
);
145 if (ares
->error
!= LDB_SUCCESS
) {
146 return ldb_module_done(ac
->req
, ares
->controls
,
147 ares
->response
, ares
->error
);
150 if (ares
->type
!= LDB_REPLY_DONE
) {
151 ldb_set_errstring(ldb
, "Invalid request type!\n");
152 return ldb_module_done(ac
->req
, NULL
, NULL
,
153 LDB_ERR_OPERATIONS_ERROR
);
157 return ldb_module_done(ac
->req
, ares
->controls
,
158 ares
->response
, LDB_SUCCESS
);
161 ac
->op_reply
= talloc_steal(ac
, ares
);
163 ret
= ukt_search_modified(ac
);
164 if (ret
!= LDB_SUCCESS
) {
165 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
171 static int ukt_del_op(struct update_kt_ctx
*ac
)
173 struct ldb_context
*ldb
;
174 struct ldb_request
*down_req
;
177 ldb
= ldb_module_get_ctx(ac
->module
);
179 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
182 ac
, update_kt_op_callback
,
184 LDB_REQ_SET_LOCATION(down_req
);
185 if (ret
!= LDB_SUCCESS
) {
188 return ldb_next_request(ac
->module
, down_req
);
191 static int ukt_search_modified_callback(struct ldb_request
*req
,
192 struct ldb_reply
*ares
)
194 struct update_kt_ctx
*ac
;
197 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
200 return ldb_module_done(ac
->req
, NULL
, NULL
,
201 LDB_ERR_OPERATIONS_ERROR
);
203 if (ares
->error
!= LDB_SUCCESS
) {
204 return ldb_module_done(ac
->req
, ares
->controls
,
205 ares
->response
, ares
->error
);
208 switch (ares
->type
) {
209 case LDB_REPLY_ENTRY
:
214 case LDB_REPLY_REFERRAL
:
221 /* do the dirty sync job here :/ */
222 ret
= add_modified(ac
->module
, ac
->dn
, ac
->do_delete
, ac
->req
);
226 ret
= ukt_del_op(ac
);
227 if (ret
!= LDB_SUCCESS
) {
228 return ldb_module_done(ac
->req
,
234 return ldb_module_done(ac
->req
, ac
->op_reply
->controls
,
235 ac
->op_reply
->response
, LDB_SUCCESS
);
242 static int ukt_search_modified(struct update_kt_ctx
*ac
)
244 struct ldb_context
*ldb
;
245 static const char * const no_attrs
[] = { NULL
};
246 struct ldb_request
*search_req
;
249 ldb
= ldb_module_get_ctx(ac
->module
);
251 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
252 ac
->dn
, LDB_SCOPE_BASE
,
253 "(&(objectClass=kerberosSecret)"
254 "(privateKeytab=*))", no_attrs
,
256 ac
, ukt_search_modified_callback
,
258 LDB_REQ_SET_LOCATION(search_req
);
259 if (ret
!= LDB_SUCCESS
) {
262 return ldb_next_request(ac
->module
, search_req
);
267 static int update_kt_add(struct ldb_module
*module
, struct ldb_request
*req
)
269 struct ldb_context
*ldb
;
270 struct update_kt_ctx
*ac
;
271 struct ldb_request
*down_req
;
274 ldb
= ldb_module_get_ctx(module
);
276 ac
= update_kt_ctx_init(module
, req
);
278 return ldb_operr(ldb
);
281 ac
->dn
= req
->op
.add
.message
->dn
;
283 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
286 ac
, update_kt_op_callback
,
288 LDB_REQ_SET_LOCATION(down_req
);
289 if (ret
!= LDB_SUCCESS
) {
293 return ldb_next_request(module
, down_req
);
297 static int update_kt_modify(struct ldb_module
*module
, struct ldb_request
*req
)
299 struct ldb_context
*ldb
;
300 struct update_kt_ctx
*ac
;
301 struct ldb_request
*down_req
;
304 ldb
= ldb_module_get_ctx(module
);
306 ac
= update_kt_ctx_init(module
, req
);
308 return ldb_operr(ldb
);
311 ac
->dn
= req
->op
.mod
.message
->dn
;
313 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
316 ac
, update_kt_op_callback
,
318 LDB_REQ_SET_LOCATION(down_req
);
319 if (ret
!= LDB_SUCCESS
) {
323 return ldb_next_request(module
, down_req
);
327 static int update_kt_delete(struct ldb_module
*module
, struct ldb_request
*req
)
329 struct update_kt_ctx
*ac
;
331 ac
= update_kt_ctx_init(module
, req
);
333 return ldb_operr(ldb_module_get_ctx(module
));
336 ac
->dn
= req
->op
.del
.dn
;
337 ac
->do_delete
= true;
339 return ukt_search_modified(ac
);
343 static int update_kt_rename(struct ldb_module
*module
, struct ldb_request
*req
)
345 struct ldb_context
*ldb
;
346 struct update_kt_ctx
*ac
;
347 struct ldb_request
*down_req
;
350 ldb
= ldb_module_get_ctx(module
);
352 ac
= update_kt_ctx_init(module
, req
);
354 return ldb_operr(ldb
);
357 ac
->dn
= req
->op
.rename
.newdn
;
359 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
360 req
->op
.rename
.olddn
,
361 req
->op
.rename
.newdn
,
363 ac
, update_kt_op_callback
,
365 LDB_REQ_SET_LOCATION(down_req
);
366 if (ret
!= LDB_SUCCESS
) {
370 return ldb_next_request(module
, down_req
);
373 /* prepare for a commit */
374 static int update_kt_prepare_commit(struct ldb_module
*module
)
376 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
377 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
379 struct smb_krb5_context
*smb_krb5_context
;
380 int krb5_ret
= smb_krb5_init_context(data
, ldb_get_event_context(ldb
), ldb_get_opaque(ldb
, "loadparm"),
383 talloc_free(data
->changed_dns
);
384 data
->changed_dns
= NULL
;
385 ldb_asprintf_errstring(ldb
, "Failed to setup krb5_context: %s", error_message(krb5_ret
));
386 return LDB_ERR_OPERATIONS_ERROR
;
389 ldb
= ldb_module_get_ctx(module
);
391 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
392 const char *error_string
;
393 krb5_ret
= smb_krb5_update_keytab(data
, smb_krb5_context
, ldb
, p
->msg
, p
->do_delete
, &error_string
);
395 talloc_free(data
->changed_dns
);
396 data
->changed_dns
= NULL
;
397 ldb_asprintf_errstring(ldb
, "Failed to update keytab from entry %s in %s: %s",
398 ldb_dn_get_linearized(p
->msg
->dn
),
399 (const char *)ldb_get_opaque(ldb
, "ldb_url"),
401 return LDB_ERR_OPERATIONS_ERROR
;
405 talloc_free(data
->changed_dns
);
406 data
->changed_dns
= NULL
;
408 return ldb_next_prepare_commit(module
);
411 /* end a transaction */
412 static int update_kt_del_trans(struct ldb_module
*module
)
414 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
416 talloc_free(data
->changed_dns
);
417 data
->changed_dns
= NULL
;
419 return ldb_next_del_trans(module
);
422 static int update_kt_init(struct ldb_module
*module
)
424 struct ldb_context
*ldb
;
425 struct update_kt_private
*data
;
427 ldb
= ldb_module_get_ctx(module
);
429 data
= talloc(module
, struct update_kt_private
);
434 data
->changed_dns
= NULL
;
436 ldb_module_set_private(module
, data
);
438 return ldb_next_init(module
);
441 static const struct ldb_module_ops ldb_update_keytab_module_ops
= {
442 .name
= "update_keytab",
443 .init_context
= update_kt_init
,
444 .add
= update_kt_add
,
445 .modify
= update_kt_modify
,
446 .rename
= update_kt_rename
,
447 .del
= update_kt_delete
,
448 .prepare_commit
= update_kt_prepare_commit
,
449 .del_transaction
= update_kt_del_trans
,
452 int ldb_update_keytab_module_init(const char *version
)
454 LDB_MODULE_CHECK_VERSION(version
);
455 return ldb_register_module(&ldb_update_keytab_module_ops
);