2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2010-2011 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
18 #ifndef SLAPD_MOD_KINIT
19 #define SLAPD_MOD_KINIT SLAPD_MOD_DYNAMIC
22 #ifdef SLAPD_MOD_KINIT
27 #include <ac/string.h>
28 #include <krb5/krb5.h>
30 typedef struct kinit_data {
35 krb5_get_init_creds_opt *opts;
38 static char* principal;
40 static kinit_data *kid;
43 log_krb5_errmsg( krb5_context ctx, const char* func, krb5_error_code rc )
45 const char* errmsg = krb5_get_error_message(ctx, rc);
46 Log2(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "slapd-kinit: %s: %s\n", func, errmsg);
47 krb5_free_error_message(ctx, errmsg);
52 kinit_check_tgt(kinit_data *kid, int *remaining)
57 krb5_cc_cursor cursor;
60 time_t now=time(NULL);
62 rc = krb5_cc_get_principal(kid->ctx, kid->ccache, &princ);
64 log_krb5_errmsg(kid->ctx, "krb5_cc_get_principal", rc);
67 if (!krb5_principal_compare(kid->ctx, kid->princ, princ)) {
68 Log0(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
69 "Principal in ccache does not match requested principal\n");
70 krb5_free_principal(kid->ctx, princ);
75 rc = krb5_cc_start_seq_get(kid->ctx, kid->ccache, &cursor);
77 log_krb5_errmsg(kid->ctx, "krb5_cc_start_seq_get", rc);
78 krb5_free_principal(kid->ctx, princ);
82 while (!(rc = krb5_cc_next_cred(kid->ctx, kid->ccache, &cursor, &creds))) {
83 if (krb5_is_config_principal(kid->ctx, creds.server)) {
84 krb5_free_cred_contents(kid->ctx, &creds);
88 if (creds.server->length==2 &&
89 (!strcmp(creds.server->data[0].data, "krbtgt")) &&
90 (!strcmp(creds.server->data[1].data, princ->realm.data))) {
92 krb5_unparse_name(kid->ctx, creds.server, &name);
94 *remaining = (time_t)creds.times.endtime-now;
95 if ( *remaining <= 0) {
96 Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
97 "kinit_qtask: TGT (%s) expired\n", name);
99 Log4(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
100 "kinit_qtask: TGT (%s) expires in %dh:%02dm:%02ds\n",
101 name, *remaining/3600, (*remaining%3600)/60, *remaining%60);
105 if (*remaining <= 30) {
106 if (creds.times.renew_till-60 > now) {
107 int renewal=creds.times.renew_till-now;
108 Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
109 "kinit_qtask: Time remaining for renewal: %dh:%02dm:%02ds\n",
110 renewal/3600, (renewal%3600)/60, renewal%60);
113 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
114 "kinit_qtask: Only short time left for renewal. "
115 "Trying to re-init.\n");
121 krb5_free_cred_contents(kid->ctx, &creds);
124 krb5_free_cred_contents(kid->ctx, &creds);
127 krb5_cc_end_seq_get(kid->ctx, kid->ccache, &cursor);
128 krb5_free_principal(kid->ctx, princ);
133 kinit_qtask( void *ctx, void *arg )
135 struct re_s *rtask = arg;
136 kinit_data *kid = (kinit_data*)rtask->arg;
139 int nextcheck, remaining, renew=0;
140 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: running TGT check\n");
142 memset(&creds, 0, sizeof(creds));
144 renew = kinit_check_tgt(kid, &remaining);
148 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
149 "kinit_qtask: Trying to renew TGT: ");
150 rc = krb5_get_renewed_creds(kid->ctx, &creds, kid->princ, kid->ccache, NULL);
152 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n");
153 log_krb5_errmsg( kid->ctx,
154 "kinit_qtask, Renewal failed: krb5_get_renewed_creds", rc );
157 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n");
158 krb5_cc_initialize(kid->ctx, kid->ccache, creds.client);
159 krb5_cc_store_cred(kid->ctx, kid->ccache, &creds);
160 krb5_free_cred_contents(kid->ctx, &creds);
161 renew=kinit_check_tgt(kid, &remaining);
165 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
166 "kinit_qtask: Trying to get new TGT: ");
167 rc = krb5_get_init_creds_keytab( kid->ctx, &creds, kid->princ,
168 kid->keytab, 0, NULL, kid->opts);
170 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n");
171 log_krb5_errmsg(kid->ctx, "krb5_get_init_creds_keytab", rc);
173 Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n");
174 renew=kinit_check_tgt(kid, &remaining);
176 krb5_free_cred_contents(kid->ctx, &creds);
180 nextcheck = remaining-30;
185 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
186 if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
187 ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
189 Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
190 "kinit_qtask: Next TGT check in %dh:%02dm:%02ds\n",
191 nextcheck/3600, (nextcheck%3600)/60, nextcheck%60);
192 rtask->interval.tv_sec = nextcheck;
193 ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
194 slap_wake_listener();
195 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
200 kinit_initialize(void)
202 Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_initialize\n" );
204 struct re_s *task = NULL;
206 kid = ch_calloc(1, sizeof(kinit_data) );
208 rc = krb5_init_context( &kid->ctx );
210 rc = krb5_cc_default(kid->ctx, &kid->ccache );
214 int len=STRLENOF("ldap/")+global_host_bv.bv_len+1;
215 principal=ch_calloc(len, 1);
216 snprintf(principal, len, "ldap/%s", global_host_bv.bv_val);
217 Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Principal <%s>\n", principal);
220 rc = krb5_parse_name(kid->ctx, principal, &kid->princ);
223 if ( !rc && kt_name) {
224 rc = krb5_kt_resolve(kid->ctx, kt_name, &kid->keytab);
228 rc = krb5_get_init_creds_opt_alloc(kid->ctx, &kid->opts);
231 rc = krb5_get_init_creds_opt_set_out_ccache( kid->ctx, kid->opts, kid->ccache);
234 ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
235 task = ldap_pvt_runqueue_insert( &slapd_rq, 10, kinit_qtask, (void*)kid,
236 "kinit_qtask", "ldap/bronsted.g17.lan@G17.LAN" );
237 ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
241 log_krb5_errmsg(kid->ctx, "kinit_initialize", rc);
247 #if SLAPD_MOD_KINIT == SLAPD_MOD_DYNAMIC
248 int init_module(int argc, char *argv[]) {
250 principal = ch_strdup(argv[0]);
253 kt_name = ch_strdup(argv[1]);
258 return kinit_initialize();
270 task=ldap_pvt_runqueue_find( &slapd_rq, kinit_qtask, (void*)kid);
272 if ( ldap_pvt_runqueue_isrunning(&slapd_rq, task) ) {
273 ldap_pvt_runqueue_stoptask(&slapd_rq, task);
275 ldap_pvt_runqueue_remove(&slapd_rq, task);
279 krb5_free_principal(kid->ctx, kid->princ);
281 krb5_cc_close(kid->ctx, kid->ccache);
283 krb5_kt_close(kid->ctx, kid->keytab);
285 krb5_get_init_creds_opt_free(kid->ctx, kid->opts);
286 krb5_free_context(kid->ctx);
294 #endif /* SLAPD_MOD_KINIT */