#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>

#include <signal.h>
#include <sys/utsname.h>

#include <krb.h>
#include <des.h>
#include <com_err.h>

void alarm_handler();
void cleanup();
int get_tokens();

static char host[256];
static char realm[REALM_SZ+1];

#define WAKEUP 300	/* renewal interval (seconds) */
#define TKT_LIFE 2	/* ticket lifetime (TKT_LIFE * 5 min) */

main(argc, argv)
    int argc;
    char *argv[];
{
    int code;
    pid_t pid;
    char buf[256];
    struct utsname utn;
    struct sigaction sa;
    sigset_t sigs;

    if (setpag()) {
	return 1;
    }

    if (uname(&utn) < 0) {
	return 2;
    }
    strncpy(host, krb_get_phost(utn.nodename), sizeof(host));

    if (krb_get_lrealm(realm, 1) != KSUCCESS) {
	return 3;
    }

    pid = getpid();
    sprintf(buf, "KRBTKFILE=/tmp/tkt_pid%d", (int)pid);
    putenv(buf);

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = cleanup;
    (void) sigaction(SIGHUP, &sa, (struct sigaction *)0);
    (void) sigaction(SIGINT, &sa, (struct sigaction *)0);
    (void) sigaction(SIGTERM, &sa, (struct sigaction *)0);

    sa.sa_handler = alarm_handler;
    (void) sigaction(SIGALRM, &sa, (struct sigaction *)0);
    
    (void) get_tokens();
    
    pid = fork();
    switch(pid)
    {
    case -1:
	return 11;
	/* NOTREACHED */
    case 0:
	break;
    default:
	sleep(2);
	execvp(argv[1], &argv[1]);
	return -1;
	/* NOTREACHED */
    }

    /* Child process (renewing daemon) */
    while(1)
    {
	alarm(WAKEUP);
	sigemptyset(&sigs);
	sigsuspend(&sigs);

	alarm(0);
	(void) get_tokens();
    }
    /* NOTREACHED */
}

int get_tokens()
{
    int code;
    pid_t pid;
    
    code = krb_get_svc_in_tkt("rcmd", host, realm,
			      "krbtgt", realm, TKT_LIFE, KEYFILE);
    if (code) {
	fprintf(stderr, "renew: %s", error_message(code));
    } else {
	pid = fork();
	switch(pid) {
	case -1:
	    break;
	case 0:
	    execl("/bin/athena/aklog", "aklog", 0);
	    exit(2);
	default:
	    waitpid(pid, 0, 0);
	}
    }
    return code;
}

void alarm_handler(sig)
    int sig;
{
    return;
}

void cleanup(sig)
    int sig;
{
    (void) dest_tkt();
    exit(0);
}
