X-Git-Url: http://dolda2000.com/gitweb/?p=utils.git;a=blobdiff_plain;f=krb5-agent.c;h=a24423e985dbeb4304b7a10a7337b13ce3b28561;hp=6cbb7835e519ca34745a454beec77851b1660383;hb=dbf61e61b53f747b6eb10f0732d7ddccff3d3289;hpb=d5996a1f67acfd10f5291d52abec5caabe3cba2d diff --git a/krb5-agent.c b/krb5-agent.c index 6cbb783..a24423e 100644 --- a/krb5-agent.c +++ b/krb5-agent.c @@ -1,9 +1,289 @@ +/* + * 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 #include +#include +#include +#include +#include + +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; + +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) +{ + switch(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(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) { - return(0); + char *p; + int c; + time_t interval, now; + pid_t wpid; + int ret, status; + + interval = -1; + while((c = getopt(argc, argv, "+hi:vqf")) != -1) { + switch(c) { + case 'v': + verbose++; + break; + case 'q': + quiet = 1; + break; + case 'f': + failsafe = 1; + break; + case 'i': + p = optarg + strlen(optarg) - 1; + if((*p >= 'a') && (*p <= 'z')) { + if(*p == 'm') + interval = 60; + else if(*p == 'h') + interval = 3600; + else if(*p == 'd') + interval = 86400; + else + interval = 1; + *p = 0; + } else { + interval = 1; + } + interval *= atoi(optarg); + break; + case 'h': + case '?': + case ':': + default: + fprintf(stderr, "usage: krb5-agent [-hvqf] [-i interval] [program args...]\n"); + exit((c == 'h')?0:1); + } + } + + atexit(cleanup_krb5); + if((ret = krb5_init_context(&context)) != 0) { + if(!quiet) + fprintf(stderr, "could not initialize Kerberos context: %s\n", error_message(ret)); + if(!failsafe) + exit(1); + } + if(context != NULL) { + if((ret = krb5_cc_default(context, &ccache)) != 0) { + if(!quiet) + fprintf(stderr, "could not initialize Kerberos context: %s\n", error_message(ret)); + if(!failsafe) + exit(1); + } + } + + if(optind < argc) { + execmode = 1; + signal(SIGCHLD, sighandler); + if((child = fork()) < 0) { + perror("fork"); + exit(1); + } + if(child == 0) { + char buf[80]; + 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 = time(NULL); + if(interval >= 0) + renewat = now + interval; + while(1) { + if(died) { + wpid = waitpid(-1, &status, WNOHANG); + if(wpid < 0) { + perror("waitpid"); + } else if(execmode && (wpid == child)) { + /* Try to preserve exit status as best as we can... */ + if(WIFEXITED(status)) { + exit(WEXITSTATUS(status)); + } else { + cleanup_krb5(); + signal(WTERMSIG(status), SIG_DFL); + kill(getpid(), WTERMSIG(status)); + exit(255); + } + } + died = 0; + } + 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((renewat >= 0) && (now >= renewat)) { + renew(); + now = time(NULL); + if(interval >= 0) + renewat = now + interval; + } + } } + +/* + * Local Variables: + * compile-command: "gcc -Wall -g -o krb5-agent krb5-agent.c -lkrb5" + * End: + */