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"
38 struct cli_credentials
*creds
;
39 struct dn_list
*prev
, *next
;
42 struct update_kt_private
{
43 struct dn_list
*changed_dns
;
46 struct update_kt_ctx
{
47 struct ldb_module
*module
;
48 struct ldb_request
*req
;
53 struct ldb_reply
*op_reply
;
57 static struct update_kt_ctx
*update_kt_ctx_init(struct ldb_module
*module
,
58 struct ldb_request
*req
)
60 struct update_kt_ctx
*ac
;
62 ac
= talloc_zero(req
, struct update_kt_ctx
);
64 ldb_oom(ldb_module_get_ctx(module
));
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
79 static 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
);
84 struct ldb_result
*res
;
85 const char *attrs
[] = { NULL
};
89 filter
= talloc_asprintf(data
, "(&(dn=%s)(&(objectClass=kerberosSecret)(privateKeytab=*)))",
90 ldb_dn_get_linearized(dn
));
93 return LDB_ERR_OPERATIONS_ERROR
;
96 ret
= ldb_search(ldb
, data
, &res
,
97 dn
, LDB_SCOPE_BASE
, attrs
, "%s", filter
);
98 if (ret
!= LDB_SUCCESS
) {
103 if (res
->count
!= 1) {
104 /* if it's not a kerberosSecret then we don't have anything to update */
111 item
= talloc(data
->changed_dns
? (void *)data
->changed_dns
: (void *)data
, struct dn_list
);
115 return LDB_ERR_OPERATIONS_ERROR
;
118 item
->creds
= cli_credentials_init(item
);
120 DEBUG(1, ("cli_credentials_init failed!"));
123 return LDB_ERR_OPERATIONS_ERROR
;
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
);
129 if (NT_STATUS_IS_OK(status
)) {
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);
134 cli_credentials_set_nt_hash(item
->creds
, NULL
,
137 DLIST_ADD_END(data
->changed_dns
, item
, struct dn_list
*);
142 static int ukt_search_modified(struct update_kt_ctx
*ac
);
144 static int update_kt_op_callback(struct ldb_request
*req
,
145 struct ldb_reply
*ares
)
147 struct ldb_context
*ldb
;
148 struct update_kt_ctx
*ac
;
151 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
152 ldb
= ldb_module_get_ctx(ac
->module
);
155 return ldb_module_done(ac
->req
, NULL
, NULL
,
156 LDB_ERR_OPERATIONS_ERROR
);
158 if (ares
->error
!= LDB_SUCCESS
) {
159 return ldb_module_done(ac
->req
, ares
->controls
,
160 ares
->response
, ares
->error
);
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
);
170 return ldb_module_done(ac
->req
, ares
->controls
,
171 ares
->response
, LDB_SUCCESS
);
174 ac
->op_reply
= talloc_steal(ac
, ares
);
176 ret
= ukt_search_modified(ac
);
177 if (ret
!= LDB_SUCCESS
) {
178 return ldb_module_done(ac
->req
, NULL
, NULL
, ret
);
184 static int ukt_del_op(struct update_kt_ctx
*ac
)
186 struct ldb_context
*ldb
;
187 struct ldb_request
*down_req
;
190 ldb
= ldb_module_get_ctx(ac
->module
);
192 ret
= ldb_build_del_req(&down_req
, ldb
, ac
,
195 ac
, update_kt_op_callback
,
197 if (ret
!= LDB_SUCCESS
) {
200 return ldb_next_request(ac
->module
, down_req
);
203 static int ukt_search_modified_callback(struct ldb_request
*req
,
204 struct ldb_reply
*ares
)
206 struct update_kt_ctx
*ac
;
209 ac
= talloc_get_type(req
->context
, struct update_kt_ctx
);
212 return ldb_module_done(ac
->req
, NULL
, NULL
,
213 LDB_ERR_OPERATIONS_ERROR
);
215 if (ares
->error
!= LDB_SUCCESS
) {
216 return ldb_module_done(ac
->req
, ares
->controls
,
217 ares
->response
, ares
->error
);
220 switch (ares
->type
) {
221 case LDB_REPLY_ENTRY
:
226 case LDB_REPLY_REFERRAL
:
233 /* do the dirty sync job here :/ */
234 ret
= add_modified(ac
->module
, ac
->dn
, ac
->do_delete
);
238 ret
= ukt_del_op(ac
);
239 if (ret
!= LDB_SUCCESS
) {
240 return ldb_module_done(ac
->req
,
246 return ldb_module_done(ac
->req
, ac
->op_reply
->controls
,
247 ac
->op_reply
->response
, LDB_SUCCESS
);
254 static int ukt_search_modified(struct update_kt_ctx
*ac
)
256 struct ldb_context
*ldb
;
257 static const char * const attrs
[] = { "distinguishedName", NULL
};
258 struct ldb_request
*search_req
;
261 ldb
= ldb_module_get_ctx(ac
->module
);
263 ret
= ldb_build_search_req(&search_req
, ldb
, ac
,
264 ac
->dn
, LDB_SCOPE_BASE
,
265 "(&(objectClass=kerberosSecret)"
266 "(privateKeytab=*))", attrs
,
268 ac
, ukt_search_modified_callback
,
270 if (ret
!= LDB_SUCCESS
) {
273 return ldb_next_request(ac
->module
, search_req
);
278 static int update_kt_add(struct ldb_module
*module
, struct ldb_request
*req
)
280 struct ldb_context
*ldb
;
281 struct update_kt_ctx
*ac
;
282 struct ldb_request
*down_req
;
285 ldb
= ldb_module_get_ctx(module
);
287 ac
= update_kt_ctx_init(module
, req
);
289 return LDB_ERR_OPERATIONS_ERROR
;
292 ac
->dn
= req
->op
.add
.message
->dn
;
294 ret
= ldb_build_add_req(&down_req
, ldb
, ac
,
297 ac
, update_kt_op_callback
,
299 if (ret
!= LDB_SUCCESS
) {
303 return ldb_next_request(module
, down_req
);
307 static int update_kt_modify(struct ldb_module
*module
, struct ldb_request
*req
)
309 struct ldb_context
*ldb
;
310 struct update_kt_ctx
*ac
;
311 struct ldb_request
*down_req
;
314 ldb
= ldb_module_get_ctx(module
);
316 ac
= update_kt_ctx_init(module
, req
);
318 return LDB_ERR_OPERATIONS_ERROR
;
321 ac
->dn
= req
->op
.mod
.message
->dn
;
323 ret
= ldb_build_mod_req(&down_req
, ldb
, ac
,
326 ac
, update_kt_op_callback
,
328 if (ret
!= LDB_SUCCESS
) {
332 return ldb_next_request(module
, down_req
);
336 static int update_kt_delete(struct ldb_module
*module
, struct ldb_request
*req
)
338 struct update_kt_ctx
*ac
;
340 ac
= update_kt_ctx_init(module
, req
);
342 return LDB_ERR_OPERATIONS_ERROR
;
345 ac
->dn
= req
->op
.del
.dn
;
346 ac
->do_delete
= true;
348 return ukt_search_modified(ac
);
352 static int update_kt_rename(struct ldb_module
*module
, struct ldb_request
*req
)
354 struct ldb_context
*ldb
;
355 struct update_kt_ctx
*ac
;
356 struct ldb_request
*down_req
;
359 ldb
= ldb_module_get_ctx(module
);
361 ac
= update_kt_ctx_init(module
, req
);
363 return LDB_ERR_OPERATIONS_ERROR
;
366 ac
->dn
= req
->op
.rename
.newdn
;
368 ret
= ldb_build_rename_req(&down_req
, ldb
, ac
,
369 req
->op
.rename
.olddn
,
370 req
->op
.rename
.newdn
,
372 ac
, update_kt_op_callback
,
374 if (ret
!= LDB_SUCCESS
) {
378 return ldb_next_request(module
, down_req
);
381 /* end a transaction */
382 static int update_kt_end_trans(struct ldb_module
*module
)
384 struct ldb_context
*ldb
;
385 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
388 ldb
= ldb_module_get_ctx(module
);
390 for (p
=data
->changed_dns
; p
; p
= p
->next
) {
392 kret
= cli_credentials_update_keytab(p
->creds
, ldb_get_event_context(ldb
), ldb_get_opaque(ldb
, "loadparm"));
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
;
401 talloc_free(data
->changed_dns
);
402 data
->changed_dns
= NULL
;
404 return ldb_next_end_trans(module
);
407 /* end a transaction */
408 static int update_kt_del_trans(struct ldb_module
*module
)
410 struct update_kt_private
*data
= talloc_get_type(ldb_module_get_private(module
), struct update_kt_private
);
412 talloc_free(data
->changed_dns
);
413 data
->changed_dns
= NULL
;
415 return ldb_next_del_trans(module
);
418 static int update_kt_init(struct ldb_module
*module
)
420 struct ldb_context
*ldb
;
421 struct update_kt_private
*data
;
423 ldb
= ldb_module_get_ctx(module
);
425 data
= talloc(module
, struct update_kt_private
);
428 return LDB_ERR_OPERATIONS_ERROR
;
431 data
->changed_dns
= NULL
;
433 ldb_module_set_private(module
, data
);
435 return ldb_next_init(module
);
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 .end_transaction
= update_kt_end_trans
,
446 .del_transaction
= update_kt_del_trans
,