Back to index

openldap  2.4.31
kinit.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 2010-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 #include <portable.h>
00017 
00018 #ifndef SLAPD_MOD_KINIT
00019 #define SLAPD_MOD_KINIT SLAPD_MOD_DYNAMIC
00020 #endif
00021 
00022 #ifdef SLAPD_MOD_KINIT
00023 
00024 #include <slap.h>
00025 #include "ldap_rq.h"
00026 #include <ac/errno.h>
00027 #include <ac/string.h>
00028 #include <krb5/krb5.h>
00029 
00030 typedef struct kinit_data {
00031        krb5_context ctx;
00032        krb5_ccache ccache;
00033        krb5_keytab keytab;
00034        krb5_principal princ;
00035        krb5_get_init_creds_opt *opts;
00036 } kinit_data;
00037 
00038 static char* principal;
00039 static char* kt_name;
00040 static kinit_data *kid;
00041 
00042 static void
00043 log_krb5_errmsg( krb5_context ctx, const char* func, krb5_error_code rc )
00044 {
00045        const char* errmsg = krb5_get_error_message(ctx, rc);
00046        Log2(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR, "slapd-kinit: %s: %s\n", func, errmsg);
00047        krb5_free_error_message(ctx, errmsg);
00048        return;
00049 }
00050 
00051 static int
00052 kinit_check_tgt(kinit_data *kid, int *remaining)
00053 {
00054        int ret=3;
00055        krb5_principal princ;
00056        krb5_error_code rc;
00057        krb5_cc_cursor cursor;
00058        krb5_creds creds;
00059        char *name;
00060        time_t now=time(NULL);
00061 
00062        rc = krb5_cc_get_principal(kid->ctx, kid->ccache, &princ);
00063        if (rc) {
00064               log_krb5_errmsg(kid->ctx, "krb5_cc_get_principal", rc);
00065               return 2;
00066        } else {
00067               if (!krb5_principal_compare(kid->ctx, kid->princ, princ)) {
00068                      Log0(LDAP_DEBUG_ANY, LDAP_LEVEL_ERR,
00069                                    "Principal in ccache does not match requested principal\n");
00070                      krb5_free_principal(kid->ctx, princ);
00071                      return 2;
00072               }
00073        }
00074 
00075        rc = krb5_cc_start_seq_get(kid->ctx, kid->ccache, &cursor);
00076        if (rc) {
00077               log_krb5_errmsg(kid->ctx, "krb5_cc_start_seq_get", rc);
00078               krb5_free_principal(kid->ctx, princ);
00079               return -1;
00080        }
00081 
00082        while (!(rc = krb5_cc_next_cred(kid->ctx, kid->ccache, &cursor, &creds))) {
00083               if (krb5_is_config_principal(kid->ctx, creds.server)) {
00084                      krb5_free_cred_contents(kid->ctx, &creds);
00085                      continue;
00086               }
00087 
00088               if (creds.server->length==2 &&
00089                             (!strcmp(creds.server->data[0].data, "krbtgt")) &&
00090                             (!strcmp(creds.server->data[1].data, princ->realm.data))) {
00091 
00092                      krb5_unparse_name(kid->ctx, creds.server, &name);
00093 
00094                      *remaining = (time_t)creds.times.endtime-now;
00095                      if ( *remaining <= 0) {
00096                             Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00097                                           "kinit_qtask: TGT (%s) expired\n", name);
00098                      } else {
00099                             Log4(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00100                                           "kinit_qtask: TGT (%s) expires in %dh:%02dm:%02ds\n",
00101                                           name, *remaining/3600, (*remaining%3600)/60, *remaining%60);
00102                      }
00103                      free(name);
00104 
00105                      if (*remaining <= 30) {
00106                             if (creds.times.renew_till-60 > now) {
00107                                    int renewal=creds.times.renew_till-now;
00108                                    Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00109                                                  "kinit_qtask: Time remaining for renewal: %dh:%02dm:%02ds\n",
00110                                                  renewal/3600, (renewal%3600)/60,  renewal%60);
00111                                    ret = 1;
00112                             } else {
00113                                    Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00114                                                  "kinit_qtask: Only short time left for renewal. "
00115                                                  "Trying to re-init.\n");
00116                                    ret = 2;
00117                             }
00118                      } else {
00119                             ret=0;
00120                      }
00121                      krb5_free_cred_contents(kid->ctx, &creds);
00122                      break;
00123               }
00124               krb5_free_cred_contents(kid->ctx, &creds);
00125 
00126        }
00127        krb5_cc_end_seq_get(kid->ctx, kid->ccache, &cursor);
00128        krb5_free_principal(kid->ctx, princ);
00129        return ret;
00130 }
00131 
00132 void*
00133 kinit_qtask( void *ctx, void *arg )
00134 {
00135        struct re_s     *rtask = arg;
00136        kinit_data    *kid = (kinit_data*)rtask->arg;
00137        krb5_error_code rc;
00138        krb5_creds creds;
00139        int nextcheck, remaining, renew=0;
00140        Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_qtask: running TGT check\n");
00141 
00142        memset(&creds, 0, sizeof(creds));
00143 
00144        renew = kinit_check_tgt(kid, &remaining);
00145 
00146        if (renew > 0) {
00147               if (renew==1) {
00148                      Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00149                                    "kinit_qtask: Trying to renew TGT: ");
00150                      rc = krb5_get_renewed_creds(kid->ctx, &creds, kid->princ, kid->ccache, NULL);
00151                      if (rc!=0) {
00152                             Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n");
00153                             log_krb5_errmsg( kid->ctx,
00154                                           "kinit_qtask, Renewal failed: krb5_get_renewed_creds", rc );
00155                             renew++;
00156                      } else {
00157                             Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n");
00158                             krb5_cc_initialize(kid->ctx, kid->ccache, creds.client);
00159                             krb5_cc_store_cred(kid->ctx, kid->ccache, &creds);
00160                             krb5_free_cred_contents(kid->ctx, &creds);
00161                             renew=kinit_check_tgt(kid, &remaining);
00162                      }
00163               }
00164               if (renew > 1) {
00165                      Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00166                                    "kinit_qtask: Trying to get new TGT: ");
00167                      rc = krb5_get_init_creds_keytab( kid->ctx, &creds, kid->princ,
00168                                    kid->keytab, 0, NULL, kid->opts);
00169                      if (rc) {
00170                             Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Failed\n");
00171                             log_krb5_errmsg(kid->ctx, "krb5_get_init_creds_keytab", rc);
00172                      } else {
00173                             Log0(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Success\n");
00174                             renew=kinit_check_tgt(kid, &remaining);
00175                      }
00176                      krb5_free_cred_contents(kid->ctx, &creds);
00177               }
00178        }
00179        if (renew == 0) {
00180               nextcheck = remaining-30;
00181        } else {
00182               nextcheck = 60;
00183        }
00184 
00185        ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00186        if ( ldap_pvt_runqueue_isrunning( &slapd_rq, rtask )) {
00187               ldap_pvt_runqueue_stoptask( &slapd_rq, rtask );
00188        }
00189        Log3(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG,
00190                      "kinit_qtask: Next TGT check in %dh:%02dm:%02ds\n",
00191                      nextcheck/3600, (nextcheck%3600)/60,  nextcheck%60);
00192        rtask->interval.tv_sec = nextcheck;
00193        ldap_pvt_runqueue_resched( &slapd_rq, rtask, 0 );
00194        slap_wake_listener();
00195        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00196        return NULL;
00197 }
00198 
00199 int
00200 kinit_initialize(void)
00201 {
00202        Log0( LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "kinit_initialize\n" );
00203        krb5_error_code rc;
00204        struct re_s *task = NULL;
00205 
00206        kid = ch_calloc(1, sizeof(kinit_data) );
00207 
00208        rc = krb5_init_context( &kid->ctx );
00209        if ( !rc )
00210               rc = krb5_cc_default(kid->ctx, &kid->ccache );
00211 
00212        if ( !rc ) {
00213               if (!principal) {
00214                      int len=STRLENOF("ldap/")+global_host_bv.bv_len+1;
00215                      principal=ch_calloc(len, 1);
00216                      snprintf(principal, len, "ldap/%s", global_host_bv.bv_val);
00217                      Log1(LDAP_DEBUG_TRACE, LDAP_LEVEL_DEBUG, "Principal <%s>\n", principal);
00218 
00219               }
00220               rc = krb5_parse_name(kid->ctx, principal, &kid->princ);
00221        }
00222 
00223        if ( !rc && kt_name) {
00224               rc = krb5_kt_resolve(kid->ctx, kt_name, &kid->keytab);
00225        }
00226 
00227        if ( !rc )
00228               rc = krb5_get_init_creds_opt_alloc(kid->ctx, &kid->opts);
00229 
00230        if ( !rc )
00231               rc = krb5_get_init_creds_opt_set_out_ccache( kid->ctx, kid->opts, kid->ccache);
00232 
00233        if ( !rc ) {
00234               ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
00235               task = ldap_pvt_runqueue_insert( &slapd_rq, 10, kinit_qtask, (void*)kid,
00236                             "kinit_qtask", "ldap/bronsted.g17.lan@G17.LAN" );
00237               ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
00238        }
00239 
00240        if (rc) {
00241               log_krb5_errmsg(kid->ctx, "kinit_initialize", rc);
00242               rc = -1;
00243        }
00244        return rc;
00245 }
00246 
00247 #if SLAPD_MOD_KINIT == SLAPD_MOD_DYNAMIC
00248 int init_module(int argc, char *argv[]) {
00249        if (argc > 0) {
00250               principal = ch_strdup(argv[0]);
00251        }
00252        if (argc > 1) {
00253               kt_name = ch_strdup(argv[1]);
00254        }
00255        if (argc > 2) {
00256               return -1;
00257        }
00258        return kinit_initialize();
00259 }
00260 
00261 int
00262 term_module() {
00263        if (principal)
00264               ch_free(principal);
00265        if (kt_name)
00266               ch_free(kt_name);
00267        if (kid) {
00268               struct re_s *task;
00269 
00270               task=ldap_pvt_runqueue_find( &slapd_rq, kinit_qtask, (void*)kid);
00271               if (task) {
00272                      if ( ldap_pvt_runqueue_isrunning(&slapd_rq, task) ) {
00273                             ldap_pvt_runqueue_stoptask(&slapd_rq, task);
00274                      }
00275                      ldap_pvt_runqueue_remove(&slapd_rq, task);
00276               }
00277               if ( kid->ctx ) {
00278                      if ( kid->princ )
00279                             krb5_free_principal(kid->ctx, kid->princ);
00280                      if ( kid->ccache )
00281                             krb5_cc_close(kid->ctx, kid->ccache);
00282                      if ( kid->keytab )
00283                             krb5_kt_close(kid->ctx, kid->keytab);
00284                      if ( kid->opts )
00285                             krb5_get_init_creds_opt_free(kid->ctx, kid->opts);
00286                      krb5_free_context(kid->ctx);
00287               }
00288               ch_free(kid);
00289        }
00290        return 0;
00291 }
00292 #endif
00293 
00294 #endif /* SLAPD_MOD_KINIT */
00295