1 /* 2 * Copyright (c) 2013, 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 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32 package sun.security.krb5.internal.rcache; 33 34 import java.io.IOException; 35 import java.nio.BufferUnderflowException; 36 import java.nio.ByteBuffer; 37 import java.nio.ByteOrder; 38 import java.nio.channels.SeekableByteChannel; 39 import java.nio.charset.StandardCharsets; 40 import java.util.StringTokenizer; 41 42 /** 43 * The class represents an old style replay cache entry. It is only used in 44 * a dfl file. 45 * 46 * @author Sun/Oracle 47 * @author Yanni Zhang 48 */ 49 public class AuthTime { 50 final int ctime; 51 final int cusec; 52 final String client; 53 final String server; 54 55 /** 56 * Constructs an <code>AuthTime</code>. 57 */ 58 public AuthTime(String client, String server, 59 int ctime, int cusec) { 60 this.ctime = ctime; 61 this.cusec = cusec; 62 this.client = client; 63 this.server = server; 64 } 65 66 @Override 67 public String toString() { 68 return String.format("%d/%06d/----/%s", ctime, cusec, client); 69 } 70 71 // Methods used when saved in a dfl file. See DflCache.java 72 73 /** 74 * Reads an LC style string from a channel, which is a int32 length 75 * plus a UTF-8 encoded string possibly ends with \0. 76 * @throws IOException if there is a format error 77 * @throws BufferUnderflowException if goes beyond the end 78 */ 79 private static String readStringWithLength(SeekableByteChannel chan) 80 throws IOException { 81 ByteBuffer bb = ByteBuffer.allocate(4); 82 bb.order(ByteOrder.nativeOrder()); 83 chan.read(bb); 84 bb.flip(); 85 int len = bb.getInt(); 86 if (len > 1024) { 87 // Memory attack? The string should be fairly short. 88 throw new IOException("Invalid string length"); 89 } 90 bb = ByteBuffer.allocate(len); 91 if (chan.read(bb) != len) { 92 throw new IOException("Not enough string"); 93 } 94 byte[] data = bb.array(); 95 return (data[len-1] == 0)? 96 new String(data, 0, len-1, StandardCharsets.UTF_8): 97 new String(data, StandardCharsets.UTF_8); 98 } 99 100 /** 101 * Reads an AuthTime or AuthTimeWithHash object from a channel. 102 * @throws IOException if there is a format error 103 * @throws BufferUnderflowException if goes beyond the end 104 */ 105 public static AuthTime readFrom(SeekableByteChannel chan) 106 throws IOException { 107 String client = readStringWithLength(chan); 108 String server = readStringWithLength(chan); 109 ByteBuffer bb = ByteBuffer.allocate(8); 110 chan.read(bb); 111 bb.order(ByteOrder.nativeOrder()); 112 int cusec = bb.getInt(0); 113 int ctime = bb.getInt(4); 114 if (client.isEmpty()) { 115 StringTokenizer st = new StringTokenizer(server, " :"); 116 if (st.countTokens() != 6) { 117 throw new IOException("Incorrect rcache style"); 118 } 119 st.nextToken(); 120 String hash = st.nextToken(); 121 st.nextToken(); 122 client = st.nextToken(); 123 st.nextToken(); 124 server = st.nextToken(); 125 return new AuthTimeWithHash( 126 client, server, ctime, cusec, hash); 127 } else { 128 return new AuthTime( 129 client, server, ctime, cusec); 130 } 131 } 132 133 /** 134 * Encodes to be used in a dfl file 135 */ 136 protected byte[] encode0(String cstring, String sstring) { 137 byte[] c = cstring.getBytes(StandardCharsets.UTF_8);; 138 byte[] s = sstring.getBytes(StandardCharsets.UTF_8);; 139 byte[] zero = new byte[1]; 140 int len = 4 + c.length + 1 + 4 + s.length + 1 + 4 + 4; 141 ByteBuffer bb = ByteBuffer.allocate(len) 142 .order(ByteOrder.nativeOrder()); 143 bb.putInt(c.length+1).put(c).put(zero) 144 .putInt(s.length+1).put(s).put(zero) 145 .putInt(cusec).putInt(ctime); 146 return bb.array(); 147 } 148 149 /** 150 * Encodes to be used in a dfl file 151 * @param withHash useless here 152 */ 153 public byte[] encode(boolean withHash) { 154 return encode0(client, server); 155 } 156 }