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 */
116 item
= talloc(data
->changed_dns
? (void *)data
->changed_dns
: (void *)data
, struct dn_list
);
123 item
->msg
= talloc_steal(item
, res
->msgs
[0]);
124 item
->do_delete
= do_delete
;
127 DLIST_ADD_END(data
->changed_dns
, item
, struct dn_list
*);
131 static int ukt_search_modified(struct update_kt_ctx
*ac
);
133 static int update_kt_op_callback(struct ldb_request
*req
,
134 struct ldb_reply
*ares
)
136 struct ldb_context
*ldb
;
137 struct update_kt_ctx
*ac
;
140 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
141 ldb
= ldb_module_get_ctx(ac
->module
);
144 return ldb_module_done(ac
->req
, NULL
, NULL
,
145 LDB_ERR_OPERATIONS_ERROR
);
147 if (ares
->error
!= LDB_SUCCESS
) {
148 return ldb_module_done(ac
->req
, ares
->controls
,
149 ares
->response
, ares
->error
);
152 if (ares
->type
!= LDB_REPLY_DONE
) {
153 ldb_set_errstring(ldb
, "Invalid request type!\n");
154 return ldb_module_done(ac
->req
, NULL
, NULL
,
155 LDB_ERR_OPERATIONS_ERROR
);
159 return ldb_module_done(ac
->req
, ares
->controls
,
160 ares
->response
, LDB_SUCCESS
);
163 ac
->op_reply
= talloc_steal(ac
, ares
);
165 ret
= ukt_search_modified(ac
);
166 if (ret
!= LDB_SUCCESS
) {
167 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
173 static int ukt_del_op(struct update_kt_ctx
*ac
)
175 struct ldb_context
*ldb
;
176 struct ldb_request
*down_req
;
179 ldb
= ldb_module_get_ctx(ac
->module
);
181 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
184 ac
, update_kt_op_callback
,
186 LDB_REQ_SET_LOCATION(down_req
);
187 if (ret
!= LDB_SUCCESS
) {
190 return ldb_next_request(ac
->module
, down_req
);
193 static int ukt_search_modified_callback(struct ldb_request
*req
,
194 struct ldb_reply
*ares
)
196 struct update_kt_ctx
*ac
;
199 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
202 return ldb_module_done(ac
->req
, NULL
, NULL
,
203 LDB_ERR_OPERATIONS_ERROR
);
205 if (ares
->error
!= LDB_SUCCESS
) {
206 return ldb_module_done(ac
->req
, ares
->controls
,
207 ares
->response
, ares
->error
);
210 switch (ares
->type
) {
211 case LDB_REPLY_ENTRY
:
216 case LDB_REPLY_REFERRAL
:
223 /* do the dirty sync job here :/ */
224 ret
= add_modified(ac
->module
, ac
->dn
, ac
->do_delete
, ac
->req
);
228 ret
= ukt_del_op(ac
);
229 if (ret
!= LDB_SUCCESS
) {
230 return ldb_module_done(ac
->req
,
236 return ldb_module_done(ac
->req
, ac
->op_reply
->controls
,
237 ac
->op_reply
->response
, LDB_SUCCESS
);
244 static int ukt_search_modified(struct update_kt_ctx
*ac
)
246 struct ldb_context
*ldb
;
247 static const char * const no_attrs
[] = { NULL
};
248 struct ldb_request
*search_req
;
251 ldb
= ldb_module_get_ctx(ac
->module
);
253 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
254 ac
->dn
, LDB_SCOPE_BASE
,
255 "(&(objectClass=kerberosSecret)"
256 "(privateKeytab=*))", no_attrs
,
258 ac
, ukt_search_modified_callback
,
260 LDB_REQ_SET_LOCATION(search_req
);
261 if (ret
!= LDB_SUCCESS
) {
264 return ldb_next_request(ac
->module
, search_req
);
269 static int update_kt_add(struct ldb_module
*module
, struct ldb_request
*req
)
271 struct ldb_context
*ldb
;
272 struct update_kt_ctx
*ac
;
273 struct ldb_request
*down_req
;
276 ldb
= ldb_module_get_ctx(module
);
278 ac
= update_kt_ctx_init(module
, req
);
280 return ldb_operr(ldb
);
283 ac
->dn
= req
->op
.add
.message
->dn
;
285 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
288 ac
, update_kt_op_callback
,
290 LDB_REQ_SET_LOCATION(down_req
);
291 if (ret
!= LDB_SUCCESS
) {
295 return ldb_next_request(module
, down_req
);
299 static int update_kt_modify(struct ldb_module
*module
, struct ldb_request
*req
)
301 struct ldb_context
*ldb
;
302 struct update_kt_ctx
*ac
;
303 struct ldb_request
*down_req
;
306 ldb
= ldb_module_get_ctx(module
);
308 ac
= update_kt_ctx_init(module
, req
);
310 return ldb_operr(ldb
);
313 ac
->dn
= req
->op
.mod
.message
->dn
;
315 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
318 ac
, update_kt_op_callback
,
320 LDB_REQ_SET_LOCATION(down_req
);
321 if (ret
!= LDB_SUCCESS
) {
325 return ldb_next_request(module
, down_req
);
329 static int update_kt_delete(struct ldb_module
*module
, struct ldb_request
*req
)
331 struct update_kt_ctx
*ac
;
333 ac
= update_kt_ctx_init(module
, req
);
335 return ldb_operr(ldb_module_get_ctx(module
));
338 ac
->dn
= req
->op
.del
.dn
;
339 ac
->do_delete
= true;
341 return ukt_search_modified(ac
);
345 static int update_kt_rename(struct ldb_module
*module
, struct ldb_request
*req
)
347 struct ldb_context
*ldb
;
348 struct update_kt_ctx
*ac
;
349 struct ldb_request
*down_req
;
352 ldb
= ldb_module_get_ctx(module
);
354 ac
= update_kt_ctx_init(module
, req
);
356 return ldb_operr(ldb
);
359 ac
->dn
= req
->op
.rename
.newdn
;
361 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
362 req
->op
.rename
.olddn
,
363 req
->op
.rename
.newdn
,
365 ac
, update_kt_op_callback
,
367 LDB_REQ_SET_LOCATION(down_req
);
368 if (ret
!= LDB_SUCCESS
) {
372 return ldb_next_request(module
, down_req
);
375 /* prepare for a commit */
376 static int update_kt_prepare_commit(struct ldb_module
*module
)
378 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
379 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
381 struct smb_krb5_context
*smb_krb5_context
;
382 int krb5_ret
= smb_krb5_init_context(data
, ldb_get_event_context(ldb
), ldb_get_opaque(ldb
, "loadparm"),
387 ldb_asprintf_errstring(ldb
, "Failed to setup krb5_context: %s", error_message(krb5_ret
));
391 tmp_ctx
= talloc_new(data
);
397 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
398 const char *error_string
;
401 struct ldb_message_element
*spn_el
= ldb_msg_find_element(p
->msg
, "servicePrincipalName");
406 realm
= ldb_msg_find_attr_as_string(p
->msg
, "realm", NULL
);
409 upper_realm
= strupper_talloc(tmp_ctx
, realm
);
415 num_SPNs
= spn_el
->num_values
;
416 SPNs
= talloc_array(tmp_ctx
, char *, num_SPNs
);
421 for (i
= 0; i
< num_SPNs
; i
++) {
422 SPNs
[i
] = talloc_asprintf(tmp_ctx
, "%*.*s@%s",
423 (int)spn_el
->values
[i
].length
,
424 (int)spn_el
->values
[i
].length
,
425 (const char *)spn_el
->values
[i
].data
,
434 krb5_ret
= smb_krb5_update_keytab(tmp_ctx
, smb_krb5_context
->krb5_context
,
435 keytab_name_from_msg(tmp_ctx
, ldb
, p
->msg
),
436 ldb_msg_find_attr_as_string(p
->msg
, "samAccountName", NULL
),
437 realm
, (const char **)SPNs
, num_SPNs
,
438 ldb_msg_find_attr_as_string(p
->msg
, "saltPrincipal", NULL
),
439 ldb_msg_find_attr_as_string(p
->msg
, "secret", NULL
),
440 ldb_msg_find_attr_as_string(p
->msg
, "priorSecret", NULL
),
441 ldb_msg_find_attr_as_int(p
->msg
, "msDS-KeyVersionNumber", 0),
442 (uint32_t)ldb_msg_find_attr_as_int(p
->msg
, "msDS-SupportedEncryptionTypes", ENC_ALL_TYPES
),
443 p
->do_delete
, NULL
, &error_string
);
445 ldb_asprintf_errstring(ldb
, "Failed to update keytab from entry %s in %s: %s",
446 ldb_dn_get_linearized(p
->msg
->dn
),
447 (const char *)ldb_get_opaque(ldb
, "ldb_url"),
453 talloc_free(data
->changed_dns
);
454 data
->changed_dns
= NULL
;
455 talloc_free(tmp_ctx
);
457 return ldb_next_prepare_commit(module
);
460 talloc_free(data
->changed_dns
);
461 data
->changed_dns
= NULL
;
462 talloc_free(tmp_ctx
);
463 return LDB_ERR_OPERATIONS_ERROR
;
466 /* end a transaction */
467 static int update_kt_del_trans(struct ldb_module
*module
)
469 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
471 talloc_free(data
->changed_dns
);
472 data
->changed_dns
= NULL
;
474 return ldb_next_del_trans(module
);
477 static int update_kt_init(struct ldb_module
*module
)
479 struct ldb_context
*ldb
;
480 struct update_kt_private
*data
;
482 ldb
= ldb_module_get_ctx(module
);
484 data
= talloc(module
, struct update_kt_private
);
489 data
->changed_dns
= NULL
;
491 ldb_module_set_private(module
, data
);
493 return ldb_next_init(module
);
496 static const struct ldb_module_ops ldb_update_keytab_module_ops
= {
497 .name
= "update_keytab",
498 .init_context
= update_kt_init
,
499 .add
= update_kt_add
,
500 .modify
= update_kt_modify
,
501 .rename
= update_kt_rename
,
502 .del
= update_kt_delete
,
503 .prepare_commit
= update_kt_prepare_commit
,
504 .del_transaction
= update_kt_del_trans
,
507 int ldb_update_keytab_module_init(const char *version
)
509 LDB_MODULE_CHECK_VERSION(version
);
510 return ldb_register_module(&ldb_update_keytab_module_ops
);