/* * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ /* * =========================================================================== * (C) Copyright IBM Corp. 1999 All Rights Reserved. * * Copyright 1997 The Open Group Research Institute. All rights reserved. * =========================================================================== * */ package sun.security.krb5.internal.ccache; import sun.security.krb5.*; import sun.security.krb5.internal.*; import java.util.StringTokenizer; import java.util.Vector; import java.io.IOException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.*; /** * CredentialsCache stores credentials(tickets, session keys, etc) in a * semi-permanent store * for later use by different program. * * @author Yanni Zhang * @author Ram Marti */ public class FileCredentialsCache extends CredentialsCache implements FileCCacheConstants { public int version; public Tag tag; // optional public PrincipalName primaryPrincipal; public Realm primaryRealm; private Vector<Credentials> credentialsList; private static String dir; private static boolean DEBUG = Krb5.DEBUG; public static synchronized FileCredentialsCache acquireInstance( PrincipalName principal, String cache) { try { FileCredentialsCache fcc = new FileCredentialsCache(); if (cache == null) { cacheName = fcc.getDefaultCacheName(); } else { cacheName = fcc.checkValidation(cache); } if ((cacheName == null) || !(new File(cacheName)).exists()) { // invalid cache name or the file doesn't exist return null; } if (principal != null) { fcc.primaryPrincipal = principal; fcc.primaryRealm = principal.getRealm(); } fcc.load(cacheName); return fcc; } catch (IOException e) { // we don't handle it now, instead we return a null at the end. if (DEBUG) { e.printStackTrace(); } } catch (KrbException e) { // we don't handle it now, instead we return a null at the end. if (DEBUG) { e.printStackTrace(); } } return null; } public static FileCredentialsCache acquireInstance() { return acquireInstance(null, null); } static synchronized FileCredentialsCache New(PrincipalName principal, String name) { try { FileCredentialsCache fcc = new FileCredentialsCache(); cacheName = fcc.checkValidation(name); if (cacheName == null) { // invalid cache name or the file doesn't exist return null; } fcc.init(principal, cacheName); return fcc; } catch (IOException e) { } catch (KrbException e) { } return null; } static synchronized FileCredentialsCache New(PrincipalName principal) { try { FileCredentialsCache fcc = new FileCredentialsCache(); cacheName = fcc.getDefaultCacheName(); fcc.init(principal, cacheName); return fcc; } catch (IOException e) { if (DEBUG) { e.printStackTrace(); } } catch (KrbException e) { if (DEBUG) { e.printStackTrace(); } } return null; } private FileCredentialsCache() { } boolean exists(String cache) { File file = new File(cache); if (file.exists()) { return true; } else return false; } synchronized void init(PrincipalName principal, String name) throws IOException, KrbException { primaryPrincipal = principal; primaryRealm = principal.getRealm(); CCacheOutputStream cos = new CCacheOutputStream(new FileOutputStream(name)); version = KRB5_FCC_FVNO_3; cos.writeHeader(primaryPrincipal, version); cos.close(); load(name); } synchronized void load(String name) throws IOException, KrbException { PrincipalName p; CCacheInputStream cis = new CCacheInputStream(new FileInputStream(name)); version = cis.readVersion(); if (version == KRB5_FCC_FVNO_4) { tag = cis.readTag(); } else { tag = null; if (version == KRB5_FCC_FVNO_1 || version == KRB5_FCC_FVNO_2) { cis.setNativeByteOrder(); } } p = cis.readPrincipal(version); if (primaryPrincipal != null) { if (!(primaryPrincipal.match(p))) { throw new IOException("Primary principals don't match."); } } else primaryPrincipal = p; primaryRealm = primaryPrincipal.getRealm(); credentialsList = new Vector<Credentials> (); while (cis.available() > 0) { credentialsList.addElement(cis.readCred(version)); } cis.close(); } /** * Updates the credentials list. If the specified credentials for the * service is new, add it to the list. If there is an entry in the list, * replace the old credentials with the new one. * @param c the credentials. */ public synchronized void update(Credentials c) { if (credentialsList != null) { if (credentialsList.isEmpty()) { credentialsList.addElement(c); } else { Credentials tmp = null; boolean matched = false; for (int i = 0; i < credentialsList.size(); i++) { tmp = credentialsList.elementAt(i); if (match(c.sname.getNameStrings(), tmp.sname.getNameStrings()) && ((c.sname.getRealmString()).equalsIgnoreCase( tmp.sname.getRealmString()))) { matched = true; if (c.endtime.getTime() >= tmp.endtime.getTime()) { if (DEBUG) { System.out.println(" >>> FileCredentialsCache " + "Ticket matched, overwrite " + "the old one."); } credentialsList.removeElementAt(i); credentialsList.addElement(c); } } } if (matched == false) { if (DEBUG) { System.out.println(" >>> FileCredentialsCache Ticket " + "not exactly matched, " + "add new one into cache."); } credentialsList.addElement(c); } } } } public synchronized PrincipalName getPrimaryPrincipal() { return primaryPrincipal; } /** * Saves the credentials cache file to the disk. */ public synchronized void save() throws IOException, Asn1Exception { CCacheOutputStream cos = new CCacheOutputStream(new FileOutputStream(cacheName)); cos.writeHeader(primaryPrincipal, version); Credentials[] tmp = null; if ((tmp = getCredsList()) != null) { for (int i = 0; i < tmp.length; i++) { cos.addCreds(tmp[i]); } } cos.close(); } boolean match(String[] s1, String[] s2) { if (s1.length != s2.length) { return false; } else { for (int i = 0; i < s1.length; i++) { if (!(s1[i].equalsIgnoreCase(s2[i]))) { return false; } } } return true; } /** * Returns the list of credentials entries in the cache file. */ public synchronized Credentials[] getCredsList() { if ((credentialsList == null) || (credentialsList.isEmpty())) { return null; } else { Credentials[] tmp = new Credentials[credentialsList.size()]; for (int i = 0; i < credentialsList.size(); i++) { tmp[i] = credentialsList.elementAt(i); } return tmp; } } public Credentials getCreds(LoginOptions options, PrincipalName sname, Realm srealm) { if (options == null) { return getCreds(sname, srealm); } else { Credentials[] list = getCredsList(); if (list == null) { return null; } else { for (int i = 0; i < list.length; i++) { if (sname.match(list[i].sname) && (srealm.toString().equals(list[i].srealm.toString()))) { if (list[i].flags.match(options)) { return list[i]; } } } } return null; } } /** * Gets a credentials for a specified service. * @param sname service principal name. * @param srealm the realm that the service belongs to. */ public Credentials getCreds(PrincipalName sname, Realm srealm) { Credentials[] list = getCredsList(); if (list == null) { return null; } else { for (int i = 0; i < list.length; i++) { if (sname.match(list[i].sname) && (srealm.toString().equals(list[i].srealm.toString()))) { return list[i]; } } } return null; } public Credentials getDefaultCreds() { Credentials[] list = getCredsList(); if (list == null) { return null; } else { for (int i = list.length-1; i >= 0; i--) { if (list[i].sname.toString().startsWith("krbtgt")) { String[] nameStrings = list[i].sname.getNameStrings(); // find the TGT for the current realm krbtgt/realm@realm if (nameStrings[1].equals(list[i].srealm.toString())) { return list[i]; } } } } return null; } /* * Returns path name of the credentials cache file. * The path name is searched in the following order: * * 1. /tmp/krb5cc_<uid> on unix systems * 2. <user.home>/krb5cc_<user.name> * 3. <user.home>/krb5cc (if can't get <user.name>) */ public static String getDefaultCacheName() { String stdCacheNameComponent = "krb5cc"; String name; // get cache name from system.property String osname = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("os.name")); /* * For Unix platforms we use the default cache name to be * /tmp/krbcc_uid ; for all other platforms we use * {user_home}/krb5_cc{user_name} * Please note that for Windows 2K we will use LSA to get * the TGT from the the default cache even before we come here; * however when we create cache we will create a cache under * {user_home}/krb5_cc{user_name} for non-Unix platforms including * Windows 2K. */ if (osname != null) { String cmd = null; String uidStr = null; long uid = 0; if (osname.startsWith("SunOS") || (osname.startsWith("Linux"))) { try { Class<?> c = Class.forName ("com.sun.security.auth.module.UnixSystem"); Constructor<?> constructor = c.getConstructor(); Object obj = constructor.newInstance(); Method method = c.getMethod("getUid"); uid = ((Long)method.invoke(obj)).longValue(); name = File.separator + "tmp" + File.separator + stdCacheNameComponent + "_" + uid; if (DEBUG) { System.out.println(">>>KinitOptions cache name is " + name); } return name; } catch (Exception e) { if (DEBUG) { System.out.println("Exception in obtaining uid " + "for Unix platforms " + "Using user's home directory"); e.printStackTrace(); } } } } // we did not get the uid; String user_name = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("user.name")); String user_home = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("user.home")); if (user_home == null) { user_home = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("user.dir")); } if (user_name != null) { name = user_home + File.separator + stdCacheNameComponent + "_" + user_name; } else { name = user_home + File.separator + stdCacheNameComponent; } if (DEBUG) { System.out.println(">>>KinitOptions cache name is " + name); } return name; } public static String checkValidation(String name) { String fullname = null; if (name == null) { return null; } try { // get full path name fullname = (new File(name)).getCanonicalPath(); File fCheck = new File(fullname); if (!(fCheck.exists())) { // get absolute directory File temp = new File(fCheck.getParent()); // test if the directory exists if (!(temp.isDirectory())) fullname = null; temp = null; } fCheck = null; } catch (IOException e) { fullname = null; // invalid name } return fullname; } private static String exec(String c) { StringTokenizer st = new StringTokenizer(c); Vector<String> v = new Vector<String> (); while (st.hasMoreTokens()) { v.addElement(st.nextToken()); } final String[] command = new String[v.size()]; v.copyInto(command); try { Process p = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction<Process> () { public Process run() { try { return (Runtime.getRuntime().exec(command)); } catch (java.io.IOException e) { if (DEBUG) { e.printStackTrace(); } return null; } } }); if (p == null) { // exception occured in execing the command return null; } BufferedReader commandResult = new BufferedReader (new InputStreamReader(p.getInputStream(), "8859_1")); String s1 = null; if ((command.length == 1) && (command[0].equals("/usr/bin/env"))) { while ((s1 = commandResult.readLine()) != null) { if (s1.length() >= 11) { if ((s1.substring(0, 11)).equalsIgnoreCase ("KRB5CCNAME=")) { s1 = s1.substring(11); break; } } } } else s1 = commandResult.readLine(); commandResult.close(); return s1; } catch (Exception e) { if (DEBUG) { e.printStackTrace(); } } return null; } }