1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 28 * Copyright 1997 The Open Group Research Institute. All rights reserved. 29 */ 30 31 package sun.security.krb5.internal.tools; 32 33 import sun.security.krb5.*; 34 import sun.security.krb5.internal.*; 35 import sun.security.krb5.internal.ccache.*; 36 import java.io.IOException; 37 import java.time.Instant; 38 import java.io.FileInputStream; 39 40 /** 41 * Maintains user-specific options or default settings when the user requests 42 * a KDC ticket using Kinit. 43 * 44 * @author Yanni Zhang 45 * @author Ram Marti 46 */ 47 class KinitOptions { 48 49 // 1. acquire, 2. renew, 3. validate 50 public int action = 1; 51 52 // forwardable and proxiable flags have two states: 53 // -1 - flag set to be not forwardable or proxiable; 54 // 1 - flag set to be forwardable or proxiable. 55 public short forwardable = 0; 56 public short proxiable = 0; 57 public KerberosTime lifetime; 58 public KerberosTime renewable_lifetime; 59 public String target_service; 60 public String keytab_file; 61 public String cachename; 62 private PrincipalName principal; 63 public String realm; 64 char[] password = null; 65 public boolean keytab; 66 private boolean DEBUG = Krb5.DEBUG; 67 private boolean includeAddresses = true; // default. 68 private boolean useKeytab = false; // default = false. 69 private String ktabName; // keytab file name 70 71 public KinitOptions() throws RuntimeException, RealmException { 72 // no args were specified in the command line; 73 // use default values 74 cachename = FileCredentialsCache.getDefaultCacheName(); 75 if (cachename == null) { 76 throw new RuntimeException("default cache name error"); 77 } 78 principal = getDefaultPrincipal(); 79 } 80 81 public void setKDCRealm(String r) throws RealmException { 82 realm = r; 83 } 84 85 public String getKDCRealm() { 86 if (realm == null) { 87 if (principal != null) { 88 return principal.getRealmString(); 89 } 90 } 91 return null; 92 } 93 94 public KinitOptions(String[] args) 95 throws KrbException, RuntimeException, IOException { 96 // currently we provide support for -f -p -c principal options 97 String p = null; // store principal 98 99 for (int i = 0; i < args.length; i++) { 100 if (args[i].equals("-f")) { 101 forwardable = 1; 102 } else if (args[i].equals("-p")) { 103 proxiable = 1; 104 } else if (args[i].equals("-c")) { 105 106 if (args[i + 1].startsWith("-")) { 107 throw new IllegalArgumentException("input format " + 108 " not correct: " + 109 " -c option " + 110 "must be followed " + 111 "by the cache name"); 112 } 113 cachename = args[++i]; 114 if ((cachename.length() >= 5) && 115 cachename.substring(0, 5).equalsIgnoreCase("FILE:")) { 116 cachename = cachename.substring(5); 117 }; 118 } else if (args[i].equals("-A")) { 119 includeAddresses = false; 120 } else if (args[i].equals("-k")) { 121 useKeytab = true; 122 } else if (args[i].equals("-t")) { 123 if (ktabName != null) { 124 throw new IllegalArgumentException 125 ("-t option/keytab file name repeated"); 126 } else if (i + 1 < args.length) { 127 ktabName = args[++i]; 128 } else { 129 throw new IllegalArgumentException 130 ("-t option requires keytab file name"); 131 } 132 133 useKeytab = true; 134 } else if (args[i].equals("-R")) { 135 action = 2; 136 } else if (args[i].equals("-l")) { 137 lifetime = getTime(Config.duration(args[++i])); 138 } else if (args[i].equals("-r")) { 139 renewable_lifetime = getTime(Config.duration(args[++i])); 140 } else if (args[i].equalsIgnoreCase("-?") || 141 args[i].equalsIgnoreCase("-h") || 142 args[i].equalsIgnoreCase("--help") || 143 // -help: legacy. 144 args[i].equalsIgnoreCase("-help")) { 145 printHelp(); 146 System.exit(0); 147 } else if (p == null) { // Haven't yet processed a "principal" 148 p = args[i]; 149 try { 150 principal = new PrincipalName(p); 151 } catch (Exception e) { 152 throw new IllegalArgumentException("invalid " + 153 "Principal name: " + p + 154 e.getMessage()); 155 } 156 } else if (this.password == null) { 157 // Have already processed a Principal, this must be a password 158 password = args[i].toCharArray(); 159 } else { 160 throw new IllegalArgumentException("too many parameters"); 161 } 162 } 163 // we should get cache name before getting the default principal name 164 if (cachename == null) { 165 cachename = FileCredentialsCache.getDefaultCacheName(); 166 if (cachename == null) { 167 throw new RuntimeException("default cache name error"); 168 } 169 } 170 if (principal == null) { 171 principal = getDefaultPrincipal(); 172 } 173 } 174 175 PrincipalName getDefaultPrincipal() { 176 177 // get default principal name from the cachename if it is 178 // available. 179 180 try { 181 CCacheInputStream cis = 182 new CCacheInputStream(new FileInputStream(cachename)); 183 int version; 184 if ((version = cis.readVersion()) == 185 FileCCacheConstants.KRB5_FCC_FVNO_4) { 186 cis.readTag(); 187 } else { 188 if (version == FileCCacheConstants.KRB5_FCC_FVNO_1 || 189 version == FileCCacheConstants.KRB5_FCC_FVNO_2) { 190 cis.setNativeByteOrder(); 191 } 192 } 193 PrincipalName p = cis.readPrincipal(version); 194 cis.close(); 195 if (DEBUG) { 196 System.out.println(">>>KinitOptions principal name from "+ 197 "the cache is :" + p); 198 } 199 return p; 200 } catch (IOException e) { 201 // ignore any exceptions; we will use the user name as the 202 // principal name 203 if (DEBUG) { 204 e.printStackTrace(); 205 } 206 } catch (RealmException e) { 207 if (DEBUG) { 208 e.printStackTrace(); 209 } 210 } 211 212 String username = System.getProperty("user.name"); 213 if (DEBUG) { 214 System.out.println(">>>KinitOptions default username is :" 215 + username); 216 } 217 try { 218 PrincipalName p = new PrincipalName(username); 219 return p; 220 } catch (RealmException e) { 221 // ignore exception , return null 222 if (DEBUG) { 223 System.out.println ("Exception in getting principal " + 224 "name " + e.getMessage()); 225 e.printStackTrace(); 226 } 227 } 228 return null; 229 } 230 231 232 void printHelp() { 233 System.out.println("Usage:\n\n1. Initial ticket request:\n" + 234 " kinit [-A] [-f] [-p] [-c cachename] " + 235 "[-l lifetime] [-r renewable_time]\n" + 236 " [[-k [-t keytab_file_name]] [principal] " + 237 "[password]"); 238 System.out.println("2. Renew a ticket:\n" + 239 " kinit -R [-c cachename] [principal]"); 240 System.out.println("\nAvailable options to " + 241 "Kerberos 5 ticket request:"); 242 System.out.println("\t-A do not include addresses"); 243 System.out.println("\t-f forwardable"); 244 System.out.println("\t-p proxiable"); 245 System.out.println("\t-c cache name " + 246 "(i.e., FILE:\\d:\\myProfiles\\mykrb5cache)"); 247 System.out.println("\t-l lifetime"); 248 System.out.println("\t-r renewable time " + 249 "(total lifetime a ticket can be renewed)"); 250 System.out.println("\t-k use keytab"); 251 System.out.println("\t-t keytab file name"); 252 System.out.println("\tprincipal the principal name "+ 253 "(i.e., qweadf@ATHENA.MIT.EDU qweadf)"); 254 System.out.println("\tpassword the principal's Kerberos password"); 255 } 256 257 public boolean getAddressOption() { 258 return includeAddresses; 259 } 260 261 public boolean useKeytabFile() { 262 return useKeytab; 263 } 264 265 public String keytabFileName() { 266 return ktabName; 267 } 268 269 public PrincipalName getPrincipal() { 270 return principal; 271 } 272 273 private KerberosTime getTime(int s) { 274 return new KerberosTime(Instant.now().plusSeconds(s)); 275 } 276 }