X-Git-Url: http://dolda2000.com/gitweb/?p=utils.git;a=blobdiff_plain;f=krb5-agent.c;h=a24423e985dbeb4304b7a10a7337b13ce3b28561;hp=7edd36968b5e6105ae5a984a5f3503582c6fe290;hb=c848a4bf736eb8ac67e9225d0e72618a6da1011a;hpb=e73ae1346f7b795d6f89a193dbb5d4b5fca9b39a diff --git a/krb5-agent.c b/krb5-agent.c index 7edd369..a24423e 100644 --- a/krb5-agent.c +++ b/krb5-agent.c @@ -1,3 +1,21 @@ +/* + * krb5-agent - Renews Kerberos tickets periodically. + * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ #include #include #include @@ -7,12 +25,12 @@ #include #include -#define STD_INTERVAL (3600 * 8) - volatile int died = 0; pid_t child; int execmode = 0, failsafe = 0; int verbose = 0, quiet = 0; +time_t renewat; + krb5_context context = NULL; krb5_ccache ccache = NULL; @@ -20,8 +38,10 @@ void cleanup_krb5(void) { if(ccache != NULL) krb5_cc_close(context, ccache); + ccache = NULL; if(context != NULL) krb5_free_context(context); + context = NULL; } void sighandler(int sig) @@ -30,26 +50,124 @@ void sighandler(int sig) case SIGCHLD: died = 1; break; + case SIGHUP: + case SIGINT: + case SIGTERM: + if(execmode) + kill(child, sig); + break; } } void renew(void) { int ret; + krb5_principal me; + krb5_creds creds; - if(ccache == NULL) + if(context == NULL) return; + if(ccache == NULL) { + if((ret = krb5_cc_default(context, &ccache)) != 0) { + if(!quiet) + fprintf(stderr, "could not initialize Kerberos context: %s\n", error_message(ret)); + return; + } + } + + me = NULL; + memset(&creds, 0, sizeof(creds)); + if((ret = krb5_cc_get_principal(context, ccache, &me)) != 0) { + if(!quiet) + fprintf(stderr, "could not get principal from cache: %s\n", error_message(ret)); + goto out; + } + if((ret = krb5_get_renewed_creds(context, &creds, me, ccache, NULL)) != 0) { + if(!quiet) + fprintf(stderr, "could not get renewed credentials: %s\n", error_message(ret)); + goto out; + } + if((ret = krb5_cc_initialize(context, ccache, me)) != 0) { + if(!quiet) + fprintf(stderr, "could not reinitialize cache: %s\n", error_message(ret)); + krb5_free_cred_contents(context, &creds); + goto out; + } + if((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) { + if(!quiet) + fprintf(stderr, "could not store renewed credentials: %s\n", error_message(ret)); + krb5_free_cred_contents(context, &creds); + goto out; + } + krb5_free_cred_contents(context, &creds); + if(verbose >= 1) + printf("successfully renewed credentials\n"); + + out: + if(me != NULL) + krb5_free_principal(context, me); +} + +time_t goodrenewtime(void) +{ + int ret; + krb5_principal me; + krb5_cc_cursor cur; + krb5_creds creds; + time_t now, good; + + if(context == NULL) + return(-1); + if(ccache == NULL) { + if((ret = krb5_cc_default(context, &ccache)) != 0) { + if(!quiet) + fprintf(stderr, "could not initialize Kerberos context: %s\n", error_message(ret)); + return(-1); + } + } + + me = NULL; + cur = NULL; + good = -1; + if((ret = krb5_cc_get_principal(context, ccache, &me)) != 0) { + if(!quiet) + fprintf(stderr, "could not get principal from cache: %s\n", error_message(ret)); + goto out; + } + if((ret = krb5_cc_start_seq_get(context, ccache, &cur)) != 0) { + if(!quiet) + fprintf(stderr, "could not open credentials cache: %s\n", error_message(ret)); + goto out; + } + now = time(NULL); + while(!krb5_cc_next_cred(context, ccache, &cur, &creds)) { + if(!strcmp(krb5_princ_component(context, creds.server, 0)->data, KRB5_TGS_NAME) && + !strcmp(krb5_princ_component(context, creds.server, 1)->data, me->realm.data)) { + if(!creds.times.starttime) + creds.times.starttime = creds.times.authtime; + good = (creds.times.starttime + (((creds.times.endtime - creds.times.starttime) * 9) / 10)); + break; + } + krb5_free_cred_contents(context, &creds); + } + + out: + if(cur != NULL) + krb5_cc_end_seq_get(context, ccache, &cur); + if(me != NULL) + krb5_free_principal(context, me); + return(good); } int main(int argc, char **argv) { char *p; int c; - time_t interval, last, now; + time_t interval, now; pid_t wpid; int ret, status; - interval = STD_INTERVAL; + interval = -1; while((c = getopt(argc, argv, "+hi:vqf")) != -1) { switch(c) { case 'v': @@ -63,7 +181,7 @@ int main(int argc, char **argv) break; case 'i': p = optarg + strlen(optarg) - 1; - if((*p >= 'a') || (*p <= 'z')) { + if((*p >= 'a') && (*p <= 'z')) { if(*p == 'm') interval = 60; else if(*p == 'h') @@ -112,14 +230,19 @@ int main(int argc, char **argv) } if(child == 0) { char buf[80]; - snprintf(buf, 80, "KRB5_AGENT_PID=%i", getpid()); + snprintf(buf, 80, "KRB5_AGENT_PID=%i", getppid()); putenv(buf); execvp(argv[optind], argv + optind); perror(argv[optind]); exit(255); } + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); } - now = last = time(NULL); + now = time(NULL); + if(interval >= 0) + renewat = now + interval; while(1) { if(died) { wpid = waitpid(-1, &status, WNOHANG); @@ -130,6 +253,7 @@ int main(int argc, char **argv) if(WIFEXITED(status)) { exit(WEXITSTATUS(status)); } else { + cleanup_krb5(); signal(WTERMSIG(status), SIG_DFL); kill(getpid(), WTERMSIG(status)); exit(255); @@ -137,10 +261,24 @@ int main(int argc, char **argv) } died = 0; } - sleep((last + interval) - now); + if(interval < 0) { + if((renewat = goodrenewtime()) < 0) { + renewat = -1; + } else if(verbose >= 2) { + printf("will renew tickets at %s", ctime(&renewat)); + } + } + if(renewat < 0) + sleep(60); + else + sleep(renewat - now); now = time(NULL); - if(now >= last + interval) + if((renewat >= 0) && (now >= renewat)) { renew(); + now = time(NULL); + if(interval >= 0) + renewat = now + interval; + } } }