+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+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);
+}