/*
 * $Source: /usr/local/MASTER/plexus/kerberosIV/c.c,v $
 * $Author: sanders $
 *
 * Copyright 1989 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Simple UDP-based sample client program.  For demonstration.
 * This program performs no useful function.
 */

#ifndef	lint
static char rcsid_simple_client_c[] =
"$Header: /usr/local/MASTER/plexus/kerberosIV/c.c,v 2.0 1993/05/19 22:40:05 sanders Exp $";
#endif	lint

#include <mit-copyright.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <des.h>
#include <krb.h>
#include "simple.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MSG "hi, Jennifer!"		/* message text */

#define SEND(a,b,c,d,e,f) sendto(a,b,c,d,e,f)
#define RECV(a,b,c,d,e,f) recvfrom(a,b,c,d,e,f)

main()
{
	int sock, i;
	int flags = 0;			/* flags for sendto() */
	long len;
	u_long cksum = 0L;		/* cksum not used */
	char c_realm[REALM_SZ];		/* local Kerberos realm */
	char *s_realm;			/* server's Kerberos realm */
	struct servent *serv;
	struct hostent *host;
	struct sockaddr_in s_sock;	/* server address */
	char hostname[64];		/* local hostname */

	KTEXT_ST k;			/* Kerberos data */
	KTEXT ktxt = &k;
        MSG_DAT msg_data;               /* received message */

	extern char *krb_realmofhost();

	/* for krb_mk_safe/priv */
	struct sockaddr_in c_sock;	/* client address */
	CREDENTIALS c;			/* ticket & session key */
	CREDENTIALS *cred = &c;

	/* for krb_mk_priv */
	des_key_schedule sched;		/* session key schedule */

	/* Look up service */
	if ((serv = getservbyname(SERVICE, "udp")) == NULL) {
		fprintf(stderr, "service unknown: %s/udp\n", SERVICE);
		exit(1);
	}

	/* Look up server host */
	if ((host = gethostbyname(HOST)) == (struct hostent *) 0) {
		fprintf(stderr, "%s: unknown host\n", HOST);
		exit(1);
	}

	/* Set server's address */
	bzero((char *)&s_sock, sizeof(s_sock));
	bcopy(host->h_addr, (char *)&s_sock.sin_addr, host->h_length);
#ifdef DEBUG
	printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
#endif
	s_sock.sin_family = AF_INET;
	s_sock.sin_port = serv->s_port;

	if (gethostname(hostname, sizeof(hostname)) < 0) {
	    perror("gethostname");
	    exit(1);
	}

	if ((host = gethostbyname(hostname)) == (struct hostent *)0) {
	    fprintf(stderr, "%s: unknown host\n", hostname);
	    exit(1);
	}

	/* Open a socket */
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("opening datagram socket");
		exit(1);
	}

	bzero((char *)&c_sock, sizeof(c_sock));
	bcopy(host->h_addr, (char *)&c_sock.sin_addr, host->h_length);
	c_sock.sin_family = AF_INET;

	/* Bind it to set the address; kernel will fill in port # */
	if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
	    perror("binding datagram socket");
	    exit(1);
	}
	
	/* Get local realm, not needed, just an example */
	if ((i = krb_get_lrealm(c_realm, 1)) != KSUCCESS) {
		fprintf(stderr, "can't find local Kerberos realm\n");
		exit(1);
	}
	printf("Local Kerberos realm is %s\n", c_realm);

	/* Get Kerberos realm of host */
	s_realm = krb_realmofhost(HOST);
#ifdef DEBUG
	printf("Kerberos realm of %s is %s\n", HOST, s_realm);
