diff -r 836adbf7a2cd -r 3317bb8137f4 jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ccache/FileCredentialsCache.java Sun Aug 17 15:54:13 2014 +0100 @@ -0,0 +1,545 @@ +/* + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.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; + private Vector 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 = FileCredentialsCache.getDefaultCacheName(); + } else { + cacheName = FileCredentialsCache.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.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 = FileCredentialsCache.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 = FileCredentialsCache.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; + 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; + credentialsList = new Vector (); + while (cis.available() > 0) { + Credentials cred = cis.readCred(version); + if (cred != null) { + credentialsList.addElement(cred); + } + } + 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) { + if (options == null) { + return getCreds(sname); + } else { + Credentials[] list = getCredsList(); + if (list == null) { + return null; + } else { + for (int i = 0; i < list.length; i++) { + if (sname.match(list[i].sname)) { + if (list[i].flags.match(options)) { + return list[i]; + } + } + } + } + return null; + } + } + + + /** + * Gets a credentials for a specified service. + * @param sname service principal name. + */ + public Credentials getCreds(PrincipalName sname) { + Credentials[] list = getCredsList(); + if (list == null) { + return null; + } else { + for (int i = 0; i < list.length; i++) { + if (sname.match(list[i].sname)) { + 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].sname.getRealm().toString())) { + return list[i]; + } + } + } + } + return null; + } + + /* + * Returns path name of the credentials cache file. + * The path name is searched in the following order: + * + * 1. KRB5CCNAME (bare file name without FILE:) + * 2. /tmp/krb5cc_ on unix systems + * 3. /krb5cc_ + * 4. /krb5cc (if can't get ) + */ + + public static String getDefaultCacheName() { + + String stdCacheNameComponent = "krb5cc"; + String name; + + // The env var can start with TYPE:, we only support FILE: here. + // http://docs.oracle.com/cd/E19082-01/819-2252/6n4i8rtr3/index.html + name = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + @Override + public String run() { + String cache = System.getenv("KRB5CCNAME"); + if (cache != null && + (cache.length() >= 5) && + cache.regionMatches(true, 0, "FILE:", 0, 5)) { + cache = cache.substring(5); + } + return cache; + } + }); + if (name != null) { + if (DEBUG) { + System.out.println(">>>KinitOptions cache name is " + name); + } + return 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 v = new Vector<>(); + 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 () { + public Process run() { + try { + return (Runtime.getRuntime().exec(command)); + } catch (java.io.IOException e) { + if (DEBUG) { + e.printStackTrace(); + } + return null; + } + } + }); + if (p == null) { + // exception occurred during executing 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; + } +}