1 /* 2 * Copyright (c) 2000, 2011, 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; 33 34 import sun.security.krb5.PrincipalName; 35 import sun.security.krb5.KrbException; 36 import sun.security.krb5.Asn1Exception; 37 import sun.security.util.*; 38 import java.util.Vector; 39 import java.util.ArrayList; 40 import java.net.InetAddress; 41 import java.net.Inet4Address; 42 import java.net.Inet6Address; 43 import java.net.UnknownHostException; 44 import java.io.IOException; 45 import sun.security.krb5.internal.ccache.CCacheOutputStream; 46 47 /** 48 * Implements the ASN.1 HostAddresses type. 49 * 50 * <xmp> 51 * HostAddresses -- NOTE: subtly different from rfc1510, 52 * -- but has a value mapping and encodes the same 53 * ::= SEQUENCE OF HostAddress 54 * 55 * HostAddress ::= SEQUENCE { 56 * addr-type [0] Int32, 57 * address [1] OCTET STRING 58 * } 59 * </xmp> 60 * 61 * <p> 62 * This definition reflects the Network Working Group RFC 4120 63 * specification available at 64 * <a href="http://www.ietf.org/rfc/rfc4120.txt"> 65 * http://www.ietf.org/rfc/rfc4120.txt</a>. 66 */ 67 68 public class HostAddresses implements Cloneable { 69 private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; 70 private HostAddress[] addresses = null; 71 private volatile int hashCode = 0; 72 73 public HostAddresses(HostAddress[] new_addresses) throws IOException { 74 if (new_addresses != null) { 75 addresses = new HostAddress[new_addresses.length]; 76 for (int i = 0; i < new_addresses.length; i++) { 77 if (new_addresses[i] == null) { 78 throw new IOException("Cannot create a HostAddress"); 79 } else { 80 addresses[i] = (HostAddress)new_addresses[i].clone(); 81 } 82 } 83 } 84 } 85 86 public HostAddresses() throws UnknownHostException { 87 addresses = new HostAddress[1]; 88 addresses[0] = new HostAddress(); 89 } 90 91 private HostAddresses(int dummy) {} 92 93 public HostAddresses(PrincipalName serverPrincipal) 94 throws UnknownHostException, KrbException { 95 96 String[] components = serverPrincipal.getNameStrings(); 97 98 if (serverPrincipal.getNameType() != PrincipalName.KRB_NT_SRV_HST || 99 components.length < 2) 100 throw new KrbException(Krb5.KRB_ERR_GENERIC, "Bad name"); 101 102 String host = components[1]; 103 InetAddress addr[] = InetAddress.getAllByName(host); 104 HostAddress hAddrs[] = new HostAddress[addr.length]; 105 106 for (int i = 0; i < addr.length; i++) { 107 hAddrs[i] = new HostAddress(addr[i]); 108 } 109 110 addresses = hAddrs; 111 } 112 113 public Object clone() { 114 HostAddresses new_hostAddresses = new HostAddresses(0); 115 if (addresses != null) { 116 new_hostAddresses.addresses = new HostAddress[addresses.length]; 117 for (int i = 0; i < addresses.length; i++) { 118 new_hostAddresses.addresses[i] = 119 (HostAddress)addresses[i].clone(); 120 } 121 } 122 return new_hostAddresses; 123 } 124 125 public boolean inList(HostAddress addr) { 126 if (addresses != null) { 127 for (int i = 0; i < addresses.length; i++) 128 if (addresses[i].equals(addr)) 129 return true; 130 } 131 return false; 132 } 133 134 public int hashCode() { 135 if (hashCode == 0) { 136 int result = 17; 137 if (addresses != null) { 138 for (int i=0; i < addresses.length; i++) { 139 result = 37*result + addresses[i].hashCode(); 140 } 141 } 142 hashCode = result; 143 } 144 return hashCode; 145 146 } 147 148 149 public boolean equals(Object obj) { 150 if (this == obj) { 151 return true; 152 } 153 154 if (!(obj instanceof HostAddresses)) { 155 return false; 156 } 157 158 HostAddresses addrs = (HostAddresses)obj; 159 if ((addresses == null && addrs.addresses != null) || 160 (addresses != null && addrs.addresses == null)) 161 return false; 162 if (addresses != null && addrs.addresses != null) { 163 if (addresses.length != addrs.addresses.length) 164 return false; 165 for (int i = 0; i < addresses.length; i++) 166 if (!addresses[i].equals(addrs.addresses[i])) 167 return false; 168 } 169 return true; 170 } 171 172 /** 173 * Constructs a new <code>HostAddresses</code> object. 174 * @param encoding a single DER-encoded value. 175 * @exception Asn1Exception if an error occurs while decoding an 176 * ASN1 encoded data. 177 * @exception IOException if an I/O error occurs while reading 178 * encoded data. 179 */ 180 public HostAddresses(DerValue encoding) 181 throws Asn1Exception, IOException { 182 Vector<HostAddress> tempAddresses = new Vector<>(); 183 DerValue der = null; 184 while (encoding.getData().available() > 0) { 185 der = encoding.getData().getDerValue(); 186 tempAddresses.addElement(new HostAddress(der)); 187 } 188 if (tempAddresses.size() > 0) { 189 addresses = new HostAddress[tempAddresses.size()]; 190 tempAddresses.copyInto(addresses); 191 } 192 } 193 194 195 /** 196 * Encodes a <code>HostAddresses</code> object. 197 * @return byte array of encoded <code>HostAddresses</code> object. 198 * @exception Asn1Exception if an error occurs while decoding an 199 * ASN1 encoded data. 200 * @exception IOException if an I/O error occurs while reading 201 * encoded data. 202 */ 203 public byte[] asn1Encode() throws Asn1Exception, IOException { 204 DerOutputStream bytes = new DerOutputStream(); 205 DerOutputStream temp = new DerOutputStream(); 206 207 if (addresses != null && addresses.length > 0) { 208 for (int i = 0; i < addresses.length; i++) 209 bytes.write(addresses[i].asn1Encode()); 210 } 211 temp.write(DerValue.tag_Sequence, bytes); 212 return temp.toByteArray(); 213 } 214 215 /** 216 * Parse (unmarshal) a <code>HostAddresses</code> from a DER input stream. 217 * This form 218 * parsing might be used when expanding a value which is part of 219 * a constructed sequence and uses explicitly tagged type. 220 * 221 * @exception Asn1Exception if an Asn1Exception occurs. 222 * @param data the Der input stream value, which contains one or more 223 * marshaled value. 224 * @param explicitTag tag number. 225 * @param optional indicates if this data field is optional. 226 * @return an instance of <code>HostAddresses</code>. 227 */ 228 public static HostAddresses parse(DerInputStream data, 229 byte explicitTag, boolean optional) 230 throws Asn1Exception, IOException { 231 if ((optional) && 232 (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) 233 return null; 234 DerValue der = data.getDerValue(); 235 if (explicitTag != (der.getTag() & (byte)0x1F)) { 236 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 237 } else { 238 DerValue subDer = der.getData().getDerValue(); 239 return new HostAddresses(subDer); 240 } 241 } 242 243 /** 244 * Writes data field values in <code>HostAddresses</code> in FCC 245 * format to a <code>CCacheOutputStream</code>. 246 * 247 * @param cos a <code>CCacheOutputStream</code> to be written to. 248 * @exception IOException if an I/O exception occurs. 249 * @see sun.security.krb5.internal.ccache.CCacheOutputStream 250 */ 251 252 public void writeAddrs(CCacheOutputStream cos) throws IOException { 253 cos.write32(addresses.length); 254 for (int i = 0; i < addresses.length; i++) { 255 cos.write16(addresses[i].addrType); 256 cos.write32(addresses[i].address.length); 257 cos.write(addresses[i].address, 0, 258 addresses[i].address.length); 259 } 260 } 261 262 263 public InetAddress[] getInetAddresses() { 264 265 if (addresses == null || addresses.length == 0) 266 return null; 267 268 ArrayList<InetAddress> ipAddrs = new ArrayList<>(addresses.length); 269 270 for (int i = 0; i < addresses.length; i++) { 271 try { 272 if ((addresses[i].addrType == Krb5.ADDRTYPE_INET) || 273 (addresses[i].addrType == Krb5.ADDRTYPE_INET6)) { 274 ipAddrs.add(addresses[i].getInetAddress()); 275 } 276 } catch (java.net.UnknownHostException e) { 277 // Should not happen since IP address given 278 return null; 279 } 280 } 281 282 InetAddress[] retVal = new InetAddress[ipAddrs.size()]; 283 return ipAddrs.toArray(retVal); 284 285 } 286 287 /** 288 * Returns all the IP addresses of the local host. 289 */ 290 public static HostAddresses getLocalAddresses() throws IOException 291 { 292 String hostname = null; 293 InetAddress[] inetAddresses = null; 294 try { 295 InetAddress localHost = InetAddress.getLocalHost(); 296 hostname = localHost.getHostName(); 297 inetAddresses = InetAddress.getAllByName(hostname); 298 HostAddress[] hAddresses = new HostAddress[inetAddresses.length]; 299 for (int i = 0; i < inetAddresses.length; i++) 300 { 301 hAddresses[i] = new HostAddress(inetAddresses[i]); 302 } 303 if (DEBUG) { 304 System.out.println(">>> KrbKdcReq local addresses for " 305 + hostname + " are: "); 306 307 for (int i = 0; i < inetAddresses.length; i++) { 308 System.out.println("\n\t" + inetAddresses[i]); 309 if (inetAddresses[i] instanceof Inet4Address) 310 System.out.println("IPv4 address"); 311 if (inetAddresses[i] instanceof Inet6Address) 312 System.out.println("IPv6 address"); 313 } 314 } 315 return (new HostAddresses(hAddresses)); 316 } catch (Exception exc) { 317 throw new IOException(exc.toString()); 318 } 319 320 } 321 322 /** 323 * Creates a new HostAddresses instance from the supplied list 324 * of InetAddresses. 325 */ 326 public HostAddresses(InetAddress[] inetAddresses) 327 { 328 if (inetAddresses == null) 329 { 330 addresses = null; 331 return; 332 } 333 334 addresses = new HostAddress[inetAddresses.length]; 335 for (int i = 0; i < inetAddresses.length; i++) 336 addresses[i] = new HostAddress(inetAddresses[i]); 337 } 338 }