| /* |
| * Copyright (c) 2000, 2009, 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; |
| 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. KRB5CCNAME |
| * 2. /tmp/krb5cc_<uid> on unix systems |
| * 3. <user.home>/krb5cc_<user.name> |
| * 4. <user.home>/krb5cc (if can't get <user.name>) |
| */ |
| |
| public static String getDefaultCacheName() { |
| |
| String stdCacheNameComponent = "krb5cc"; |
| String name; |
| |
| name = java.security.AccessController.doPrivileged( |
| new java.security.PrivilegedAction<String>() { |
| @Override |
| public String run() { |
| return System.getenv("KRB5CCNAME"); |
| } |
| }); |
| 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<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; |
| } |
| } |