blob: 5a62d6d2508fed4cf281066e0f6d72d965398735 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
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
31package sun.security.krb5.internal.ccache;
32
33import java.io.IOException;
34import java.io.InputStream;
35import java.util.Hashtable;
36import java.util.Vector;
37import java.util.StringTokenizer;
38import sun.security.krb5.*;
39import sun.security.krb5.internal.*;
40import sun.security.krb5.internal.util.KrbDataInputStream;
41
42/**
43 * This class extends KrbDataInputStream. It is used for parsing FCC-format
44 * data from file to memory.
45 *
46 * @author Yanni Zhang
47 *
48 */
49public class CCacheInputStream extends KrbDataInputStream implements FileCCacheConstants {
50
51 /*
52 * FCC version 2 contains type information for principals. FCC
53 * version 1 does not.
54 *
55 * FCC version 3 contains keyblock encryption type information, and is
56 * architecture independent. Previous versions are not.
57 *
58 * The code will accept version 1, 2, and 3 ccaches, and depending
59 * what KRB5_FCC_DEFAULT_FVNO is set to, it will create version 1, 2,
60 * or 3 FCC caches.
61 *
62 * The default credentials cache should be type 3 for now (see
63 * init_ctx.c).
64 */
65 /* V4 of the credentials cache format allows for header tags */
66
67 private static boolean DEBUG = Krb5.DEBUG;
68
69 public CCacheInputStream(InputStream is){
70 super(is);
71 }
72
73 /* Read tag field introduced in KRB5_FCC_FVNO_4 */
74 // this needs to be public for Kinit.
75 public Tag readTag() throws IOException {
76 char[] buf = new char[1024];
77 byte[] bytes;
78 int len;
79 int tag = -1;
80 int taglen;
81 Integer time_offset = null;
82 Integer usec_offset = null;
83
84 len = read(2);
85 if (len < 0) {
86 throw new IOException("stop.");
87 }
88 bytes = new byte[len + 2];
89 if (len > buf.length) {
90 throw new IOException("Invalid tag length.");
91 }
92 while (len > 0) {
93 tag = read(2);
94 taglen = read(2);
95 switch (tag) {
96 case FCC_TAG_DELTATIME:
97 time_offset = new Integer(read(4));
98 usec_offset = new Integer(read(4));
99 break;
100 default:
101 }
102 len = len - (4 + taglen);
103 }
104 Tag result;
105 if (tag == -1) {
106 }
107 result = new Tag(len, tag, time_offset, usec_offset);
108 return result;
109 }
110 /*
111 * In file-based credential cache, the realm name is stored as part of
112 * principal name at the first place.
113 */
114 // made public for KinitOptions to call directly
115 public PrincipalName readPrincipal(int version) throws IOException, RealmException {
116 int type, length, namelength, kret;
117 PrincipalName p;
118 String[] pname = null;
119 String realm;
120 /* Read principal type */
121 if (version == KRB5_FCC_FVNO_1) {
122 type = KRB5_NT_UNKNOWN;
123 } else {
124 type = read(4);
125 }
126 length = read(4);
127 String[] result = new String[length + 1];
128 /*
129 * DCE includes the principal's realm in the count; the new format
130 * does not.
131 */
132 if (version == KRB5_FCC_FVNO_1)
133 length--;
134 for (int i = 0; i <= length; i++) {
135 namelength = read(4);
136 if (namelength > MAXNAMELENGTH) {
137 throw new IOException("Invalid name length in principal name.");
138 }
139 byte[] bytes = new byte[namelength];
140 read(bytes, 0, namelength);
141 result[i] = new String(bytes);
142 }
143 if (isRealm(result[0])) {
144 realm = result[0];
145 pname = new String[length];
146 System.arraycopy(result, 1, pname, 0, length);
147 p = new PrincipalName(pname, type);
148 p.setRealm(realm);
149 }
150 else p = new PrincipalName(result, type);
151 return p;
152 }
153
154 /*
155 * In practice, a realm is named by uppercasing the DNS domain name. we currently
156 * rely on this to determine if the string within the principal identifier is realm
157 * name.
158 *
159 */
160 boolean isRealm(String str) {
161 try {
162 Realm r = new Realm(str);
163 }
164 catch (Exception e) {
165 return false;
166 }
167 StringTokenizer st = new StringTokenizer(str, ".");
168 String s;
169 while (st.hasMoreTokens()) {
170 s = st.nextToken();
171 for (int i = 0; i < s.length(); i++) {
172 if (s.charAt(i) >= 141) {
173 return false;
174 }
175 }
176 }
177 return true;
178 }
179
180 EncryptionKey readKey(int version) throws IOException {
181 int keyType, keyLen;
182 keyType = read(2);
183 if (version == KRB5_FCC_FVNO_3)
184 read(2); /* keytype recorded twice in fvno 3 */
185 keyLen = read(4);
186 byte[] bytes = new byte[keyLen];
187 for (int i = 0; i < keyLen; i++) {
188 bytes[i] = (byte)read();
189 }
190 return new EncryptionKey(bytes, keyType, new Integer(version));
191 }
192
193 long[] readTimes() throws IOException {
194 long[] times = new long[4];
195 times[0] = (long)read(4) * 1000;
196 times[1] = (long)read(4) * 1000;
197 times[2] = (long)read(4) * 1000;
198 times[3] = (long)read(4) * 1000;
199 return times;
200 }
201
202 boolean readskey() throws IOException {
203 if (read() == 0) {
204 return false;
205 }
206 else return true;
207 }
208
209 HostAddress[] readAddr() throws IOException, KrbApErrException {
210 int numAddrs, addrType, addrLength;
211 numAddrs = read(4);
212 if (numAddrs > 0) {
213 HostAddress[] addrs = new HostAddress[numAddrs];
214 for (int i = 0; i < numAddrs; i++) {
215 addrType = read(2);
216 addrLength = read(4);
217 if (!(addrLength == 4 || addrLength == 16)) {
218 System.out.println("Incorrect address format.");
219 return null;
220 }
221 byte[] result = new byte[addrLength];
222 for (int j = 0; j < addrLength; j++)
223 result[j] = (byte)read(1);
224 addrs[i] = new HostAddress(addrType, result);
225 }
226 return addrs;
227 }
228 return null;
229 }
230
231 AuthorizationDataEntry[] readAuth() throws IOException {
232 int num, adtype, adlength;
233 num = read(4);
234 if (num > 0) {
235 AuthorizationDataEntry[] auData = new AuthorizationDataEntry[num];
236 byte[] data = null;
237 for (int i = 0; i < num; i++) {
238 adtype = read(2);
239 adlength = read(4);
240 data = new byte[adlength];
241 for (int j = 0; j < adlength; j++) {
242 data[j] = (byte)read();
243 }
244 auData[i] = new AuthorizationDataEntry(adtype, data);
245 }
246 return auData;
247 }
248 else return null;
249 }
250
251 Ticket readData() throws IOException, RealmException, KrbApErrException, Asn1Exception {
252 int length;
253 length = read(4);
254 if (length > 0) {
255 byte[] bytes = new byte[length];
256 read(bytes, 0, length);
257 Ticket ticket = new Ticket(bytes);
258 return ticket;
259 }
260 else return null;
261 }
262
263 boolean[] readFlags() throws IOException {
264 boolean[] flags = new boolean[Krb5.TKT_OPTS_MAX+1];
265 int ticketFlags;
266 ticketFlags = read(4);
267 if ((ticketFlags & 0x40000000) == TKT_FLG_FORWARDABLE)
268 flags[1] = true;
269 if ((ticketFlags & 0x20000000) == TKT_FLG_FORWARDED)
270 flags[2] = true;
271 if ((ticketFlags & 0x10000000) == TKT_FLG_PROXIABLE)
272 flags[3] = true;
273 if ((ticketFlags & 0x08000000) == TKT_FLG_PROXY)
274 flags[4] = true;
275 if ((ticketFlags & 0x04000000) == TKT_FLG_MAY_POSTDATE)
276 flags[5] = true;
277 if ((ticketFlags & 0x02000000) == TKT_FLG_POSTDATED)
278 flags[6] = true;
279 if ((ticketFlags & 0x01000000) == TKT_FLG_INVALID)
280 flags[7] = true;
281 if ((ticketFlags & 0x00800000) == TKT_FLG_RENEWABLE)
282 flags[8] = true;
283 if ((ticketFlags & 0x00400000) == TKT_FLG_INITIAL)
284 flags[9] = true;
285 if ((ticketFlags & 0x00200000) == TKT_FLG_PRE_AUTH)
286 flags[10] = true;
287 if ((ticketFlags & 0x00100000) == TKT_FLG_HW_AUTH)
288 flags[11] = true;
289 if (DEBUG) {
290 String msg = ">>> CCacheInputStream: readFlags() ";
291 if (flags[1] == true) {
292 msg += " FORWARDABLE;";
293 }
294 if (flags[2] == true) {
295 msg += " FORWARDED;";
296 }
297 if (flags[3] == true) {
298 msg += " PROXIABLE;";
299 }
300 if (flags[4] == true) {
301 msg += " PROXY;";
302 }
303 if (flags[5] == true) {
304 msg += " MAY_POSTDATE;";
305 }
306 if (flags[6] == true) {
307 msg += " POSTDATED;";
308 }
309 if (flags[7] == true) {
310 msg += " INVALID;";
311 }
312 if (flags[8] == true) {
313 msg += " RENEWABLE;";
314 }
315
316 if (flags[9] == true) {
317 msg += " INITIAL;";
318 }
319 if (flags[10] == true) {
320 msg += " PRE_AUTH;";
321 }
322 if (flags[11] == true) {
323 msg += " HW_AUTH;";
324 }
325 System.out.println(msg);
326 }
327 return flags;
328 }
329 Credentials readCred(int version) throws IOException,RealmException, KrbApErrException, Asn1Exception {
330 PrincipalName cpname = readPrincipal(version);
331 if (DEBUG)
332 System.out.println(">>>DEBUG <CCacheInputStream> client principal is " + cpname.toString());
333 PrincipalName spname = readPrincipal(version);
334 if (DEBUG)
335 System.out.println(">>>DEBUG <CCacheInputStream> server principal is " + spname.toString());
336 EncryptionKey key = readKey(version);
337 if (DEBUG)
338 System.out.println(">>>DEBUG <CCacheInputStream> key type: " + key.getEType());
339 long times[] = readTimes();
340 KerberosTime authtime = new KerberosTime(times[0]);
341 KerberosTime starttime = new KerberosTime(times[1]);
342 KerberosTime endtime = new KerberosTime(times[2]);
343 KerberosTime renewTill = new KerberosTime(times[3]);
344
345 if (DEBUG) {
346 System.out.println(">>>DEBUG <CCacheInputStream> auth time: " + authtime.toDate().toString());
347 System.out.println(">>>DEBUG <CCacheInputStream> start time: " + starttime.toDate().toString());
348 System.out.println(">>>DEBUG <CCacheInputStream> end time: " + endtime.toDate().toString());
349 System.out.println(">>>DEBUG <CCacheInputStream> renew_till time: " + renewTill.toDate().toString());
350 }
351 boolean skey = readskey();
352 boolean flags[] = readFlags();
353 TicketFlags tFlags = new TicketFlags(flags);
354 HostAddress addr[] = readAddr();
355 HostAddresses addrs = null;
356 if (addr != null) {
357 addrs = new HostAddresses(addr);
358 }
359 AuthorizationDataEntry[] auDataEntry = readAuth();
360 AuthorizationData auData = null;
361 if (auData != null) {
362 auData = new AuthorizationData(auDataEntry);
363 }
364 Ticket ticket = readData();
365 if (DEBUG) {
366 System.out.println(">>>DEBUG <CCacheInputStream>");
367 if (ticket == null) {
368 System.out.println("///ticket is null");
369 }
370 }
371 Ticket secTicket = readData();
372 Credentials cred = new Credentials(cpname, spname, key, authtime, starttime,
373 endtime, renewTill, skey, tFlags,
374 addrs, auData, ticket, secTicket);
375 return cred;
376 }
377}