// Copyright 1997 The Open Group Research Institute.  All rights reserved.

//Configurable constants and global state
/**
 * Sets up the configurable constants - site specified.
 */

package krb5.lib;

import java.io.*;
import java.util.*;
import java.applet.*;
import krb5.lib.util.*;
import krb5.lib.ccache.*;
import krb5.lib.rcache.*;

public class Config {
    
	//Site specific values
	/**
	 * PA_ENC_TIMESTAMP_REQUIRED = true
	 */
	public static final boolean PA_ENC_TIMESTAMP_REQUIRED = true;

	/**
	 * AP_EMPTY_ADDRESSES_ALLOWED = true
	 */
	public static final boolean AP_EMPTY_ADDRESSES_ALLOWED = true;

	//Assigned KDC values

	//Currently all are assigned the default values from class krb5

	/**
	 * Allowable clock skew
	 * @see krb5.lib.Krb5
	 */
	public static final int KDC_ALLOWABLE_CLOCKSKEW = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW; //5 minutes
	/**
	 * Mininum lifetime
	 * @see krb5.lib.Krb5
	 */
	public static final int KDC_MINIMUM_LIFETIME = Krb5.DEFAULT_MINIMUM_LIFETIME; //5 minutes
	/**
	 * Maximum renewable lifetime
	 * @see krb5.lib.Krb5
	 */
	public static final int KDC_MAXIMUM_RENEWABLE_LIFETIME = Krb5.DEFAULT_MAXIMUM_RENEWABLE_LIFETIME; //1 week
	/**
	 * Maximum ticket lifetime
	 * @see krb5.lib.Krb5
	 */
	public static final int KDC_MAXIMUM_TICKET_LIFETIME = Krb5.DEFAULT_MAXIMUM_TICKET_LIFETIME; //1 day
	/**
	 * Whether an empty address is allowed 
	 * @see krb5.lib.Krb5
	 */
	public static final boolean KDC_EMPTY_ADDRESSES_ALLOWED = Krb5.DEFAULT_EMPTY_ADDRESSES_ALLOWED; //false
	/**
	 * Whether forwarding is allowed
	 * @see krb5.lib.Krb5
	 */
	public static final boolean KDC_FORWARDABLE_ALLOWED = Krb5.DEFAULT_FORWARDABLE_ALLOWED; //true
	/**
	 * Whether to allow proxy
	 * @see krb5.lib.Krb5
	 */
	public static final boolean KDC_PROXIABLE_ALLOWED = Krb5.DEFAULT_PROXIABLE_ALLOWED; //true
	/**
	 * Whether to allow postdated credentials
	 * @see krb5.lib.Krb5
	 */
	public static final boolean KDC_POSTDATE_ALLOWED = Krb5.DEFAULT_POSTDATE_ALLOWED; //true
	/**
	 * Whether to allow renewable credentials
	 * @see krb5.lib.Krb5
	 */
	public static final boolean KDC_RENEWABLE_ALLOWED = Krb5.DEFAULT_RENEWABLE_ALLOWED; //true

	//Defaults

	/**
	 * Default encryption type
	 * @see krb5.lib.Krb5
	 */
	public static final int ETYPE_DEFAULT = Krb5.ETYPE_DES_CBC_CRC;
	/**
	 * Default checksum type 
	 * @see krb5.lib.Krb5
	 */	
	public static final int CKSUMTYPE_DEFAULT = Krb5.CKSUMTYPE_RSA_MD4;
	/**
	 * Default safe checksum type
	 * @see krb5.lib.Krb5
	 */	
	public static final int SAFECKSUMTYPE_DEFAULT = Krb5.CKSUMTYPE_RSA_MD4_DES;
	/**
	 * Default key type
	 * @see krb5.lib.Krb5
	 */	
	public static final int KEYTYPE_DEFAULT = Krb5.KEYTYPE_DES;
	/**
	 * Default keytab version number
	 * @see krb5.lib.Krb5
	 */	
	public static final int KT_VNO_DEFAULT = Krb5.KT_VNO_2;

	/**
	 * Default encryption type list 
	 * @see krb5.lib.Krb5
	 */		
	public static final int[] ETYPE_LIST_DEFAULT = {
	    //XXX commented out for interop testing
        //Krb5.ETYPE_DES_CBC_MD5,
		Krb5.ETYPE_DES_CBC_CRC
	};

	//Debugging, tracing, and logging (all in one for now)

