/* * Copyright (c) 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.rcache; import java.io.IOException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; import java.util.StringTokenizer; /** * The class represents an old style replay cache entry. It is only used in * a dfl file. * * @author Sun/Oracle * @author Yanni Zhang */ public class AuthTime { final int ctime; final int cusec; final String client; final String server; /** * Constructs an AuthTime. */ public AuthTime(String client, String server, int ctime, int cusec) { this.ctime = ctime; this.cusec = cusec; this.client = client; this.server = server; } @Override public String toString() { return String.format("%d/%06d/----/%s", ctime, cusec, client); } // Methods used when saved in a dfl file. See DflCache.java /** * Reads an LC style string from a channel, which is a int32 length * plus a UTF-8 encoded string possibly ends with \0. * @throws IOException if there is a format error * @throws BufferUnderflowException if goes beyond the end */ private static String readStringWithLength(SeekableByteChannel chan) throws IOException { ByteBuffer bb = ByteBuffer.allocate(4); bb.order(ByteOrder.nativeOrder()); chan.read(bb); bb.flip(); int len = bb.getInt(); if (len > 1024) { // Memory attack? The string should be fairly short. throw new IOException("Invalid string length"); } bb = ByteBuffer.allocate(len); if (chan.read(bb) != len) { throw new IOException("Not enough string"); } byte[] data = bb.array(); return (data[len-1] == 0)? new String(data, 0, len-1, StandardCharsets.UTF_8): new String(data, StandardCharsets.UTF_8); } /** * Reads an AuthTime or AuthTimeWithHash object from a channel. * @throws IOException if there is a format error * @throws BufferUnderflowException if goes beyond the end */ public static AuthTime readFrom(SeekableByteChannel chan) throws IOException { String client = readStringWithLength(chan); String server = readStringWithLength(chan); ByteBuffer bb = ByteBuffer.allocate(8); chan.read(bb); bb.order(ByteOrder.nativeOrder()); int cusec = bb.getInt(0); int ctime = bb.getInt(4); if (client.isEmpty()) { StringTokenizer st = new StringTokenizer(server, " :"); if (st.countTokens() != 6) { throw new IOException("Incorrect rcache style"); } String hashAlg = st.nextToken(); String hash = st.nextToken(); st.nextToken(); client = st.nextToken(); st.nextToken(); server = st.nextToken(); return new AuthTimeWithHash( client, server, ctime, cusec, hashAlg, hash); } else { return new AuthTime( client, server, ctime, cusec); } } /** * Encodes to be used in a dfl file */ protected byte[] encode0(String cstring, String sstring) { byte[] c = cstring.getBytes(StandardCharsets.UTF_8);; byte[] s = sstring.getBytes(StandardCharsets.UTF_8);; byte[] zero = new byte[1]; int len = 4 + c.length + 1 + 4 + s.length + 1 + 4 + 4; ByteBuffer bb = ByteBuffer.allocate(len) .order(ByteOrder.nativeOrder()); bb.putInt(c.length+1).put(c).put(zero) .putInt(s.length+1).put(s).put(zero) .putInt(cusec).putInt(ctime); return bb.array(); } /** * Encodes to be used in a dfl file * @param withHash useless here */ public byte[] encode(boolean withHash) { return encode0(client, server); } }