#endif

	/* PREPARE KRB_MK_REQ MESSAGE */

	/* Get credentials for server, create krb_mk_req message */
	if ((i = krb_mk_req(ktxt, SERVICE, HOST, s_realm, cksum))
		!= KSUCCESS) {
		fprintf(stderr, "%s\n", krb_err_txt[i]);
		exit(1);
	}
	printf("Got credentials for %s.\n", SERVICE);

	/* Send authentication info to server */
	i = SEND(sock, (char *)ktxt->dat, ktxt->length, flags,
		   (struct sockaddr *)&s_sock, sizeof(s_sock));
	if (i < 0)
		perror("sending datagram message");
	printf("Sent authentication data: %d bytes\n", i);

	/* PREPARE KRB_MK_SAFE MESSAGE */

	/* Get my address */
	bzero((char *) &c_sock, sizeof(c_sock));
	i = sizeof(c_sock);
	if (getsockname(sock, (struct sockaddr *)&c_sock, &i) < 0) {
		perror("getsockname");
		exit(1);
	}

	/* Get session key */
	i = krb_get_cred(SERVICE, HOST, s_realm, cred);
#ifdef DEBUG
	printf("krb_get_cred returned %d: %s\n", i, krb_err_txt[i]);
#endif
	if (i != KSUCCESS)
		exit(1);

	/* Make the safe message */
	len = krb_mk_safe(MSG, ktxt->dat, strlen(MSG)+1,
		cred->session, &c_sock, &s_sock);
#ifdef DEBUG
	printf("krb_mk_safe returned %ld\n", len);
#endif

	/* Send it */
	i = SEND(sock, (char *)ktxt->dat, (int) len, flags,
		   (struct sockaddr *)&s_sock, sizeof(s_sock));
	if (i < 0)
		perror("sending safe message");
	printf("Sent checksummed message: %d bytes\n", i);

	/* VERIFY CLIENT */

{
#ifdef NOENCRYPTION
        bzero((char *)sched, sizeof(sched));
#else
        /* Get key schedule for session key */
        des_key_sched(cred->session, sched);
#endif
	fprintf(stderr, "client: expecting verification message\n");
	i = sizeof(s_sock);
        i = RECV(sock, (char *)ktxt->dat, MAX_KTXT_LEN, flags,
                 (struct sockaddr *)&s_sock, &i);
	fprintf(stderr, "client: got verification message\n");
	if (i < 0) { perror("receiving datagram"); exit(1); }
        i = krb_rd_priv(ktxt->dat, i, sched, cred->session,
		&s_sock, &c_sock, &msg_data);
        if (i != KSUCCESS) {
                fprintf(stderr, "%s\n", krb_err_txt[i]); exit(1); }
        
	fprintf(stderr, "client: sending reply: %s\n", msg_data.app_data);
	fprintf(stderr, "client: foo\n");
	/* Make the reply safe */
	len = krb_mk_safe(msg_data, ktxt->dat, msg_data.app_length,
		cred->session, &c_sock, &s_sock);
        if (i != KSUCCESS) {
                fprintf(stderr, "%s\n", krb_err_txt[i]); exit(1); }
	i = SEND(sock, (char *)ktxt->dat, (int) len, flags,
		   (struct sockaddr *)&s_sock, sizeof(s_sock));
	if (i < 0) { perror("sending safe reply"); exit(1); }
	fprintf(stderr, "client: done\n");
}


	/* PREPARE KRB_MK_PRIV MESSAGE */

#ifdef NOENCRYPTION
	bzero((char *)sched, sizeof(sched));
#else
	/* Get key schedule for session key */
	des_key_sched(cred->session, sched);
#endif

	/* Make the encrypted message */
	len = krb_mk_priv(MSG, ktxt->dat, strlen(MSG)+1,
			  sched, cred->session, &c_sock, &s_sock);
#ifdef DEBUG
	printf("krb_mk_priv returned %ld\n", len);
#endif

	/* Send it */
	i = SEND(sock, (char *)ktxt->dat, (int) len, flags,
		   (struct sockaddr *)&s_sock, sizeof(s_sock));
	if (i < 0)
		perror("sending encrypted message");
	printf("Sent encrypted message: %d bytes\n", i);
	return(0);
}