	/**
	 * Debug or not
	 */
	public static final boolean debug = true;

	//Paths
	/**
	 * Default path to the configuration file
	 */
	public static final String KRB_CONF_PATH = "C:\\cygnus\\kerbnet\\etc"; //XXX should reference a default
	/**
	 * Default configuration file name
	 */
	public static final String KRB_CONF_FILE = "krb5.conf"; //XXX should reference a default

	/**
	 * Default path to the log file
	 */	   	                                                        //XXX might break on DOS
	public static final String KRB_LOG_PATH = "C:\\cygnus\\kerbnet\\etc"; //XXX should reference a default
	/**
	 * Default log file name
	 */	
	public static final String KRB_LOG_FILE = "krb5.log";	//XXX should reference a default

    //global KDC parameters
    
	/**
	 * Default realm
	 */
    public static String DEFAULT_REALM = null;

	/**
	 * Host name
	 */
    public static String KDC_HOST_NAME = null;
    static {
        try {
            KrbConfFile conf = new KrbConfFile(KRB_CONF_PATH +
                System.getProperty("file.separator") +
                KRB_CONF_FILE);
            conf.parse();
	        String realm = conf.getValue("libdefaults", "default_realm");
	        if (realm != null) {
	            setDefaultRealm(realm);
	            Hashtable realmSection = conf.getSubsection("realms", realm);
	            String kdc = conf.getValue(realmSection, "kdc");
	            if (kdc != null)
	                setKDCHostName(kdc);
	        }
        } catch (KrbException e) {}
    }
    
	/**
	 * Sets the default realm
     * @param realm is of type String
	 */
    public static void setDefaultRealm(String realm) {
        DEFAULT_REALM = realm;
    }
    
	/**
	 * Sets KDC host name
	 * @param name is of type String
	 */
    public static void setKDCHostName(String name) {
        KDC_HOST_NAME = name;
    }
    
    //replay cache instance

	/**
	 * Replay cache
	 */
    public static ReplayCache replayCache = new ReplayCacheImpl();
    
    //CCache parameters
    
    //General ccache behavior:
    
    //Applets should default to using the memory ccache impl in the absence of other
    //config data
    
    //Applications should default to using the pure java file ccache impl in the
    //absence of the environment string value for KRB5CCNAME
    
    //set in call to getCCacheTypeDefault()
	/**
	 * Get credentials cache name via environment
	 */
    public static boolean getCCacheNameViaEnv;

    /**
	 * Credentials cache environment variable
	 */
    public static String KRB5CCNAME_ENVIRONMENT_VARIABLE = "KRB5CCNAME";

	/**
	 * Credentials cache suffix
	 */
    public static String DEFAULT_FILE_CCACHE_SUFFIX = ".ccache";  //XXX might break on DOS

	/**
	 * Memory credentials cache name 
	 */
    public static String DEFAULT_MEM_CCACHE_NAME = "CCACHE";

	/**
	 * Native credentials cache name 
	 */
    public static String DEFAULT_NATIVE_CCACHE_NAME = "CCACHE";

    /**
	 * Credentials cache type - memory
	 */
    public static final int KRB_CCACHE_TYPE_MEM     = 0;

    /**
	 * Credentials cache type - file
	 */
    public static final int KRB_CCACHE_TYPE_FILE    = 1;
    
    /**
	 * Credentials cache type - native
	 */
    public static final int KRB_CCACHE_TYPE_NATIVE  = 2;
    
    /**
	 * Default credentials cache type
	 */    
    public static final int KRB_CCACHE_TYPE_DEFAULT = getCCacheTypeDefault();
    
    //sets getCCacheNameViaEnv as a side-effect
    /**
     * Gets default credentials cache type
     * @return int is a result
     */
    static int getCCacheTypeDefault() {
        //detect whether we are an applet or application here
        if (SysUtil.isApplet()) {
            getCCacheNameViaEnv = false;
            return KRB_CCACHE_TYPE_MEM;
        }
        getCCacheNameViaEnv = true;
        return KRB_CCACHE_TYPE_FILE;
    }
    
    /**
     * credentials cache name prefix map
     */
    public static Dictionary ccacheNamePrefixMap = new Hashtable();
    static {
        ccacheNamePrefixMap.put(new Integer(KRB_CCACHE_TYPE_MEM), "MEM");
        ccacheNamePrefixMap.put(new Integer(KRB_CCACHE_TYPE_FILE), "FILE");
        ccacheNamePrefixMap.put(new Integer(KRB_CCACHE_TYPE_NATIVE), "NATIVE");
    }
    
