// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb5.lib;

import java.io.*;
import krb5.lib.asn1.*;
import krb5.lib.ccache.*;

/**
 * Kerberos Ticket Granted Service Request
 */
public class KrbTgsReq {

	/**
	 * Principal Name
	 * @see krb5.lib.PrincipalName
	 */
	PrincipalName princName;
	
	/**
	 * Server Name
	 * @see krb5.lib.PrincipalName
	 */
	PrincipalName servName;
	
	/**
	 * Ticket Granted Service Request
	 * @see krb5.lib.TGSReq
	 */
	TGSReq tgs_req;
	
	/**
	 * Output buffer
	 */
	byte[] obuf;
	
	/**
	 * Input buffer
	 */
	byte[] ibuf;
	
	/**
	 * Credentials
	 * @see krb5.lib.Credentials
	 */
	Credentials creds;
	
	/**
	 * Time
	 * @see krb5.lib.KerberosTime
	 */
	KerberosTime _ctime;


	/**
	 * Class constructor
	 *
	 * @param options is of type KDCOptions
	 * @param as_creds is of type Credentials
	 * @param sname is of type PrincipalName
	 * @param from is of type KerberosTime
	 * @param till is of type KerberosTime
	 * @param rtime is of type KerberosTime
	 * @param eTypes is of type int[]
	 * @param addresses is of type HostAddresses
	 * @param authorizationData is of type AuthorizationData
	 * @param additionalTickets is of type Ticket[]
	 * @param subKey is of type EncryptionKey
	 * @exception KrbException an exception
	 * @exception IOException an exception
	 * @see krb5.lib.Credentials
	 * @see krb5.lib.KDCOptions
	 * @see krb5.lib.KerberosTime
     * @see krb5.lib.PrincipalName
     * @see krb5.lib.HostAddress
     * @see krb5.lib.AuthorizationData
     * @see krb5.lib.Ticket
     * @see krb5.lib.EncryptionKey
     * @see krb5.lib.KrbException
     * @see java.io.IOException
	 */
	public KrbTgsReq(
		KDCOptions options,
		Credentials as_creds,
		PrincipalName sname,
		KerberosTime from,
		KerberosTime till,
		KerberosTime rtime,
		int[] eTypes,
		HostAddresses addresses,
		AuthorizationData authorizationData,
		Ticket[] additionalTickets,
		EncryptionKey subKey
	) throws KrbException, IOException {
		princName = as_creds.client();
		servName = sname;
		_ctime = new KerberosTime(KerberosTime.NOW);
		tgs_req = ApiUtil.tgs_req(
			options,
			as_creds.ticket,
			as_creds.key,
			_ctime,
			princName,
			servName.getRealm(),
			servName,
			from,
			till,
			rtime,
			eTypes,
			addresses,
			authorizationData,
			additionalTickets,
			subKey
		);
		obuf = tgs_req.asn1Encode();
	}

	/**
	 * Sends the a string message to a port
	 *
	 * @param kdc is of type String
	 * @param port is of type int
	 * @exception IOException an exception
	 * @see java.lang.String
	 * @see java.io.IOException
	 */
	public void send(String kdc, int port) throws IOException {
		UDPClient kdcClient = new UDPClient(kdc, port);
		kdcClient.send(obuf);
		ibuf = kdcClient.receive();
	}

	/**
	 * Sends a  string message to Krb5.KDC_INET_DEFAULT_PORT
	 *
	 * @param kdc is of type String
	 * @exception IOException an exception
	 * @see java.lang.String
	 * @see java.io.IOException
	 * @see krb5.lib.Krb5
	 */
	public void send(String kdc) throws IOException {
		send(kdc, Krb5.KDC_INET_DEFAULT_PORT);
	}


	/**
	 * This returns kerberos ticket granted service response
	 *
	 * @return KrbTgsRep is a result
	 * @param as_creds is of type Credentials
	 * @exception KrbException an exception
	 * @see krb5.lib.KrbTgsRep
	 * @see krb5.lib.Credentials
	 * @see krb5.lib.KrbException
	 */
	public KrbTgsRep getKrbTgsRep(Credentials as_creds) throws KrbException {
		EncodeRef ref = new EncodeRef(ibuf);
		TGSRep rep = null;
		try {
			rep = new TGSRep(ref);
    	} catch (Asn1Exception e) {
			rep = null;
    		KRBError err = new KRBError(ref);
    		String eText;
    		if (err.eText.charAt(err.eText.length() - 1) == 0)
    		    eText = err.eText.substring(0, err.eText.length() - 1);
    		else
    		    eText = err.eText;
 			throw new KrbException(err.errorCode, eText);
   		}

		byte[] enc_tgs_rep_part =
			rep.encPart.decrypt(as_creds.key);
		ref = new EncodeRef(enc_tgs_rep_part);
		EncTGSRepPart enc_part = new EncTGSRepPart(ref);
		rep.ticket.sname.setRealm(rep.ticket.realm);
		rep.encKDCRepPart = enc_part;

		ApiUtil.krb_as_tgs_rep_common_checks(
			tgs_req,
			rep
		);

		creds = new Credentials(
			rep,
			null,
			null,
			false
		);
		return new KrbTgsRep(ibuf, creds);
	}

	/**
	 * Returns time
	 *
	 * @return KerberosTime is a result
	 * @see krb5.lib.KerberosTime
	 */
	public KerberosTime ctime() {
		return _ctime;
	}

}
