// Copyright 1999 Memesoft.  All rights reserved.

package krb5.lib.util;

import java.io.*;
import krb5.lib.Krb5;
import krb5.lib.KrbException;
import krb5.lib.PrincipalName;
import krb5.lib.EncryptionKey;

/*
 * entry layout:
 * name_components_count: u_short (KRB5_KT_VNO_2: net-order, realm not in count; KRB5_KT_VNO_1: host-order, realm in count)
 * name_components: realm first, then rest in most-distinguishing-to-least order
 * component:
 * component_length: u_short (KRB5_KT_VNO_2: net-order; KRB5_KT_VNO_1: host-order)
 * bytes: u_char[component_length] (non-null terminated)
 * principal_type: u_long net-order (KRB5_KT_VNO_2 only) (see definition below; really name type)
 * timestamp: u_long (KRB5_KT_VNO_2: net-order; KRB5_KT_VNO_1: host-order) (C-time() format)
 * key_vno: u_char
 * enc_type: u_short (KRB5_KT_VNO_2: net-order; KRB5_KT_VNO_1: host-order)
 * key_block:
 * key_length: u_short (KRB5_KT_VNO_2: net-order; KRB5_KT_VNO_1: host-order)
 * bytes: u_char[key_length]
 */
/** 
 * Key tab entry
 */
public class KeytabEntry {

	/**
	 * Realm
	 */
    String realm;

	/**
	 * List of components
	 */
    String components[];

	/**
	 * Principal type
	 */
    int princ_type;

	/**
	 * Timestamp
	 */
    public int timestamp;

	/**
	 * Key version
	 */
    int key_vno;

	/**
	 * Encryption type
	 */
    int enc_type;

	/**
	 * List of key
	 */
    byte key[];

	/**
	 * Keytab version
	 */
    int kt_vno;

	/**
	 * Principal name
	 */
    public PrincipalName princName;

	/**
	 * Encryption key
	 */
    public EncryptionKey encKey;

	/**
	 * Class constructor
	 *
	 * @param _kt_vno is of type int
	 * @param buf is of type byte[]
	 * @exception KrbException an exception
	 * @see krb5.lib.KrbException
	 */
    public KeytabEntry(int _kt_vno, byte buf[]) throws KrbException {
        kt_vno = _kt_vno;
	    try {
	        FileBuf fb = new FileBuf(buf);
	        int count = toShort(fb.getShort());
	        if (kt_vno == Krb5.KT_VNO_1)
	            --count;
	        int len = toShort(fb.getShort());
	        realm = fb.getString(len);
	        components = new String[count];
	        int i = 0;
	        while(i < count) {
	            len = toShort(fb.getShort());
                components[i] = fb.getString(len);
	            ++i;
	        }
	        princ_type = toInt(fb.getInt());
	        timestamp = toInt(fb.getInt());
	        key_vno = fb.getByte();
	        enc_type = toShort(fb.getShort());
	        len = toShort(fb.getShort());
	        key = fb.getBytes(len);
	    } catch (IOException e) {
	        throw new KrbException(Krb5.KT_FILE_CORRUPT);
	    }
	    princName = new PrincipalName(components, realm, princ_type);
	    encKey = new EncryptionKey(key, new Integer(enc_type), new Integer(key_vno));
	}

	/**
	 * Print
	 */
	public void print() {
	    System.out.print("name: ");
	    int i = 0;
	    while (i < components.length) {
	        if (i > 0)
    	        System.out.print("/");
	        System.out.print(components[i]);
	        ++i;
	    }
	    System.out.println("@" + realm);
	    System.out.println("princ_type: " + princ_type);
	    System.out.println("timestamp: " + timestamp);
	    System.out.println("key_vno: " + key_vno);
	    System.out.println("enc_type: " + enc_type);
	    System.out.print("key:");
	    i = 0;
	    while (i < key.length) {
	        String s = Integer.toHexString(key[i] & 0x0ff);
	        if (s.length() == 1)
	            System.out.print(" 0" + s);
	        else
	            System.out.print(" " + s);
	        ++i;
	    }
	    System.out.println();
	}

	/**
	 * Converts to short
	 *
	 * @return int is a result
	 * @param s is of type short
	 */
	int toShort(short s) {
        return kt_vno == Krb5.KT_VNO_2 ? s : SysUtil.htons(s);
	}

	/**
	 * Converts to int
	 *
	 * @return int is a result
	 * @param s is of type int
	 */
	int toInt(int s) {
	    return kt_vno == Krb5.KT_VNO_2 ? s : SysUtil.htonl(s);
	}
}