// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb4.lib;

import java.io.*;

public class Krb4TGSReq {
	public byte pvno;
	public byte msgType;
	boolean littleEndian;
	public byte keyVersion;
	public String srealm;
	public byte[] encTicket;
	public byte[] encAuthenticator;
	public Krb4Ticket ticket;
	public Krb4Authenticator authenticator;
	public long timestamp;
	public long lifetime;
	public String sname;
	public String sinst;
	public byte[] obuf;
	public byte[] ibuf;

	public Krb4TGSReq(
		int new_keyVersion,
		String new_srealm,
		byte[] new_encTicket,
		byte[] new_encAuthenticator,
		long new_timestamp,
		long new_lifetime,
		String new_sname,
		String new_sinst
	) throws Krb4Exception, IOException {
		pvno = (byte)Krb4.KRB_PROT_VERSION;
		msgType = (byte)Krb4.AUTH_MSG_APPL_REQUEST;
		littleEndian = true;
		keyVersion = (byte)new_keyVersion;
		srealm = new_srealm;
		encTicket = new_encTicket;
		encAuthenticator = new_encAuthenticator;
		timestamp = new_timestamp;
		lifetime = new_lifetime;
		sname = new_sname;
		sinst = new_sinst;
		obuf = encode();
	}

	public Krb4TGSReq(
		Krb4Creds creds,
		String cname,
		String cinst,
		String crealm,
		int checksum,
		int new_keyVersion,
		String new_srealm,
		long new_timestamp,
		long new_lifetime,
		String new_sname,
		String new_sinst
	) throws Krb4Exception, IOException {
		pvno = (byte)Krb4.KRB_PROT_VERSION;
		msgType = (byte)Krb4.AUTH_MSG_APPL_REQUEST;
		littleEndian = true;
		keyVersion = (byte)new_keyVersion;
		srealm = new_srealm;
		encTicket = creds.encTicket;
		Krb4Authenticator authenticator = new Krb4Authenticator(
			cname,
			cinst,
			crealm,
			checksum
		);
		encAuthenticator = authenticator.encode(creds.sessionKey);
		timestamp = new_timestamp;
		lifetime = new_lifetime;
		sname = new_sname;
		sinst = new_sinst;
		obuf = encode();
	}

	public Krb4TGSReq(
		Krb4Creds creds,
		String cname,
		String cinst,
		String crealm,
		int checksum,
		String new_sname,
		String new_sinst,
		String new_srealm
	) throws Krb4Exception, IOException {
		pvno = (byte)Krb4.KRB_PROT_VERSION;
		msgType = (byte)Krb4.AUTH_MSG_APPL_REQUEST;
		littleEndian = true;
		keyVersion = (byte)0;
		srealm = new_srealm;
		encTicket = creds.encTicket;
		Krb4Authenticator authenticator = new Krb4Authenticator(
			cname,
			cinst,
			crealm,
			checksum
		);
		encAuthenticator = authenticator.encode(creds.sessionKey);
		timestamp = new java.util.Date().getTime();
		lifetime = Krb4.DEFAULT_TKT_LIFE * 5L * 60L * 1000L;
		sname = new_sname;
		sinst = new_sinst;
		obuf = encode();
	}

	public Krb4TGSReq(
		Krb4Creds creds,
		String cname,
		String cinst,
		String crealm,
		String new_sname,
		String new_sinst,
		String new_srealm
	) throws Krb4Exception, IOException {
		this(
			creds,
			cname,
			cinst,
			crealm,
			0,
			new_sname,
			new_sinst,
			new_srealm
		);
	}

	public byte[] encode() throws Krb4Exception, IOException {
		ByteArrayOutputStream o = new ByteArrayOutputStream();
		o.write(pvno);
		byte temp = (byte)((msgType << 1) +
			(littleEndian ? 1 : 0));
		o.write(temp);
		o.write(keyVersion);
		o.write(Krb4Encode.toBytes(srealm));
		o.write((byte)encTicket.length);
		o.write((byte)encAuthenticator.length);
		o.write(encTicket);
		o.write(encAuthenticator);
		o.write(Krb4Encode.toBytes((int)(timestamp / 1000L)));
		o.write((byte)(lifetime / (1000L * 60L * 5L)));
		o.write(Krb4Encode.toBytes(sname));
		o.write(Krb4Encode.toBytes(sinst));
		return o.toByteArray();
	}

	public int getServerKeyVersion() {
		return (int)keyVersion;
	}

	public void send(String kdc) throws IOException {
		send(kdc, Krb4.KRB_PORT);
	}

	public void send(String kdc, int port) throws IOException {
		UDPClient kdcClient = new UDPClient(kdc, port);
		kdcClient.send(obuf);
		ibuf = kdcClient.receive();
	}

	public Krb4TGSRep getKrb4TGSRep() throws Krb4Exception {
		Krb4TGSRep rep = null;
		try {
			rep = new Krb4TGSRep(ibuf);
		} catch (Krb4Exception e) {
			rep = null;
			if (e.returnCode() == Krb4.RD_AP_MSG_TYPE) {
				Krb4KDCErr err = new Krb4KDCErr(ibuf);
				throw new Krb4Exception(err.error_code);
			}
			else
				throw e;
		}
		return rep;
	}
}
