/*
 *   Copyright ©1997 by the Massachusetts Institute of Technology
 *   All rights reserved.
 */

/* Warning: this is a hack!
 * This file contains functions that are supposed to look like kerberos calls, feel like 
 * kerberos calls, but they actually make some really gross assumptions. They work for
 * CVS, and they make some assumptions about the way they are called from CVS.
 * Details below.
 */
 
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#if defined (HAVE_KERBEROS) && defined (USE_KCLIENT)

#include "kclient_if.h"

char errorStr [64];

KClientSessionInfo KSession;

/*
 * This does -not- work in the same way krb_sendauth is supposed to work on any other
 * platform.
 * - The only option it understands is KOPT_DO_MUTUAL. It ignores all other options.
 * - It pays no attention to ticket. It will never return the ticket to the caller
 *      (in the case of CVS, the ticket doesn't matter anyways.)
 * - It ignores msg_data. CVS ignores it as well.
 * - It ignores credentials. So does CVS.
 */
 
int
krb_sendauth (
	long options,
	int fd,
	KTEXT ticket,
	char *service,
	char *inst,
	char *realm,
	u_long checksum,
	MSG_DAT *msg_data, 
	CREDENTIALS *cred,
	Key_schedule schedule, 
	struct sockaddr_in *laddr,
	struct sockaddr_in *faddr, 
	char *version)
     /* options: bit-pattern of options */
     /* fd: file descriptor to write onto */
     /* ticket: where to put ticket (return); or supplied in case of KOPT_DONT_MK_REQ */
     /* service, inst, realm: service name, instance, realm */
     /* checksum: checksum to include in request */
     /* msg_data: mutual auth MSG_DAT (return) */
     /* cred: credentials (return) */
     /* schedule: key schedule (return) */
     /* laddr: local address */
     /* faddr: address of foreign host on fd */
     /* version: version string */
{
#pragma unused (ticket)
#pragma unused (msg_data)
#pragma unused (cred)
#pragma unused (schedule)

	OSErr err = noErr;
	char KService [SNAME_SZ + INST_SZ + 2];
	char KBuf [BUFSIZ]; 
	unsigned long KBuflen = BUFSIZ;
	long KChecksum = checksum;
	char* KVersion = version;

	err = KClientInitSession (&KSession, laddr -> sin_addr.s_addr, laddr -> sin_port, faddr -> sin_addr.s_addr, faddr -> sin_port);
	
	if (err != noErr)
		return err; 
	
	err = KClientSetLocalRealm (realm);
	
	if (err != noErr)
		return err; 

	/* Truncate inst at the first period */
	inst [strcspn (inst, ".")] = '\0';
	
	sprintf (KService, "%s.%s", service, inst);

	err = KClientMakeSendAuth (&KSession, KService, KBuf, &KBuflen, KChecksum, KVersion);

	if (err != noErr)
		return err;

	if (write (fd, KBuf, KBuflen) != KBuflen)
		return KFAILURE;

	if (options & KOPT_DO_MUTUAL)
	{
		unsigned long bytesRead = 0;
/* first read the size of the data blob */
	
		if (read (fd, KBuf, sizeof (KBuflen)) != sizeof (KBuflen))
			return KFAILURE;
			
/* then read the data */
		KBuflen = *(unsigned long*) KBuf;		
		
		while (bytesRead < KBuflen)
		{
			unsigned long chunkRead = read (fd, KBuf + bytesRead + sizeof (KBuflen), KBuflen - bytesRead);
			if (chunkRead < 0)
				return KFAILURE;
			bytesRead += chunkRead;
		}

		err = KClientVerifySendAuth (&KSession, KBuf, &KBuflen);
		if (err != noErr)
			return err;
	}
	
	return KSUCCESS;
}

char*
krb_realmofhost (
	char *host)
{
	char*	realm = malloc (REALM_SZ);
	KClientGetRealm (host, realm);
	return realm;
}

char*
krb_get_err_text (
	int status)
{
	KClientErrorText (status, errorStr);
	return errorStr;
}

#endif /* HAVE_KERBEROS && USE_KCLIENT */