    /**
     * Credentials cache class name implementation map
     */
    public static Dictionary ccacheImplClassNameMap = new Hashtable();
    static {
        ccacheImplClassNameMap.put(new Integer(KRB_CCACHE_TYPE_MEM), "VmCCacheImpl");
        ccacheImplClassNameMap.put(new Integer(KRB_CCACHE_TYPE_FILE), "FileCCacheImpl");
        ccacheImplClassNameMap.put(new Integer(KRB_CCACHE_TYPE_NATIVE), "NativeCCacheImpl");
    }
    
    /**
     * Returns credentials cache
     * @return CredentialsCache is a result
     * @exception KrbException an exception
     * @see krb5.lib.KrbException
     * @see krb5.lib.ccache.CredentialsCache
     */
	public static CredentialsCache getCredentialsCache() throws KrbException {
	    return getCredentialsCache(null);
	}
	
	/**
     * Returns credentials cache for a given name
     * @return CredentialsCache is a result
     * @param name is of type String
     * @exception KrbException an exception
     * @see krb5.lib.KrbException
     * @see krb5.lib.ccache.CredentialsCache
     */
	public static CredentialsCache getCredentialsCache(String name) throws KrbException {
	    if (name == null || name.length() == 0)
	        name = getDefaultCredentialsCacheName();
	    //assume KRB_CCACHE_TYPE_FILE type if unspecified (possible with env var string)
	    if (name.indexOf(':') == -1)
	        name = (String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_FILE)) +
	            ":" + name;
	    CredentialsCache ccache = null;
	    try {
            CCacheFactory ccacheFactory = CCacheFactory.getFactory();
	        if (name.startsWith((String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_FILE)) + ":")) {
                ccache = ccacheFactory.newCCacheInstance(
                    (String)ccacheImplClassNameMap.get(new Integer(KRB_CCACHE_TYPE_FILE)),
                    name.substring(5)
                );
	        }
	        if (name.startsWith((String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_MEM)) + ":")) {
                ccache = ccacheFactory.newCCacheInstance(
                    (String)ccacheImplClassNameMap.get(new Integer(KRB_CCACHE_TYPE_FILE)),
                    name.substring(4)
                );
	        }
	    } catch (Exception e) {}
	    if (ccache == null)
	        throw new KrbException(Krb5.CCACHE_NOT_FOUND);
	    return ccache;
	}

	/**
     * Returns default credentials cache name
     * @return String is a result
     * @exception KrbException an exception
     * @see krb5.lib.KrbException
     */
	public static String getDefaultCredentialsCacheName() throws KrbException {
	    if (getCCacheNameViaEnv) {
	        String result = SysUtil.getenv(KRB5CCNAME_ENVIRONMENT_VARIABLE);
	        if (result.length() > 0)
	            return result;
	    }
	    if (KRB_CCACHE_TYPE_DEFAULT == KRB_CCACHE_TYPE_MEM)
	        return (String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_MEM)) + ":" +
	             DEFAULT_MEM_CCACHE_NAME;
	    if (KRB_CCACHE_TYPE_DEFAULT == KRB_CCACHE_TYPE_FILE) {
	        String home = System.getProperty("user.home");
	        if (!home.endsWith(System.getProperty("file.separator")))
	            home += System.getProperty("file.separator");
	        return (String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_FILE)) + ":" +
	            //XXX assumes user name contains valid file name chars
	            home + System.getProperty("user.name") + DEFAULT_FILE_CCACHE_SUFFIX;
	    }
	    if (KRB_CCACHE_TYPE_DEFAULT == KRB_CCACHE_TYPE_NATIVE)
	        return (String)ccacheNamePrefixMap.get(new Integer(KRB_CCACHE_TYPE_NATIVE)) + ":" +
	              DEFAULT_NATIVE_CCACHE_NAME;
	    throw new KrbException(Krb5.CCACHE_INVALID_TYPE);
	}
	
	//XXX eventually this will be a constructor for Config
	/**
     * Sets the applet context
     * @param ctx is of type AppletContext 
     * @see java.applet.AppletContext
     */	
	public static void setAppletContext(AppletContext ctx) {
	    SysUtil.setAppletContext(ctx);
	}
}