/*
 * Let's play with kerberos ticket files!!!!
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <strings.h>
#include <netdb.h>
#include <netinet/in.h>
#include <krb.h>

#define SRV_FILE "/etc/srvtab"
#define DEFAULT_LIFETIME 96

#define HOST_LEN 80

char	*progname;
char	*tkt_string();
int	debug;			/* For the kerberos library */

char	*tkt_file;		/* File to store tickets */
char	*srv_file = SRV_FILE;	/*  where service keys may be */
				/* found */

int	srvtabmode = 0;		/* If one, generate a ticket-granting */
				/* ticket for a service found in */
				/* srvtab */

char	pname[ANAME_SZ];	/* name of principal */
char	pinst[INST_SZ];		/* instance of principal*/
char	prealm[REALM_SZ];	/* realm of principal */

char	k_flags;		/* Kerberos flags */
int	kvno;			/* Key version number */
int	lifetime;		/* Lifetime of ticket */

char	sname[ANAME_SZ];	/* name of service */
char	sinst[INST_SZ];		/* instance of service*/
char	srealm[REALM_SZ];	/* realm of service */

C_Block session_key;		/* session key */
C_Block	service_key;		/* service_key */

KTEXT_ST	tkt_st;		/* Where the constructed ticket goes */
KTEXT		tkt = &tkt_st;

struct in_addr	internet_address; /* Here's our address */
static struct timeval	k_time;	/* current time */

main(argc, argv)
	int argc;
	char **argv;
{
	int	retval;
	
	PRS(argv);
	init_inetaddr();
	if (!srvtabmode)
		init_principal();
	init_realm();
	init_service_key();
	
	if (srvtabmode) {
		srvtab_tktgen();
		/* NOTREACHED */
	}
		
	gettimeofday(&k_time,NULL); /* Get the current time */
	random_key(session_key);

	(void) printf("Creating %s%s%s@%s ticket for %s%s%s@%s\n",
		      sname,sinst[0] ? "." : "", sinst, srealm,
		      pname,pinst[0] ? "." : "", pinst, prealm);
	
	krb_create_ticket(tkt,k_flags,pname,pinst,prealm,
		      internet_address.s_addr,
		      session_key, lifetime, k_time.tv_sec,
		      sname, sinst, service_key);

	bzero(service_key,sizeof(service_key));
	
	retval = save_credentials(sname,sinst,srealm,session_key,lifetime,
				  kvno, tkt, k_time.tv_sec);
	if (retval == KFAILURE) {
		fprintf(stderr,"Unable to write ticket\n");
		exit(1);
	}

	bzero(session_key,sizeof(session_key));
	exit(0);
}

PRS(argv)
	char	**argv;
{
	progname = argv[0];
	k_flags = 0;
	kvno = 0;
	lifetime = DEFAULT_LIFETIME;
	tkt_file = TKT_FILE;	/* Set default ticket file */
	while (*(++argv) && (*argv[0] == '-')) {
		if (!strcmp(*argv,"-keyfile")) {
			if (*(++argv)) {
				srv_file = *argv;
				continue;
			}
			else usage();
		}
		if (!strcmp(*argv,"-s")) {
			srvtabmode = 1;
			continue;
		}
		if (!strcmp(*argv,"-d")) {
			debug = 1;
			continue;
		}
		if (!strcmp(*argv,"-lifetime")) {
			if (*(++argv)) {
				lifetime= atoi(*argv);
				if (lifetime < 5)
					lifetime = 1;
				else
					lifetime = (lifetime+4)/5;
				if (lifetime > 255)
					lifetime = 255;
				continue;
			} else
				usage();
		}
		if (!strcmp(*argv, "-tktfile")) {
			if (*(++argv)) {
				krb_set_tkt_string(*argv);
				continue;
			} else
				usage();
		}
		usage();
	}
	if (*argv)
		parse_principal(*argv++,sname,sinst,srealm);
	else 
		usage();	/* User didn't specify service */
}

usage() 
{
        fprintf(stderr,
		"Usage: %s [-d] [-s] [-keyfile filename] [-tktfile filename] [-lifetime minutes] service\n",
		progname);
        exit(1);
}

init_inetaddr()
{
	char		host[HOST_LEN];
	struct hostent	*hp;
	
	gethostname(host,sizeof(host));
	if ((hp = gethostbyname(host)) == NULL) {
		perror("gethostbyname");
		exit(1);
	}
	bcopy(hp->h_addr, &internet_address, hp->h_length);
}

init_principal()
{
	char	str[255];
	
	/* Open ticket file and get principal, instance, and realm */ 
	if ((krb_get_tf_fullname(tkt_file, pname, pinst, prealm)) != KSUCCESS){
		printf("Ticket file not found; creating new one....\n");
		printf("Kerberos principal: ");
		gets(str);
		parse_principal(str,pname,pinst,prealm);
		if (prealm[0]) {
			fprintf(stderr,"Can't specify your realm!\n");
			exit(1);
		}
		in_tkt(pname,pinst);
		if (srealm[0])
			strcpy(prealm,srealm);
	}
}

init_realm()
{
	if (!prealm[0] && krb_get_lrealm(prealm,1)) {
		fprintf(stderr,"Can't get local realm\n");
		exit(1);
	}
	if (!srealm[0])
		strcpy(srealm,prealm);
}

init_service_key()
{
	int	retval;
	
	if (access(srv_file,R_OK)) {
		fprintf(stderr,"Can't open %s\n",srv_file);
		exit(1);
	}
	retval = read_service_key(sname,sinst,srealm,kvno,
				  srv_file,service_key);
	if (retval == KFAILURE) {
		fprintf(stderr,
			"Service key for %s%s%s@%s not found in file %s\n",
			sname, sinst[0] ? "." : "", sinst, srealm,
			srv_file);
		exit(1);
	}
}

parse_principal(str, name, inst, rlm)
	char	*str, *name, *inst, *rlm;
{
	register char	*cp;

	cp = str;
	while (*cp && (*cp != '.') && (*cp != '@'))
		*name++ = *cp++;
	if (*cp == '.')
		cp++;
	while (*cp && (*cp != '@'))
		*inst++ = *cp++;
	if (*cp == '@')
		cp++;
	while (*cp)
		*rlm++ = *cp++;
	*name = *inst = *rlm = '\0';
}

/*
 * Generate a kerberos ticket-granting-ticket from /etc/srvtab
 */
srvtab_tktgen()
{
	register int	retval;
	
	(void) printf("Creating %s.%s@%s ticket for %s%s%s@%s\n",
		      "krbtgt", srealm, srealm,
		      sname,sinst[0] ? "." : "", sinst, srealm);
	
	retval = krb_get_svc_in_tkt(sname,sinst,srealm,"krbtgt", srealm,
				lifetime, srv_file);
	if (retval) {
		fprintf(stderr,"Unable to create ticket file:\n%s\n",
			krb_err_txt[retval]);
		exit(1);
	}
	exit(0);
}
		
