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 "auth/kerberos/kerberos_srv_keytab.h"
38 #include "dsdb/samdb/ldb_modules/util.h"
39 #include "param/secrets.h"
42 struct ldb_message
*msg
;
44 struct dn_list
*prev
, *next
;
47 struct update_kt_private
{
48 struct dn_list
*changed_dns
;
51 struct update_kt_ctx
{
52 struct ldb_module
*module
;
53 struct ldb_request
*req
;
58 struct ldb_reply
*op_reply
;
62 static struct update_kt_ctx
*update_kt_ctx_init(struct ldb_module
*module
,
63 struct ldb_request
*req
)
65 struct update_kt_ctx
*ac
;
67 ac
= talloc_zero(req
, struct update_kt_ctx
);
69 ldb_oom(ldb_module_get_ctx(module
));
79 /* FIXME: too many semi-async searches here for my taste, direct and indirect as
80 * cli_credentials_set_secrets() performs a sync ldb search.
81 * Just hope we are lucky and nothing breaks (using the tdb backend masks a lot
82 * of async issues). -SSS
84 static int add_modified(struct ldb_module
*module
, struct ldb_dn
*dn
, bool do_delete
,
85 struct ldb_request
*parent
)
87 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
88 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
91 struct ldb_result
*res
;
94 filter
= talloc_asprintf(data
,
95 "(&(objectClass=kerberosSecret)(privateKeytab=*))");
100 ret
= dsdb_module_search(module
, data
, &res
,
101 dn
, LDB_SCOPE_BASE
, NULL
,
102 DSDB_FLAG_NEXT_MODULE
, parent
,
105 if (ret
!= LDB_SUCCESS
) {
109 if (res
->count
!= 1) {
110 /* if it's not a kerberosSecret then we don't have anything to update */
115 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
,
381 ldb_get_opaque(ldb
, "loadparm"),
386 ldb_asprintf_errstring(ldb
, "Failed to setup krb5_context: %s", error_message(krb5_ret
));
390 tmp_ctx
= talloc_new(data
);
396 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
397 const char *error_string
;
400 struct ldb_message_element
*spn_el
= ldb_msg_find_element(p
->msg
, "servicePrincipalName");
401 const char **SPNs
= NULL
;
405 realm
= ldb_msg_find_attr_as_string(p
->msg
, "realm", NULL
);
408 upper_realm
= strupper_talloc(tmp_ctx
, realm
);
414 num_SPNs
= spn_el
->num_values
;
415 SPNs
= talloc_array(tmp_ctx
, const char *, num_SPNs
);
420 for (i
= 0; i
< num_SPNs
; i
++) {
421 SPNs
[i
] = talloc_asprintf(SPNs
, "%*.*s@%s",
422 (int)spn_el
->values
[i
].length
,
423 (int)spn_el
->values
[i
].length
,
424 (const char *)spn_el
->values
[i
].data
,
433 krb5_ret
= smb_krb5_update_keytab(tmp_ctx
, smb_krb5_context
->krb5_context
,
434 keytab_name_from_msg(tmp_ctx
, ldb
, p
->msg
),
435 ldb_msg_find_attr_as_string(p
->msg
, "samAccountName", NULL
),
436 realm
, SPNs
, num_SPNs
,
437 ldb_msg_find_attr_as_string(p
->msg
, "saltPrincipal", NULL
),
438 ldb_msg_find_attr_as_string(p
->msg
, "secret", NULL
),
439 ldb_msg_find_attr_as_string(p
->msg
, "priorSecret", NULL
),
440 ldb_msg_find_attr_as_int(p
->msg
, "msDS-KeyVersionNumber", 0),
441 (uint32_t)ldb_msg_find_attr_as_int(p
->msg
, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES
),
442 p
->do_delete
, NULL
, &error_string
);
444 ldb_asprintf_errstring(ldb
, "Failed to update keytab from entry %s in %s: %s",
445 ldb_dn_get_linearized(p
->msg
->dn
),
446 (const char *)ldb_get_opaque(ldb
, "ldb_url"),
452 talloc_free(data
->changed_dns
);
453 data
->changed_dns
= NULL
;
454 talloc_free(tmp_ctx
);
456 return ldb_next_prepare_commit(module
);
459 talloc_free(data
->changed_dns
);
460 data
->changed_dns
= NULL
;
461 talloc_free(tmp_ctx
);
462 return LDB_ERR_OPERATIONS_ERROR
;
465 /* end a transaction */
466 static int update_kt_del_trans(struct ldb_module
*module
)
468 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
470 talloc_free(data
->changed_dns
);
471 data
->changed_dns
= NULL
;
473 return ldb_next_del_trans(module
);
476 static int update_kt_init(struct ldb_module
*module
)
478 struct ldb_context
*ldb
;
479 struct update_kt_private
*data
;
481 ldb
= ldb_module_get_ctx(module
);
483 data
= talloc(module
, struct update_kt_private
);
488 data
->changed_dns
= NULL
;
490 ldb_module_set_private(module
, data
);
492 return ldb_next_init(module
);
495 static const struct ldb_module_ops ldb_update_keytab_module_ops
= {
496 .name
= "update_keytab",
497 .init_context
= update_kt_init
,
498 .add
= update_kt_add
,
499 .modify
= update_kt_modify
,
500 .rename
= update_kt_rename
,
501 .del
= update_kt_delete
,
502 .prepare_commit
= update_kt_prepare_commit
,
503 .del_transaction
= update_kt_del_trans
,
506 int ldb_update_keytab_module_init(const char *version
)
508 LDB_MODULE_CHECK_VERSION(version
);
509 return ldb_register_module(&ldb_update_keytab_module_ops
);