From 0f3dd95156a3652b614380a96ade5ba7bb25860a Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 25 Aug 2010 15:35:45 -0700 Subject: [PATCH 01/27] 6980019: Finish rename of ARM -> try-with-resources in jdk repository Reviewed-by: jjg --- jdk/src/share/classes/java/lang/AutoCloseable.java | 4 ++-- jdk/src/share/classes/java/lang/Throwable.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java index 18c28fe887b..a44f5840cd7 100644 --- a/jdk/src/share/classes/java/lang/AutoCloseable.java +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java @@ -34,8 +34,8 @@ package java.lang; public interface AutoCloseable { /** * Close this resource, relinquishing any underlying resources. - * This method is invoked automatically by the automatic resource - * management block construct. + * This method is invoked automatically by the {@code + * try}-with-resources statement. * *

Classes implementing this method are strongly encouraged to * be declared to throw more specific exceptions (or no exception diff --git a/jdk/src/share/classes/java/lang/Throwable.java b/jdk/src/share/classes/java/lang/Throwable.java index 4d4169139e8..0073d3f3c3d 100644 --- a/jdk/src/share/classes/java/lang/Throwable.java +++ b/jdk/src/share/classes/java/lang/Throwable.java @@ -498,8 +498,8 @@ public class Throwable implements Serializable { * } * * As of release 7, the platform supports the notion of - * suppressed exceptions (in conjunction with automatic - * resource management blocks). Any exceptions that were + * suppressed exceptions (in conjunction with the {@code + * try}-with-resources statement). Any exceptions that were * suppressed in order to deliver an exception are printed out * beneath the stack trace. The format of this information * depends on the implementation, but the following example may be @@ -805,7 +805,7 @@ public class Throwable implements Serializable { /** * Adds the specified exception to the list of exceptions that - * were suppressed, typically by the automatic resource management + * were suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * *

Note that when one exception {@linkplain @@ -839,7 +839,7 @@ public class Throwable implements Serializable { /** * Returns an array containing all of the exceptions that were - * suppressed, typically by the automatic resource management + * suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * * @return an array containing all of the exceptions that were From aff3ad21b8463e4446647f3df92c279686ac40a2 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Sat, 28 Aug 2010 12:15:52 -0700 Subject: [PATCH 02/27] 6980747: Runtime.exec can fail due to SecurityException (lnx) Add missing doPrivileged to UNIXProcess.java.linux Reviewed-by: alanb --- .../classes/java/lang/UNIXProcess.java.linux | 27 ++++--- .../ProcessBuilder/SecurityManagerClinit.java | 79 +++++++++++++++++++ 2 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 jdk/test/java/lang/ProcessBuilder/SecurityManagerClinit.java diff --git a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux index af68ce18e6b..29477f93bbc 100644 --- a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux +++ b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux @@ -39,6 +39,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import java.security.AccessController; +import static java.security.AccessController.doPrivileged; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -94,14 +95,13 @@ final class UNIXProcess extends Process { private final static ThreadGroup group = getRootThreadGroup(); private static ThreadGroup getRootThreadGroup() { - return AccessController.doPrivileged - (new PrivilegedAction () { - public ThreadGroup run() { - ThreadGroup root = Thread.currentThread().getThreadGroup(); - while (root.getParent() != null) - root = root.getParent(); - return root; - }}); + return doPrivileged(new PrivilegedAction () { + public ThreadGroup run() { + ThreadGroup root = Thread.currentThread().getThreadGroup(); + while (root.getParent() != null) + root = root.getParent(); + return root; + }}); } public Thread newThread(Runnable grimReaper) { @@ -117,8 +117,12 @@ final class UNIXProcess extends Process { /** * The thread pool of "process reaper" daemon threads. */ - private static final Executor processReaperExecutor - = Executors.newCachedThreadPool(new ProcessReaperThreadFactory()); + private static final Executor processReaperExecutor = + doPrivileged(new PrivilegedAction() { + public Executor run() { + return Executors.newCachedThreadPool + (new ProcessReaperThreadFactory()); + }}); UNIXProcess(final byte[] prog, final byte[] argBlock, final int argc, @@ -136,8 +140,7 @@ final class UNIXProcess extends Process { redirectErrorStream); try { - AccessController.doPrivileged - (new PrivilegedExceptionAction() { + doPrivileged(new PrivilegedExceptionAction() { public Void run() throws IOException { initStreams(fds); return null; diff --git a/jdk/test/java/lang/ProcessBuilder/SecurityManagerClinit.java b/jdk/test/java/lang/ProcessBuilder/SecurityManagerClinit.java new file mode 100644 index 00000000000..dff61742225 --- /dev/null +++ b/jdk/test/java/lang/ProcessBuilder/SecurityManagerClinit.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 Google Inc. 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. + * + * 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. + */ + +/* + * @test + * @bug 6980747 + * @summary Check that Process-related classes have the proper + * doPrivileged blocks, and can be initialized with an adversarial + * security manager. + * @run main/othervm SecurityManagerClinit + * @author Martin Buchholz + */ + +import java.io.*; +import java.security.*; + +public class SecurityManagerClinit { + private static class Policy extends java.security.Policy { + private Permissions perms; + + public Policy(Permission... permissions) { + perms = new Permissions(); + for (Permission permission : permissions) + perms.add(permission); + } + + public boolean implies(ProtectionDomain pd, Permission p) { + return perms.implies(p); + } + } + + public static void main(String[] args) throws Throwable { + String javaExe = + System.getProperty("java.home") + + File.separator + "bin" + File.separator + "java"; + + // A funky contrived security setup, just for bug repro purposes. + java.security.Security.setProperty("package.access", "java.util"); + + final Policy policy = + new Policy + (new FilePermission("<>", "execute"), + new RuntimePermission("setSecurityManager")); + Policy.setPolicy(policy); + + System.setSecurityManager(new SecurityManager()); + + try { + String[] cmd = { javaExe, "-version" }; + Process p = Runtime.getRuntime().exec(cmd); + p.getOutputStream().close(); + p.getInputStream().close(); + p.getErrorStream().close(); + p.waitFor(); + } finally { + System.setSecurityManager(null); + } + } +} From 7fe5113fe77b2ae53768238ab4dfba752f96c30d Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 30 Aug 2010 14:37:43 +0800 Subject: [PATCH 03/27] 6911951: NTLM should be a supported Java SASL mechanism Reviewed-by: vinnie, michaelm --- .../classes/com/sun/security/ntlm/Client.java | 212 +++++++++ .../classes/com/sun/security/ntlm/NTLM.java | 426 ++++++++++++++++++ .../com/sun/security/ntlm/NTLMException.java | 88 ++++ .../classes/com/sun/security/ntlm/Server.java | 205 +++++++++ .../com/sun/security/ntlm/Version.java | 30 ++ .../com/sun/security/sasl/Provider.java | 12 +- .../sun/security/sasl/ntlm/FactoryImpl.java | 119 +++++ .../sun/security/sasl/ntlm/NTLMClient.java | 231 ++++++++++ .../sun/security/sasl/ntlm/NTLMServer.java | 226 ++++++++++ .../http/ntlm/NTLMAuthentication.java | 252 ++--------- .../com/sun/security/sasl/ntlm/NTLMTest.java | 416 +++++++++++++++++ 11 files changed, 1999 insertions(+), 218 deletions(-) create mode 100644 jdk/src/share/classes/com/sun/security/ntlm/Client.java create mode 100644 jdk/src/share/classes/com/sun/security/ntlm/NTLM.java create mode 100644 jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java create mode 100644 jdk/src/share/classes/com/sun/security/ntlm/Server.java create mode 100644 jdk/src/share/classes/com/sun/security/ntlm/Version.java create mode 100644 jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java create mode 100644 jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java create mode 100644 jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java create mode 100644 jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Client.java b/jdk/src/share/classes/com/sun/security/ntlm/Client.java new file mode 100644 index 00000000000..aed8f37084d --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.ntlm; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Date; +import java.util.Locale; + +/** + * The NTLM client. Not multi-thread enabled.

+ * Example: + *

+ * Client client = new Client(null, "host", "dummy",
+ *       "REALM", "t0pSeCr3t".toCharArray());
+ * byte[] type1 = client.type1();
+ * // Send type1 to server and receive response as type2
+ * byte[] type3 = client.type3(type2, nonce);
+ * // Send type3 to server
+ * 
+ */ +public final class Client extends NTLM { + final private String hostname; + final private String username; + + private String domain; // might be updated by Type 2 msg + private byte[] pw1, pw2; + + /** + * Creates an NTLM Client instance. + * @param version the NTLM version to use, which can be: + * + * If null, "LMv2/NTLMv2" will be used. + * @param hostname hostname of the client, can be null + * @param username username to be authenticated, must not be null + * @param domain domain of {@code username}, can be null + * @param password password for {@code username}, must not be not null. + * This method does not make any modification to this parameter, it neither + * needs to access the content of this parameter after this method call, + * so you are free to modify or nullify this parameter after this call. + * @throws NullPointerException if {@code username} or {@code password} is null. + * @throws NTLMException if {@code version} is illegal + */ + public Client(String version, String hostname, String username, + String domain, char[] password) throws NTLMException { + super(version); + if ((username == null || password == null)) { + throw new NullPointerException("username/password cannot be null"); + } + this.hostname = hostname; + this.username = username; + this.domain = domain; + this.pw1 = getP1(password); + this.pw2 = getP2(password); + debug("NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n", + hostname, username, domain, version, v.toString()); + } + + /** + * Generates the Type 1 message + * @return the message generated + */ + public byte[] type1() { + Writer p = new Writer(1, 32); + int flags = 0x8203; + if (hostname != null) { + flags |= 0x2000; + } + if (domain != null) { + flags |= 0x1000; + } + if (v != Version.NTLM) { + flags |= 0x80000; + } + p.writeInt(12, flags); + p.writeSecurityBuffer(24, hostname, false); + p.writeSecurityBuffer(16, domain, false); + debug("NTLM Client: Type 1 created\n"); + debug(p.getBytes()); + return p.getBytes(); + } + + /** + * Generates the Type 3 message + * @param type2 the responding Type 2 message from server, must not be null + * @param nonce random 8-byte array to be used in message generation, + * must not be null except for original NTLM v1 + * @return the message generated + * @throws NullPointerException if {@code type2} or {@code nonce} is null + * for NTLM v1. + * @throws NTLMException if the incoming message is invalid + */ + public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException { + if (type2 == null || (v != Version.NTLM && nonce == null)) { + throw new NullPointerException("type2 and nonce cannot be null"); + } + debug("NTLM Client: Type 2 received\n"); + debug(type2); + Reader r = new Reader(type2); + byte[] challenge = r.readBytes(24, 8); + int inputFlags = r.readInt(20); + boolean unicode = (inputFlags & 1) == 1; + String domainFromServer = r.readSecurityBuffer(12, unicode); + if (domainFromServer != null) { + domain = domainFromServer; + } + if (domain == null) { + throw new NTLMException(NTLMException.NO_DOMAIN_INFO, + "No domain info"); + } + + int flags = 0x88200 | (inputFlags & 3); + Writer p = new Writer(3, 64); + byte[] lm = null, ntlm = null; + + p.writeSecurityBuffer(28, domain, unicode); + p.writeSecurityBuffer(36, username, unicode); + p.writeSecurityBuffer(44, hostname, unicode); + + if (v == Version.NTLM) { + byte[] lmhash = calcLMHash(pw1); + byte[] nthash = calcNTHash(pw2); + if (writeLM) lm = calcResponse (lmhash, challenge); + if (writeNTLM) ntlm = calcResponse (nthash, challenge); + } else if (v == Version.NTLM2) { + byte[] nthash = calcNTHash(pw2); + lm = ntlm2LM(nonce); + ntlm = ntlm2NTLM(nthash, nonce, challenge); + } else { + byte[] nthash = calcNTHash(pw2); + if (writeLM) lm = calcV2(nthash, + username.toUpperCase(Locale.US)+domain, nonce, challenge); + if (writeNTLM) { + byte[] alist = type2.length > 48 ? + r.readSecurityBuffer(40) : new byte[0]; + byte[] blob = new byte[32+alist.length]; + System.arraycopy(new byte[]{1,1,0,0,0,0,0,0}, 0, blob, 0, 8); + // TS + byte[] time = BigInteger.valueOf(new Date().getTime()) + .add(new BigInteger("11644473600000")) + .multiply(BigInteger.valueOf(10000)) + .toByteArray(); + for (int i=0; iSystem.out.printf(format, args) is + * called. This method is designed to be overridden by child classes to + * match their own debugging/logging mechanisms. + * @param format a format string + * @param args the arguments referenced by format + * @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[]) + */ + public void debug(String format, Object... args) { + if (DEBUG) { + System.out.printf(format, args); + } + } + + /** + * Prints out the content of a byte array, called in various places inside + * the NTLM implementation for debugging/logging purposes. When the system + * property "ntlm.debug" is set, the hexdump of the array is printed into + * System.out. This method is designed to be overridden by child classes to + * match their own debugging/logging mechanisms. + * @param bytes the byte array to print out + */ + public void debug(byte[] bytes) { + if (DEBUG) { + try { + new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out); + } catch (IOException ioe) { + // Impossible + } + } + } + + /** + * Reading an NTLM packet + */ + static class Reader { + + private final byte[] internal; + + Reader(byte[] data) { + internal = data; + } + + int readInt(int offset) throws NTLMException { + try { + return internal[offset] & 0xff + + (internal[offset+1] & 0xff << 8) + + (internal[offset+2] & 0xff << 16) + + (internal[offset+3] & 0xff << 24); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + int readShort(int offset) throws NTLMException { + try { + return internal[offset] & 0xff + + (internal[offset+1] & 0xff << 8); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + byte[] readBytes(int offset, int len) throws NTLMException { + try { + return Arrays.copyOfRange(internal, offset, offset + len); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + byte[] readSecurityBuffer(int offset) throws NTLMException { + int pos = readInt(offset+4); + if (pos == 0) return null; + try { + return Arrays.copyOfRange( + internal, pos, pos + readShort(offset)); + } catch (ArrayIndexOutOfBoundsException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Input message incorrect size"); + } + } + + String readSecurityBuffer(int offset, boolean unicode) + throws NTLMException { + byte[] raw = readSecurityBuffer(offset); + try { + return raw == null ? null : new String( + raw, unicode ? "UnicodeLittleUnmarked" : "ISO8859_1"); + } catch (UnsupportedEncodingException ex) { + throw new NTLMException(NTLMException.PACKET_READ_ERROR, + "Invalid input encoding"); + } + } + } + + /** + * Writing an NTLM packet + */ + static class Writer { + + private byte[] internal; // buffer + private int current; // current written content interface buffer + + /** + * Starts writing a NTLM packet + * @param type NEGOTIATE || CHALLENGE || AUTHENTICATE + * @param len the base length, without security buffers + */ + Writer(int type, int len) { + assert len < 256; + internal = new byte[256]; + current = len; + System.arraycopy ( + new byte[] {'N','T','L','M','S','S','P',0,(byte)type}, + 0, internal, 0, 9); + } + + void writeShort(int offset, int number) { + internal[offset] = (byte)(number); + internal[offset+1] = (byte)(number >> 8); + } + + void writeInt(int offset, int number) { + internal[offset] = (byte)(number); + internal[offset+1] = (byte)(number >> 8); + internal[offset+2] = (byte)(number >> 16); + internal[offset+3] = (byte)(number >> 24); + } + + void writeBytes(int offset, byte[] data) { + System.arraycopy(data, 0, internal, offset, data.length); + } + + void writeSecurityBuffer(int offset, byte[] data) { + if (data == null) { + writeShort(offset+4, current); + } else { + int len = data.length; + if (current + len > internal.length) { + internal = Arrays.copyOf(internal, current + len + 256); + } + writeShort(offset, len); + writeShort(offset+2, len); + writeShort(offset+4, current); + System.arraycopy(data, 0, internal, current, len); + current += len; + } + } + + void writeSecurityBuffer(int offset, String str, boolean unicode) { + try { + writeSecurityBuffer(offset, str == null ? null : str.getBytes( + unicode ? "UnicodeLittleUnmarked" : "ISO8859_1")); + } catch (UnsupportedEncodingException ex) { + assert false; + } + } + + byte[] getBytes() { + return Arrays.copyOf(internal, current); + } + } + + // LM/NTLM + + /* Convert a 7 byte array to an 8 byte array (for a des key with parity) + * input starts at offset off + */ + byte[] makeDesKey (byte[] input, int off) { + int[] in = new int [input.length]; + for (int i=0; i> 1)); + out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2)); + out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3)); + out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4)); + out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5)); + out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6)); + out[7] = (byte)((in[off+6] << 1) & 0xFF); + return out; + } + + byte[] calcLMHash (byte[] pwb) { + byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + byte[] pwb1 = new byte [14]; + int len = pwb.length; + if (len > 14) + len = 14; + System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */ + + try { + DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0)); + DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7)); + + SecretKey key1 = fac.generateSecret (dks1); + SecretKey key2 = fac.generateSecret (dks2); + cipher.init (Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal (magic, 0, 8); + cipher.init (Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal (magic, 0, 8); + byte[] result = new byte [21]; + System.arraycopy (out1, 0, result, 0, 8); + System.arraycopy (out2, 0, result, 8, 8); + return result; + } catch (InvalidKeyException ive) { + // Will not happen, all key material are 8 bytes + assert false; + } catch (InvalidKeySpecException ikse) { + // Will not happen, we only feed DESKeySpec to DES factory + assert false; + } catch (IllegalBlockSizeException ibse) { + // Will not happen, we encrypt 8 bytes + assert false; + } catch (BadPaddingException bpe) { + // Will not happen, this is encryption + assert false; + } + return null; // will not happen, we returned already + } + + byte[] calcNTHash (byte[] pw) { + byte[] out = md4.digest (pw); + byte[] result = new byte [21]; + System.arraycopy (out, 0, result, 0, 16); + return result; + } + + /* key is a 21 byte array. Split it into 3 7 byte chunks, + * Convert each to 8 byte DES keys, encrypt the text arg with + * each key and return the three results in a sequential [] + */ + byte[] calcResponse (byte[] key, byte[] text) { + try { + assert key.length == 21; + DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0)); + DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7)); + DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14)); + SecretKey key1 = fac.generateSecret(dks1); + SecretKey key2 = fac.generateSecret(dks2); + SecretKey key3 = fac.generateSecret(dks3); + cipher.init(Cipher.ENCRYPT_MODE, key1); + byte[] out1 = cipher.doFinal(text, 0, 8); + cipher.init(Cipher.ENCRYPT_MODE, key2); + byte[] out2 = cipher.doFinal(text, 0, 8); + cipher.init(Cipher.ENCRYPT_MODE, key3); + byte[] out3 = cipher.doFinal(text, 0, 8); + byte[] result = new byte[24]; + System.arraycopy(out1, 0, result, 0, 8); + System.arraycopy(out2, 0, result, 8, 8); + System.arraycopy(out3, 0, result, 16, 8); + return result; + } catch (IllegalBlockSizeException ex) { // None will happen + assert false; + } catch (BadPaddingException ex) { + assert false; + } catch (InvalidKeySpecException ex) { + assert false; + } catch (InvalidKeyException ex) { + assert false; + } + return null; + } + + // LMv2/NTLMv2 + + byte[] hmacMD5(byte[] key, byte[] text) { + try { + SecretKeySpec skey = + new SecretKeySpec(Arrays.copyOf(key, 16), "HmacMD5"); + hmac.init(skey); + return hmac.doFinal(text); + } catch (InvalidKeyException ex) { + assert false; + } catch (RuntimeException e) { + assert false; + } + return null; + } + + byte[] calcV2(byte[] nthash, String text, byte[] blob, byte[] challenge) { + try { + byte[] ntlmv2hash = hmacMD5(nthash, + text.getBytes("UnicodeLittleUnmarked")); + byte[] cn = new byte[blob.length+8]; + System.arraycopy(challenge, 0, cn, 0, 8); + System.arraycopy(blob, 0, cn, 8, blob.length); + byte[] result = new byte[16+blob.length]; + System.arraycopy(hmacMD5(ntlmv2hash, cn), 0, result, 0, 16); + System.arraycopy(blob, 0, result, 16, blob.length); + return result; + } catch (UnsupportedEncodingException ex) { + assert false; + } + return null; + } + + // NTLM2 LM/NTLM + + static byte[] ntlm2LM(byte[] nonce) { + return Arrays.copyOf(nonce, 24); + } + + byte[] ntlm2NTLM(byte[] ntlmHash, byte[] nonce, byte[] challenge) { + byte[] b = Arrays.copyOf(challenge, 16); + System.arraycopy(nonce, 0, b, 8, 8); + byte[] sesshash = Arrays.copyOf(md5.digest(b), 8); + return calcResponse(ntlmHash, sesshash); + } + + // Password in ASCII and UNICODE + + static byte[] getP1(char[] password) { + try { + return new String(password).toUpperCase().getBytes("ISO8859_1"); + } catch (UnsupportedEncodingException ex) { + return null; + } + } + + static byte[] getP2(char[] password) { + try { + return new String(password).getBytes("UnicodeLittleUnmarked"); + } catch (UnsupportedEncodingException ex) { + return null; + } + } +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java b/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java new file mode 100644 index 00000000000..273825de8b7 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.ntlm; + +import java.security.GeneralSecurityException; + +/** + * An NTLM-related Exception + */ +public final class NTLMException extends GeneralSecurityException { + + /** + * If the incoming packet is invalid. + */ + public final static int PACKET_READ_ERROR = 1; + + /** + * If the client cannot get a domain value from the server and the + * caller has not provided one. + */ + public final static int NO_DOMAIN_INFO = 2; + + /** + * If the domain provided by the client does not match the one received + * from server. + */ + //public final static int DOMAIN_UNMATCH = 3; + + /** + * If the client name is not found on server's user database. + */ + public final static int USER_UNKNOWN = 3; + + /** + * If authentication fails. + */ + public final static int AUTH_FAILED = 4; + + /** + * If an illegal version string is provided. + */ + public final static int BAD_VERSION = 5; + + private int errorCode; + + /** + * Constructs an NTLMException object. + * @param errorCode the error code, which can be retrieved by + * the {@link #errorCode() } method. + * @param msg the string message, which can be retrived by + * the {@link Exception#getMessage() } method. + */ + public NTLMException(int errorCode, String msg) { + super(msg); + this.errorCode = errorCode; + } + + /** + * Returns the error code associated with this NTLMException. + * @return the error code + */ + public int errorCode() { + return errorCode; + } +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Server.java b/jdk/src/share/classes/com/sun/security/ntlm/Server.java new file mode 100644 index 00000000000..1871375a4b7 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Server.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.ntlm; + +import java.util.Arrays; +import java.util.Locale; + +/** + * The NTLM server, not multi-thread enabled.

+ * Example: + *

+ * Server server = new Server(null, "REALM") {
+ *     public char[] getPassword(String ntdomain, String username) {
+ *         switch (username) {
+ *             case "dummy": return "t0pSeCr3t".toCharArray();
+ *             case "guest": return "".toCharArray();
+ *             default: return null;
+ *         }
+ *     }
+ * };
+ * // Receive client request as type1
+ * byte[] type2 = server.type2(type1, nonce);
+ * // Send type2 to client and receive type3
+ * verify(type3, nonce);
+ * 
+ */ +public abstract class Server extends NTLM { + final private String domain; + final private boolean allVersion; + /** + * Creates a Server instance. + * @param version the NTLM version to use, which can be: + *
    + *
  • NTLM: Original NTLM v1 + *
  • NTLM2: NTLM v1 with Client Challenge + *
  • NTLMv2: NTLM v2 + *
+ * If null, all versions will be supported. Please note that unless NTLM2 + * is selected, authentication succeeds if one of LM (or LMv2) or + * NTLM (or NTLMv2) is verified. + * @param domain the domain, must not be null + * @throws NullPointerException if {@code domain} is null. + */ + public Server(String version, String domain) throws NTLMException { + super(version); + if (domain == null) { + throw new NullPointerException("domain cannot be null"); + } + this.allVersion = (version == null); + this.domain = domain; + debug("NTLM Server: (t,version) = (%s,%s)\n", domain, version); + } + + /** + * Generates the Type 2 message + * @param type1 the Type1 message received, must not be null + * @param nonce the random 8-byte array to be used in message generation, + * must not be null + * @return the message generated + * @throws NullPointerException if type1 or nonce is null + * @throws NTLMException if the incoming message is invalid + */ + public byte[] type2(byte[] type1, byte[] nonce) { + if (nonce == null) { + throw new NullPointerException("nonce cannot be null"); + } + debug("NTLM Server: Type 1 received\n"); + if (type1 != null) debug(type1); + Writer p = new Writer(2, 32); + int flags = 0x80205; + p.writeSecurityBuffer(12, domain, true); + p.writeInt(20, flags); + p.writeBytes(24, nonce); + debug("NTLM Server: Type 2 created\n"); + debug(p.getBytes()); + return p.getBytes(); + } + + /** + * Verifies the Type3 message received from client and returns + * various negotiated information. + * @param type3 the incoming Type3 message from client, must not be null + * @param nonce the same nonce provided in {@link #type2}, must not be null + * @return username and hostname of the client in a byte array + * @throws NullPointerException if {@code type3} or {@code nonce} is null + * @throws NTLMException if the incoming message is invalid + */ + public String[] verify(byte[] type3, byte[] nonce) + throws NTLMException { + if (type3 == null || nonce == null) { + throw new NullPointerException("type1 or nonce cannot be null"); + } + debug("NTLM Server: Type 3 received\n"); + if (type3 != null) debug(type3); + Reader r = new Reader(type3); + String username = r.readSecurityBuffer(36, true); + String hostname = r.readSecurityBuffer(44, true); + String incomingDomain = r.readSecurityBuffer(28, true); + /*if (incomingDomain != null && !incomingDomain.equals(domain)) { + throw new NTLMException(NTLMException.DOMAIN_UNMATCH, + "Wrong domain: " + incomingDomain + + " vs " + domain); // Needed? + }*/ + boolean verified = false; + char[] password = getPassword(domain, username); + if (password == null) { + throw new NTLMException(NTLMException.USER_UNKNOWN, + "Unknown user"); + } + byte[] incomingLM = r.readSecurityBuffer(12); + byte[] incomingNTLM = r.readSecurityBuffer(20); + + if (!verified && (allVersion || v == Version.NTLM)) { + if (incomingLM.length > 0) { + byte[] pw1 = getP1(password); + byte[] lmhash = calcLMHash(pw1); + byte[] lmresponse = calcResponse (lmhash, nonce); + if (Arrays.equals(lmresponse, incomingLM)) { + verified = true; + } + } + if (incomingNTLM.length > 0) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + byte[] ntresponse = calcResponse (nthash, nonce); + if (Arrays.equals(ntresponse, incomingNTLM)) { + verified = true; + } + } + debug("NTLM Server: verify using NTLM: " + verified + "\n"); + } + if (!verified && (allVersion || v == Version.NTLM2)) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + byte[] clientNonce = Arrays.copyOf(incomingLM, 8); + byte[] ntlmresponse = ntlm2NTLM(nthash, clientNonce, nonce); + if (Arrays.equals(incomingNTLM, ntlmresponse)) { + verified = true; + } + debug("NTLM Server: verify using NTLM2: " + verified + "\n"); + } + if (!verified && (allVersion || v == Version.NTLMv2)) { + byte[] pw2 = getP2(password); + byte[] nthash = calcNTHash(pw2); + if (incomingLM.length > 0) { + byte[] clientNonce = Arrays.copyOfRange( + incomingLM, 16, incomingLM.length); + byte[] lmresponse = calcV2(nthash, + username.toUpperCase(Locale.US)+incomingDomain, + clientNonce, nonce); + if (Arrays.equals(lmresponse, incomingLM)) { + verified = true; + } + } + if (incomingNTLM.length > 0) { + byte[] clientBlob = Arrays.copyOfRange( + incomingNTLM, 16, incomingNTLM.length); + byte[] ntlmresponse = calcV2(nthash, + username.toUpperCase(Locale.US)+incomingDomain, + clientBlob, nonce); + if (Arrays.equals(ntlmresponse, incomingNTLM)) { + verified = true; + } + } + debug("NTLM Server: verify using NTLMv2: " + verified + "\n"); + } + if (!verified) { + throw new NTLMException(NTLMException.AUTH_FAILED, + "None of LM and NTLM verified"); + } + return new String[] {username, hostname}; + } + + /** + * Retrieves the password for a given user. This method should be + * overridden in a concrete class. + * @param domain can be null + * @param username must not be null + * @return the password for the user, or null if unknown + */ + public abstract char[] getPassword(String domain, String username); +} diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Version.java b/jdk/src/share/classes/com/sun/security/ntlm/Version.java new file mode 100644 index 00000000000..bd4d0c4a07d --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/ntlm/Version.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.ntlm; + +enum Version { + NTLM, NTLM2, NTLMv2 +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/Provider.java b/jdk/src/share/classes/com/sun/security/sasl/Provider.java index 8e43d59f357..8b9c00c8800 100644 --- a/jdk/src/share/classes/com/sun/security/sasl/Provider.java +++ b/jdk/src/share/classes/com/sun/security/sasl/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -35,10 +35,12 @@ import java.security.PrivilegedAction; * - CRAM-MD5 * - DIGEST-MD5 * - GSSAPI/Kerberos v5 + * - NTLM * And server support for * - CRAM-MD5 * - DIGEST-MD5 * - GSSAPI/Kerberos v5 + * - NTLM */ public final class Provider extends java.security.Provider { @@ -47,8 +49,8 @@ public final class Provider extends java.security.Provider { private static final String info = "Sun SASL provider" + "(implements client mechanisms for: " + - "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5;" + - " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)"; + "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM;" + + " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)"; public Provider() { super("SunSASL", 1.7d, info); @@ -58,6 +60,8 @@ public final class Provider extends java.security.Provider { // Client mechanisms put("SaslClientFactory.DIGEST-MD5", "com.sun.security.sasl.digest.FactoryImpl"); + put("SaslClientFactory.NTLM", + "com.sun.security.sasl.ntlm.FactoryImpl"); put("SaslClientFactory.GSSAPI", "com.sun.security.sasl.gsskerb.FactoryImpl"); @@ -75,6 +79,8 @@ public final class Provider extends java.security.Provider { "com.sun.security.sasl.gsskerb.FactoryImpl"); put("SaslServerFactory.DIGEST-MD5", "com.sun.security.sasl.digest.FactoryImpl"); + put("SaslServerFactory.NTLM", + "com.sun.security.sasl.ntlm.FactoryImpl"); return null; } }); diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java new file mode 100644 index 00000000000..6ee1b66f968 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.sasl.ntlm; + +import java.util.Map; + +import javax.security.sasl.*; +import javax.security.auth.callback.CallbackHandler; + +import com.sun.security.sasl.util.PolicyUtils; + + +/** + * Client and server factory for NTLM SASL client/server mechanisms. + * See NTLMClient and NTLMServer for input requirements. + * + * @since 1.7 + */ + +public final class FactoryImpl implements SaslClientFactory, +SaslServerFactory{ + + private static final String myMechs[] = { "NTLM" }; + private static final int mechPolicies[] = { + PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS + }; + + /** + * Empty constructor. + */ + public FactoryImpl() { + } + + /** + * Returns a new instance of the NTLM SASL client mechanism. + * Argument checks are performed in SaslClient's constructor. + * @returns a new SaslClient ; otherwise null if unsuccessful. + * @throws SaslException If there is an error creating the NTLM + * SASL client. + */ + public SaslClient createSaslClient(String[] mechs, + String authorizationId, String protocol, String serverName, + Map props, CallbackHandler cbh) + throws SaslException { + + for (int i=0; i props, CallbackHandler cbh) + throws SaslException { + + if (mech.equals("NTLM") && + PolicyUtils.checkPolicy(mechPolicies[0], props)) { + if (props != null) { + String qop = (String)props.get(Sasl.QOP); + if (qop != null && !qop.equals("auth")) { + throw new SaslException("NTLM only support auth"); + } + } + if (cbh == null) { + throw new SaslException( + "Callback handler with support for AuthorizeCallback, "+ + "RealmCallback, NameCallback, and PasswordCallback " + + "required"); + } + return new NTLMServer(mech, protocol, serverName, props, cbh); + } + return null; + } + + /** + * Returns the authentication mechanisms that this factory can produce. + * + * @returns String[] {"NTLM"} if policies in env match those of this + * factory. + */ + public String[] getMechanismNames(Map env) { + return PolicyUtils.filterMechs(myMechs, mechPolicies, env); + } +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java new file mode 100644 index 00000000000..e5746675874 --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.sasl.ntlm; + +import com.sun.security.ntlm.Client; +import com.sun.security.ntlm.NTLMException; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; +import java.util.Random; +import javax.security.auth.callback.Callback; + + +import javax.security.sasl.*; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +/** + * Required callbacks: + * - RealmCallback + * handle can provide domain info for authentication, optional + * - NameCallback + * handler must enter username to use for authentication + * - PasswordCallback + * handler must enter password for username to use for authentication + * + * Environment properties that affect behavior of implementation: + * + * javax.security.sasl.qop + * String, quality of protection; only "auth" is accepted, default "auth" + * + * com.sun.security.sasl.ntlm.version + * String, name a specific version to use; can be: + * LM/NTLM: Original NTLM v1 + * LM: Original NTLM v1, LM only + * NTLM: Original NTLM v1, NTLM only + * NTLM2: NTLM v1 with Client Challenge + * LMv2/NTLMv2: NTLM v2 + * LMv2: NTLM v2, LM only + * NTLMv2: NTLM v2, NTLM only + * If not specified, use system property "ntlm.version". If + * still not specified, use default value "LMv2/NTLMv2". + * + * com.sun.security.sasl.ntlm.random + * java.util.Random, the nonce source to be used in NTLM v2 or NTLM v1 with + * Client Challenge. Default null, an internal java.util.Random object + * will be used + * + * Negotiated Properties: + * + * javax.security.sasl.qop + * Always "auth" + * + * com.sun.security.sasl.html.domain + * The domain for the user, provided by the server + * + * @see RFC 2222 + * - Simple Authentication and Security Layer (SASL) + * + */ +final class NTLMClient implements SaslClient { + + private static final String NTLM_VERSION = + "com.sun.security.sasl.ntlm.version"; + private static final String NTLM_RANDOM = + "com.sun.security.sasl.ntlm.random"; + private final static String NTLM_DOMAIN = + "com.sun.security.sasl.ntlm.domain"; + private final static String NTLM_HOSTNAME = + "com.sun.security.sasl.ntlm.hostname"; + + private final Client client; + private final String mech; + private final Random random; + + private int step = 0; // 0-start,1-nego,2-auth,3-done + + /** + * @param mech non-null + * @param authorizationId can be null or empty and ignored + * @param protocol non-null for Sasl, useless for NTLM + * @param serverName non-null for Sasl, but can be null for NTLM + * @param props can be null + * @param cbh can be null for Sasl, but will throw NPE for NTLM + * @throws SaslException + */ + NTLMClient(String mech, String authzid, String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException { + + this.mech = mech; + String version = null; + Random rtmp = null; + String hostname = null; + + if (props != null) { + String qop = (String)props.get(Sasl.QOP); + if (qop != null && !qop.equals("auth")) { + throw new SaslException("NTLM only support auth"); + } + version = (String)props.get(NTLM_VERSION); + rtmp = (Random)props.get(NTLM_RANDOM); + hostname = (String)props.get(NTLM_HOSTNAME); + } + this.random = rtmp != null ? rtmp : new Random(); + + if (version == null) { + version = System.getProperty("ntlm.version"); + } + + RealmCallback dcb = (serverName != null && !serverName.isEmpty())? + new RealmCallback("Realm: ", serverName) : + new RealmCallback("Realm: "); + NameCallback ncb = (authzid != null && !authzid.isEmpty()) ? + new NameCallback("User name: ", authzid) : + new NameCallback("User name: "); + PasswordCallback pcb = + new PasswordCallback("Password: ", false); + + try { + cbh.handle(new Callback[] {dcb, ncb, pcb}); + } catch (UnsupportedCallbackException e) { + throw new SaslException("NTLM: Cannot perform callback to " + + "acquire realm, username or password", e); + } catch (IOException e) { + throw new SaslException( + "NTLM: Error acquiring realm, username or password", e); + } + + if (hostname == null) { + try { + hostname = InetAddress.getLocalHost().getCanonicalHostName(); + } catch (UnknownHostException e) { + hostname = "localhost"; + } + } + try { + client = new Client(version, hostname, + ncb.getName(), + dcb.getText(), + pcb.getPassword()); + } catch (NTLMException ne) { + throw new SaslException( + "NTLM: Invalid version string: " + version, ne); + } + } + + @Override + public String getMechanismName() { + return mech; + } + + @Override + public boolean isComplete() { + return step >= 2; + } + + @Override + public byte[] unwrap(byte[] incoming, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public byte[] wrap(byte[] outgoing, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Object getNegotiatedProperty(String propName) { + if (propName.equals(Sasl.QOP)) { + return "auth"; + } else if (propName.equals(NTLM_DOMAIN)) { + return client.getDomain(); + } else { + return null; + } + } + + @Override + public void dispose() throws SaslException { + client.dispose(); + } + + @Override + public boolean hasInitialResponse() { + return true; + } + + @Override + public byte[] evaluateChallenge(byte[] challenge) throws SaslException { + step++; + if (step == 1) { + return client.type1(); + } else { + try { + byte[] nonce = new byte[8]; + random.nextBytes(nonce); + return client.type3(challenge, nonce); + } catch (NTLMException ex) { + throw new SaslException("Type3 creation failed", ex); + } + } + } +} diff --git a/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java new file mode 100644 index 00000000000..7adbeb7d37e --- /dev/null +++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.security.sasl.ntlm; + +import com.sun.security.ntlm.NTLMException; +import com.sun.security.ntlm.Server; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.Random; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.*; + +/** + * Required callbacks: + * - RealmCallback + * used as key by handler to fetch password, optional + * - NameCallback + * used as key by handler to fetch password + * - PasswordCallback + * handler must enter password for username/realm supplied + * + * Environment properties that affect the implementation: + * + * javax.security.sasl.qop + * String, quality of protection; only "auth" is accepted, default "auth" + * + * com.sun.security.sasl.ntlm.version + * String, name a specific version to accept: + * LM/NTLM: Original NTLM v1 + * LM: Original NTLM v1, LM only + * NTLM: Original NTLM v1, NTLM only + * NTLM2: NTLM v1 with Client Challenge + * LMv2/NTLMv2: NTLM v2 + * LMv2: NTLM v2, LM only + * NTLMv2: NTLM v2, NTLM only + * If not specified, use system property "ntlm.version". If also + * not specfied, all versions are accepted. + * + * com.sun.security.sasl.ntlm.domain + * String, the domain of the server, default is server name (fqdn parameter) + * + * com.sun.security.sasl.ntlm.random + * java.util.Random, the nonce source. Default null, an internal + * java.util.Random object will be used + * + * Negotiated Properties: + * + * javax.security.sasl.qop + * Always "auth" + * + * com.sun.security.sasl.ntlm.hostname + * The hostname for the user, provided by the client + * + */ + +final class NTLMServer implements SaslServer { + + private final static String NTLM_VERSION = + "com.sun.security.sasl.ntlm.version"; + private final static String NTLM_DOMAIN = + "com.sun.security.sasl.ntlm.domain"; + private final static String NTLM_HOSTNAME = + "com.sun.security.sasl.ntlm.hostname"; + private static final String NTLM_RANDOM = + "com.sun.security.sasl.ntlm.random"; + + private final Random random; + private final Server server; + private byte[] nonce; + private int step = 0; + private String authzId; + private final String mech; + private String hostname; + + /** + * @param mech not null + * @param protocol not null for Sasl, ignored in NTLM + * @param serverName not null for Sasl, can be null in NTLM. If non-null, + * might be used as domain if not provided in props + * @param props can be null + * @param cbh can be null for Sasl, but will throw NPE in auth for NTLM + * @throws SaslException + */ + NTLMServer(String mech, String protocol, String serverName, + Map props, final CallbackHandler cbh) throws SaslException { + + this.mech = mech; + String version = null; + String domain = null; + Random rtmp = null; + + if (props != null) { + domain = (String) props.get(NTLM_DOMAIN); + version = (String)props.get(NTLM_VERSION); + rtmp = (Random)props.get(NTLM_RANDOM); + } + random = rtmp != null ? rtmp : new Random(); + + if (version == null) { + version = System.getProperty("ntlm.version"); + } + if (domain == null) { + domain = serverName; + } + if (domain == null) { + throw new NullPointerException("Domain must be provided as" + + " the serverName argument or in props"); + } + + try { + server = new Server(version, domain) { + public char[] getPassword(String ntdomain, String username) { + try { + RealmCallback rcb = new RealmCallback( + "Domain: ", ntdomain); + NameCallback ncb = new NameCallback( + "Name: ", username); + PasswordCallback pcb = new PasswordCallback( + "Password: ", false); + cbh.handle(new Callback[] { rcb, ncb, pcb }); + char[] passwd = pcb.getPassword(); + pcb.clearPassword(); + return passwd; + } catch (IOException ioe) { + return null; + } catch (UnsupportedCallbackException uce) { + return null; + } + } + }; + } catch (NTLMException ne) { + throw new SaslException( + "NTLM: Invalid version string: " + version, ne); + } + nonce = new byte[8]; + } + + @Override + public String getMechanismName() { + return mech; + } + + @Override + public byte[] evaluateResponse(byte[] response) throws SaslException { + try { + step++; + if (step == 1) { + random.nextBytes(nonce); + return server.type2(response, nonce); + } else { + String[] out = server.verify(response, nonce); + authzId = out[0]; + hostname = out[1]; + return null; + } + } catch (GeneralSecurityException ex) { + throw new SaslException("", ex); + } + } + + @Override + public boolean isComplete() { + return step >= 2; + } + + @Override + public String getAuthorizationID() { + return authzId; + } + + @Override + public byte[] unwrap(byte[] incoming, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public byte[] wrap(byte[] outgoing, int offset, int len) + throws SaslException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getNegotiatedProperty(String propName) { + if (propName.equals(Sasl.QOP)) { + return "auth"; + } else if (propName.equals(NTLM_HOSTNAME)) { + return hostname; + } else { + return null; + } + } + + @Override + public void dispose() throws SaslException { + return; + } +} diff --git a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 0c8a5e28f4c..5ad8b8d54d8 100644 --- a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2010, 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 @@ -25,20 +25,14 @@ package sun.net.www.protocol.http.ntlm; +import com.sun.security.ntlm.Client; +import com.sun.security.ntlm.NTLMException; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.PasswordAuthentication; import java.net.UnknownHostException; import java.net.URL; import java.security.GeneralSecurityException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.DESKeySpec; import sun.net.www.HeaderParser; import sun.net.www.protocol.http.AuthenticationInfo; @@ -72,14 +66,8 @@ import sun.net.www.protocol.http.HttpURLConnection; */ public class NTLMAuthentication extends AuthenticationInfo { - private static final long serialVersionUID = -2403849171106437142L; + private static final long serialVersionUID = 170L; - private byte[] type1; - private byte[] type3; - - private SecretKeyFactory fac; - private Cipher cipher; - private MessageDigest md4; private String hostname; private static String defaultDomain; /* Domain to use if not specified by user */ @@ -94,53 +82,28 @@ public class NTLMAuthentication extends AuthenticationInfo { } private void init0() { - type1 = new byte[256]; - type3 = new byte[256]; - System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9); - type1[12] = (byte) 3; - type1[13] = (byte) 0xb2; - type1[28] = (byte) 0x20; - System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,3}, 0, type3, 0, 9); - type3[12] = (byte) 0x18; - type3[14] = (byte) 0x18; - type3[20] = (byte) 0x18; - type3[22] = (byte) 0x18; - type3[32] = (byte) 0x40; - type3[60] = (byte) 1; - type3[61] = (byte) 0x82; - try { - hostname = java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public String run() { - String localhost; - try { - localhost = InetAddress.getLocalHost().getHostName().toUpperCase(); - } catch (UnknownHostException e) { - localhost = "localhost"; - } - return localhost; + hostname = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public String run() { + String localhost; + try { + localhost = InetAddress.getLocalHost().getHostName().toUpperCase(); + } catch (UnknownHostException e) { + localhost = "localhost"; } - }); - int x = hostname.indexOf ('.'); - if (x != -1) { - hostname = hostname.substring (0, x); + return localhost; } - fac = SecretKeyFactory.getInstance ("DES"); - cipher = Cipher.getInstance ("DES/ECB/NoPadding"); - md4 = sun.security.provider.MD4.getInstance(); - } catch (NoSuchPaddingException e) { - assert false; - } catch (NoSuchAlgorithmException e) { - assert false; + }); + int x = hostname.indexOf ('.'); + if (x != -1) { + hostname = hostname.substring (0, x); } }; PasswordAuthentication pw; - String username; - String ntdomain; - String password; + Client client; /** * Create a NTLMAuthentication: * Username may be specified as domainusername in the application Authenticator. @@ -156,6 +119,9 @@ public class NTLMAuthentication extends AuthenticationInfo { } private void init (PasswordAuthentication pw) { + String username; + String ntdomain; + char[] password; this.pw = pw; String s = pw.getUserName(); int i = s.indexOf ('\\'); @@ -166,8 +132,19 @@ public class NTLMAuthentication extends AuthenticationInfo { ntdomain = s.substring (0, i).toUpperCase(); username = s.substring (i+1); } - password = new String (pw.getPassword()); + password = pw.getPassword(); init0(); + try { + client = new Client(System.getProperty("ntlm.version"), hostname, + username, ntdomain, password); + } catch (NTLMException ne) { + try { + client = new Client(null, hostname, username, ntdomain, password); + } catch (NTLMException ne2) { + // Will never happen + throw new AssertionError("Really?"); + } + } } /** @@ -240,181 +217,26 @@ public class NTLMAuthentication extends AuthenticationInfo { } } - private void copybytes (byte[] dest, int destpos, String src, String enc) { - try { - byte[] x = src.getBytes(enc); - System.arraycopy (x, 0, dest, destpos, x.length); - } catch (UnsupportedEncodingException e) { - assert false; - } - } - private String buildType1Msg () { - int dlen = ntdomain.length(); - type1[16]= (byte) (dlen % 256); - type1[17]= (byte) (dlen / 256); - type1[18] = type1[16]; - type1[19] = type1[17]; - - int hlen = hostname.length(); - type1[24]= (byte) (hlen % 256); - type1[25]= (byte) (hlen / 256); - type1[26] = type1[24]; - type1[27] = type1[25]; - - copybytes (type1, 32, hostname, "ISO8859_1"); - copybytes (type1, hlen+32, ntdomain, "ISO8859_1"); - type1[20] = (byte) ((hlen+32) % 256); - type1[21] = (byte) ((hlen+32) / 256); - - byte[] msg = new byte [32 + hlen + dlen]; - System.arraycopy (type1, 0, msg, 0, 32 + hlen + dlen); + byte[] msg = client.type1(); String result = "NTLM " + (new B64Encoder()).encode (msg); return result; } - - /* Convert a 7 byte array to an 8 byte array (for a des key with parity) - * input starts at offset off - */ - private byte[] makeDesKey (byte[] input, int off) { - int[] in = new int [input.length]; - for (int i=0; i> 1)); - out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2)); - out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3)); - out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4)); - out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5)); - out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6)); - out[7] = (byte)((in[off+6] << 1) & 0xFF); - return out; - } - - private byte[] calcLMHash () throws GeneralSecurityException { - byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; - byte[] pwb = password.toUpperCase ().getBytes(); - byte[] pwb1 = new byte [14]; - int len = password.length(); - if (len > 14) - len = 14; - System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */ - - DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0)); - DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7)); - - SecretKey key1 = fac.generateSecret (dks1); - SecretKey key2 = fac.generateSecret (dks2); - cipher.init (Cipher.ENCRYPT_MODE, key1); - byte[] out1 = cipher.doFinal (magic, 0, 8); - cipher.init (Cipher.ENCRYPT_MODE, key2); - byte[] out2 = cipher.doFinal (magic, 0, 8); - - byte[] result = new byte [21]; - System.arraycopy (out1, 0, result, 0, 8); - System.arraycopy (out2, 0, result, 8, 8); - return result; - } - - private byte[] calcNTHash () throws GeneralSecurityException { - byte[] pw = null; - try { - pw = password.getBytes ("UnicodeLittleUnmarked"); - } catch (UnsupportedEncodingException e) { - assert false; - } - byte[] out = md4.digest (pw); - byte[] result = new byte [21]; - System.arraycopy (out, 0, result, 0, 16); - return result; - } - - /* key is a 21 byte array. Split it into 3 7 byte chunks, - * Convert each to 8 byte DES keys, encrypt the text arg with - * each key and return the three results in a sequential [] - */ - private byte[] calcResponse (byte[] key, byte[] text) - throws GeneralSecurityException { - assert key.length == 21; - DESKeySpec dks1 = new DESKeySpec (makeDesKey (key, 0)); - DESKeySpec dks2 = new DESKeySpec (makeDesKey (key, 7)); - DESKeySpec dks3 = new DESKeySpec (makeDesKey (key, 14)); - SecretKey key1 = fac.generateSecret (dks1); - SecretKey key2 = fac.generateSecret (dks2); - SecretKey key3 = fac.generateSecret (dks3); - cipher.init (Cipher.ENCRYPT_MODE, key1); - byte[] out1 = cipher.doFinal (text, 0, 8); - cipher.init (Cipher.ENCRYPT_MODE, key2); - byte[] out2 = cipher.doFinal (text, 0, 8); - cipher.init (Cipher.ENCRYPT_MODE, key3); - byte[] out3 = cipher.doFinal (text, 0, 8); - byte[] result = new byte [24]; - System.arraycopy (out1, 0, result, 0, 8); - System.arraycopy (out2, 0, result, 8, 8); - System.arraycopy (out3, 0, result, 16, 8); - return result; - } - private String buildType3Msg (String challenge) throws GeneralSecurityException, IOException { /* First decode the type2 message to get the server nonce */ /* nonce is located at type2[24] for 8 bytes */ byte[] type2 = (new sun.misc.BASE64Decoder()).decodeBuffer (challenge); - byte[] nonce = new byte [8]; - System.arraycopy (type2, 24, nonce, 0, 8); - - int ulen = username.length()*2; - type3[36] = type3[38] = (byte) (ulen % 256); - type3[37] = type3[39] = (byte) (ulen / 256); - int dlen = ntdomain.length()*2; - type3[28] = type3[30] = (byte) (dlen % 256); - type3[29] = type3[31] = (byte) (dlen / 256); - int hlen = hostname.length()*2; - type3[44] = type3[46] = (byte) (hlen % 256); - type3[45] = type3[47] = (byte) (hlen / 256); - - int l = 64; - copybytes (type3, l, ntdomain, "UnicodeLittleUnmarked"); - type3[32] = (byte) (l % 256); - type3[33] = (byte) (l / 256); - l += dlen; - copybytes (type3, l, username, "UnicodeLittleUnmarked"); - type3[40] = (byte) (l % 256); - type3[41] = (byte) (l / 256); - l += ulen; - copybytes (type3, l, hostname, "UnicodeLittleUnmarked"); - type3[48] = (byte) (l % 256); - type3[49] = (byte) (l / 256); - l += hlen; - - byte[] lmhash = calcLMHash(); - byte[] lmresponse = calcResponse (lmhash, nonce); - byte[] nthash = calcNTHash(); - byte[] ntresponse = calcResponse (nthash, nonce); - System.arraycopy (lmresponse, 0, type3, l, 24); - type3[16] = (byte) (l % 256); - type3[17] = (byte) (l / 256); - l += 24; - System.arraycopy (ntresponse, 0, type3, l, 24); - type3[24] = (byte) (l % 256); - type3[25] = (byte) (l / 256); - l += 24; - type3[56] = (byte) (l % 256); - type3[57] = (byte) (l / 256); - - byte[] msg = new byte [l]; - System.arraycopy (type3, 0, msg, 0, l); + byte[] nonce = new byte[8]; + new java.util.Random().nextBytes(nonce); + byte[] msg = client.type3(type2, nonce); String result = "NTLM " + (new B64Encoder()).encode (msg); return result; } - } - class B64Encoder extends sun.misc.BASE64Encoder { /* to force it to to the entire encoding in one line */ protected int bytesPerLine () { diff --git a/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java b/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java new file mode 100644 index 00000000000..64a5f8e54e2 --- /dev/null +++ b/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2010, 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. + * + * 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. + */ + +/* + * @test + * @bug 6911951 + * @summary NTLM should be a supported Java SASL mechanism + */ +import java.io.IOException; +import javax.security.sasl.*; +import javax.security.auth.callback.*; +import java.util.*; + +import com.sun.security.ntlm.NTLMException; + +public class NTLMTest { + + private static final String MECH = "NTLM"; + private static final String REALM = "REALM"; + private static final String PROTOCOL = "jmx"; + private static final byte[] EMPTY = new byte[0]; + + private static final String USER1 = "dummy"; + private static final char[] PASS1 = "bogus".toCharArray(); + private static final String USER2 = "foo"; + private static final char[] PASS2 = "bar".toCharArray(); + + private static final Map maps = + new HashMap(); + static { + maps.put(USER1, PASS1); + maps.put(USER2, PASS2); + } + + static char[] getPass(String d, String u) { + if (!d.equals(REALM)) return null; + return maps.get(u); + } + + public static void main(String[] args) throws Exception { + + checkAuthOnly(); + checkClientNameOverride(); + checkServerDomainOverride(); + checkClientDomainOverride(); + checkVersions(); + checkClientHostname(); + } + + static void checkVersions() throws Exception { + // Server accepts all version + checkVersion(null, null); + checkVersion("LM/NTLM", null); + checkVersion("LM", null); + checkVersion("NTLM", null); + checkVersion("NTLM2", null); + checkVersion("LMv2/NTLMv2", null); + checkVersion("LMv2", null); + checkVersion("NTLMv2", null); + + // Client's default version is LMv2 + checkVersion(null, "LMv2"); + + // Also works if they specified identical versions + checkVersion("LM/NTLM", "LM"); + checkVersion("LM", "LM"); + checkVersion("NTLM", "LM"); + checkVersion("NTLM2", "NTLM2"); + checkVersion("LMv2/NTLMv2", "LMv2"); + checkVersion("LMv2", "LMv2"); + checkVersion("NTLMv2", "LMv2"); + + // But should not work if different + try { + checkVersion("LM/NTLM", "LMv2"); + throw new Exception("Should not succeed"); + } catch (SaslException se) { + NTLMException ne = (NTLMException)se.getCause(); + if (ne.errorCode() != NTLMException.AUTH_FAILED) { + throw new Exception("Failed false"); + } + } + try { + checkVersion("LMv2/NTLMv2", "LM"); + throw new Exception("Should not succeed"); + } catch (SaslException se) { + NTLMException ne = (NTLMException)se.getCause(); + if (ne.errorCode() != NTLMException.AUTH_FAILED) { + throw new Exception("Failed false"); + } + } + + } + + /** + * A test on version matching + * @param vc ntlm version specified for client + * @param vs ntlm version specified for server + * @throws Exception + */ + private static void checkVersion(String vc, String vs) throws Exception { + Map pc = new HashMap<>(); + pc.put("com.sun.security.sasl.ntlm.version", vc); + Map ps = new HashMap<>(); + ps.put("com.sun.security.sasl.ntlm.version", vs); + SaslClient clnt = Sasl.createSaslClient( + new String[]{MECH}, USER1, PROTOCOL, null, pc, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + NameCallback ncb = (NameCallback)cb; + ncb.setName(ncb.getDefaultName()); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(PASS1); + } + } + } + }); + + SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, ps, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + String domain = null, name = null; + PasswordCallback pcb = null; + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + name = ((NameCallback)cb).getDefaultName(); + } else if (cb instanceof RealmCallback) { + domain = ((RealmCallback)cb).getDefaultText(); + } else if (cb instanceof PasswordCallback) { + pcb = (PasswordCallback)cb; + } + } + if (pcb != null) { + pcb.setPassword(getPass(domain, name)); + } + } + }); + + handshake(clnt, srv); + } + + private static void checkClientHostname() throws Exception { + Map pc = new HashMap<>(); + pc.put("com.sun.security.sasl.ntlm.hostname", "this.is.com"); + SaslClient clnt = Sasl.createSaslClient( + new String[]{MECH}, USER1, PROTOCOL, null, pc, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + NameCallback ncb = (NameCallback)cb; + ncb.setName(ncb.getDefaultName()); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(PASS1); + } + } + } + }); + + SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + String domain = null, name = null; + PasswordCallback pcb = null; + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + name = ((NameCallback)cb).getDefaultName(); + } else if (cb instanceof RealmCallback) { + domain = ((RealmCallback)cb).getDefaultText(); + } else if (cb instanceof PasswordCallback) { + pcb = (PasswordCallback)cb; + } + } + if (pcb != null) { + pcb.setPassword(getPass(domain, name)); + } + } + }); + + handshake(clnt, srv); + if (!"this.is.com".equals( + srv.getNegotiatedProperty("com.sun.security.sasl.ntlm.hostname"))) { + throw new Exception("Hostname not trasmitted to server"); + } + } + + /** + * Client realm override, but finally overridden by server response + */ + private static void checkClientDomainOverride() throws Exception { + SaslClient clnt = Sasl.createSaslClient( + new String[]{MECH}, USER1, PROTOCOL, "ANOTHERREALM", null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + NameCallback ncb = (NameCallback)cb; + ncb.setName(ncb.getDefaultName()); + } else if(cb instanceof RealmCallback) { + RealmCallback dcb = (RealmCallback)cb; + dcb.setText("THIRDDOMAIN"); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(PASS1); + } + } + } + }); + + SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + String domain = null, name = null; + PasswordCallback pcb = null; + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + name = ((NameCallback)cb).getDefaultName(); + } else if (cb instanceof RealmCallback) { + domain = ((RealmCallback)cb).getDefaultText(); + } else if (cb instanceof PasswordCallback) { + pcb = (PasswordCallback)cb; + } + } + if (pcb != null) { + pcb.setPassword(getPass(domain, name)); + } + } + }); + + handshake(clnt, srv); + } + + /** + * Client side user name provided in callback. + * @throws Exception + */ + private static void checkClientNameOverride() throws Exception { + SaslClient clnt = Sasl.createSaslClient( + new String[]{MECH}, null, PROTOCOL, null, null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + NameCallback ncb = (NameCallback)cb; + ncb.setName(USER1); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(PASS1); + } + } + } + }); + + SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + String domain = null, name = null; + PasswordCallback pcb = null; + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + name = ((NameCallback)cb).getDefaultName(); + } else if (cb instanceof RealmCallback) { + domain = ((RealmCallback)cb).getDefaultText(); + } else if (cb instanceof PasswordCallback) { + pcb = (PasswordCallback)cb; + } + } + if (pcb != null) { + pcb.setPassword(getPass(domain, name)); + } + } + }); + + handshake(clnt, srv); + } + + /** + * server side domain provided in props. + * @throws Exception + */ + private static void checkServerDomainOverride() throws Exception { + SaslClient clnt = Sasl.createSaslClient( + new String[]{MECH}, USER1, PROTOCOL, null, null, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + NameCallback ncb = (NameCallback)cb; + ncb.setName(ncb.getDefaultName()); + } else if (cb instanceof PasswordCallback) { + ((PasswordCallback)cb).setPassword(PASS1); + } + } + } + }); + + Map ps = new HashMap<>(); + ps.put("com.sun.security.sasl.ntlm.domain", REALM); + SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, null, ps, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + String domain = null, name = null; + PasswordCallback pcb = null; + for (Callback cb: callbacks) { + if (cb instanceof NameCallback) { + name = ((NameCallback)cb).getDefaultName(); + } else if (cb instanceof RealmCallback) { + domain = ((RealmCallback)cb).getDefaultText(); + } else if (cb instanceof PasswordCallback) { + pcb = (PasswordCallback)cb; + } + } + if (pcb != null) { + pcb.setPassword(getPass(domain, name)); + } + } + }); + + handshake(clnt, srv); + } + + private static void checkAuthOnly() throws Exception { + Map props = new HashMap<>(); + props.put(Sasl.QOP, "auth-conf"); + try { + Sasl.createSaslClient( + new String[]{MECH}, USER2, PROTOCOL, REALM, props, null); + throw new Exception("NTLM should not support auth-conf"); + } catch (SaslException se) { + // Normal + } + } + + private static void handshake(SaslClient clnt, SaslServer srv) + throws Exception { + if (clnt == null) { + throw new IllegalStateException( + "Unable to find client impl for " + MECH); + } + if (srv == null) { + throw new IllegalStateException( + "Unable to find server impl for " + MECH); + } + + byte[] response = (clnt.hasInitialResponse() + ? clnt.evaluateChallenge(EMPTY) : EMPTY); + System.out.println("Initial:"); + new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out); + byte[] challenge; + + while (!clnt.isComplete() || !srv.isComplete()) { + challenge = srv.evaluateResponse(response); + response = null; + if (challenge != null) { + System.out.println("Challenge:"); + new sun.misc.HexDumpEncoder().encodeBuffer(challenge, System.out); + response = clnt.evaluateChallenge(challenge); + } + if (response != null) { + System.out.println("Response:"); + new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out); + } + } + + if (clnt.isComplete() && srv.isComplete()) { + System.out.println("SUCCESS"); + if (!srv.getAuthorizationID().equals(USER1)) { + throw new Exception("Not correct user"); + } + } else { + throw new IllegalStateException( + "FAILURE: mismatched state:" + + " client complete? " + clnt.isComplete() + + " server complete? " + srv.isComplete()); + } + + if (!clnt.getNegotiatedProperty(Sasl.QOP).equals("auth") || + !srv.getNegotiatedProperty(Sasl.QOP).equals("auth") || + !clnt.getNegotiatedProperty( + "com.sun.security.sasl.ntlm.domain").equals(REALM)) { + throw new Exception("Negotiated property error"); + } + clnt.dispose(); + srv.dispose(); + } +} From c8f3efcc756d414ffc5997a52a4b9302cd5d5fd5 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 31 Aug 2010 09:15:34 -0700 Subject: [PATCH 04/27] 6981005: TEST BUG: java/lang/ClassLoader/TestCrossDelegate.sh timeout on windows Increase timeout value Reviewed-by: alanb --- jdk/test/ProblemList.txt | 3 --- .../ClassLoader/deadlock/TestCrossDelegate.sh | 17 +++++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index ab70ed9deeb..831b3a190e6 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -201,9 +201,6 @@ java/lang/ThreadLocal/MemoryLeak.java solaris-all # Windows X64, RuntimeException: MyThread expected to have RUNNABLE but got WAITING java/lang/Thread/ThreadStateTest.java generic-all -# Timeout on windows 64bit -java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all - ############################################################################ # jdk_management diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh index 71e07441ce2..1c7d5657423 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh @@ -25,7 +25,7 @@ # @summary (cl) ClassLoader.loadClass locks all instances in chain # when delegating # -# @run shell/timeout=10 TestCrossDelegate.sh +# @run shell/timeout=300 TestCrossDelegate.sh # if running by hand on windows, change TESTSRC and TESTCLASSES to "." if [ "${TESTSRC}" = "" ] ; then @@ -41,10 +41,6 @@ if [ "${TESTJAVA}" = "" ] ; then echo "FAILED!!!" exit 1 fi -echo TESTSRC=${TESTSRC} -echo TESTCLASSES=${TESTCLASSES} -echo TESTJAVA=${TESTJAVA} -echo "" # set platform-specific variables OS=`uname -s` @@ -55,11 +51,20 @@ case "$OS" in Linux ) FS="/" ;; - Windows* | CYGWIN* ) + Windows*) FS="\\" ;; + CYGWIN* ) + FS="\\" + TESTCLASSES=`/usr/bin/cygpath -a -s -m ${TESTCLASSES}` + ;; esac +echo TESTSRC=${TESTSRC} +echo TESTCLASSES=${TESTCLASSES} +echo TESTJAVA=${TESTJAVA} +echo "" + # compile test ${TESTJAVA}${FS}bin${FS}javac \ -d ${TESTCLASSES} \ From 2aa1723b3999868f589005e5fdd6455a1f1f77b1 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Tue, 31 Aug 2010 09:17:46 -0700 Subject: [PATCH 05/27] 6977548: Broken link in ClassLoader.defineClass javadoc Reviewed-by: valeriep --- jdk/src/share/classes/java/lang/ClassLoader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java index d3346417c0f..fd9ba91d720 100644 --- a/jdk/src/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/share/classes/java/lang/ClassLoader.java @@ -823,7 +823,7 @@ public abstract class ClassLoader { * * * @param name - * The expected binary namebinary name. of the class, or * null if not known * * @param b From 080f83060e5c21cc480dff7cd2d4ee0dcc4155c6 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Wed, 1 Sep 2010 09:45:08 -0700 Subject: [PATCH 06/27] 6981145: (se) Eliminate JNI*Critical when creating pipes and other cleanups Avoid *Critical; fix compile warnings; improve readability Reviewed-by: alanb --- jdk/make/java/nio/mapfile-linux | 2 +- jdk/make/java/nio/mapfile-solaris | 2 +- jdk/src/share/classes/sun/nio/ch/IOUtil.java | 7 ++- .../sun/nio/ch/DevPollSelectorImpl.java | 9 ++- .../classes/sun/nio/ch/EPollSelectorImpl.java | 9 ++- .../solaris/classes/sun/nio/ch/PipeImpl.java | 9 +-- .../classes/sun/nio/ch/PollSelectorImpl.java | 7 +-- jdk/src/solaris/native/sun/nio/ch/IOUtil.c | 63 +++++++++---------- 8 files changed, 54 insertions(+), 54 deletions(-) diff --git a/jdk/make/java/nio/mapfile-linux b/jdk/make/java/nio/mapfile-linux index 13cc1cd01ec..c3645c5ed05 100644 --- a/jdk/make/java/nio/mapfile-linux +++ b/jdk/make/java/nio/mapfile-linux @@ -89,7 +89,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_IOUtil_drain; Java_sun_nio_ch_IOUtil_fdVal; Java_sun_nio_ch_IOUtil_initIDs; - Java_sun_nio_ch_IOUtil_initPipe; + Java_sun_nio_ch_IOUtil_makePipe; Java_sun_nio_ch_IOUtil_randomBytes; Java_sun_nio_ch_IOUtil_setfdVal; Java_sun_nio_ch_NativeThread_current; diff --git a/jdk/make/java/nio/mapfile-solaris b/jdk/make/java/nio/mapfile-solaris index 2b80e4e801e..e0dff0a32f3 100644 --- a/jdk/make/java/nio/mapfile-solaris +++ b/jdk/make/java/nio/mapfile-solaris @@ -76,7 +76,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_IOUtil_drain; Java_sun_nio_ch_IOUtil_fdVal; Java_sun_nio_ch_IOUtil_initIDs; - Java_sun_nio_ch_IOUtil_initPipe; + Java_sun_nio_ch_IOUtil_makePipe; Java_sun_nio_ch_IOUtil_randomBytes; Java_sun_nio_ch_IOUtil_setfdVal; Java_sun_nio_ch_NativeThread_current; diff --git a/jdk/src/share/classes/sun/nio/ch/IOUtil.java b/jdk/src/share/classes/sun/nio/ch/IOUtil.java index 86acff63566..97c8dca92b0 100644 --- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java @@ -319,7 +319,12 @@ class IOUtil { static native boolean randomBytes(byte[] someBytes); - static native void initPipe(int[] fda, boolean blocking); + /** + * Returns two file descriptors for a pipe encoded in a long. + * The read end of the pipe is returned in the high 32 bits, + * while the write end is returned in the low 32 bits. + */ + static native long makePipe(boolean blocking); static native boolean drain(int fd) throws IOException; diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java index 9cecedd8394..fd2538f90da 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java @@ -65,10 +65,9 @@ class DevPollSelectorImpl */ DevPollSelectorImpl(SelectorProvider sp) { super(sp); - int[] fdes = new int[2]; - IOUtil.initPipe(fdes, false); - fd0 = fdes[0]; - fd1 = fdes[1]; + long pipeFds = IOUtil.makePipe(false); + fd0 = (int) (pipeFds >>> 32); + fd1 = (int) pipeFds; pollWrapper = new DevPollArrayWrapper(); pollWrapper.initInterrupt(fd0, fd1); fdToKey = new HashMap(); @@ -147,7 +146,7 @@ class DevPollSelectorImpl selectedKeys = null; // Deregister channels - Iterator i = keys.iterator(); + Iterator i = keys.iterator(); while (i.hasNext()) { SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); deregister(ski); diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java index f631266955e..7881fe56a31 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java @@ -62,10 +62,9 @@ class EPollSelectorImpl */ EPollSelectorImpl(SelectorProvider sp) { super(sp); - int[] fdes = new int[2]; - IOUtil.initPipe(fdes, false); - fd0 = fdes[0]; - fd1 = fdes[1]; + long pipeFds = IOUtil.makePipe(false); + fd0 = (int) (pipeFds >>> 32); + fd1 = (int) pipeFds; pollWrapper = new EPollArrayWrapper(); pollWrapper.initInterrupt(fd0, fd1); fdToKey = new HashMap(); @@ -144,7 +143,7 @@ class EPollSelectorImpl selectedKeys = null; // Deregister channels - Iterator i = keys.iterator(); + Iterator i = keys.iterator(); while (i.hasNext()) { SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); deregister(ski); diff --git a/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java b/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java index 3aece1209dd..0e2852b95a1 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java @@ -39,13 +39,14 @@ class PipeImpl private final SinkChannel sink; PipeImpl(SelectorProvider sp) { - int[] fdes = new int[2]; - IOUtil.initPipe(fdes, true); + long pipeFds = IOUtil.makePipe(true); + int readFd = (int) (pipeFds >>> 32); + int writeFd = (int) pipeFds; FileDescriptor sourcefd = new FileDescriptor(); - IOUtil.setfdVal(sourcefd, fdes[0]); + IOUtil.setfdVal(sourcefd, readFd); source = new SourceChannelImpl(sp, sourcefd); FileDescriptor sinkfd = new FileDescriptor(); - IOUtil.setfdVal(sinkfd, fdes[1]); + IOUtil.setfdVal(sinkfd, writeFd); sink = new SinkChannelImpl(sp, sinkfd); } diff --git a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java index 0709d43c6a0..2a776e16a4d 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java +++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java @@ -54,10 +54,9 @@ class PollSelectorImpl */ PollSelectorImpl(SelectorProvider sp) { super(sp, 1, 1); - int[] fdes = new int[2]; - IOUtil.initPipe(fdes, false); - fd0 = fdes[0]; - fd1 = fdes[1]; + long pipeFds = IOUtil.makePipe(false); + fd0 = (int) (pipeFds >>> 32); + fd1 = (int) pipeFds; pollWrapper = new PollArrayWrapper(INIT_CAP); pollWrapper.initInterrupt(fd0, fd1); channelArray = new SelectionKeyImpl[INIT_CAP]; diff --git a/jdk/src/solaris/native/sun/nio/ch/IOUtil.c b/jdk/src/solaris/native/sun/nio/ch/IOUtil.c index 2ade52e6d17..455878f5d40 100644 --- a/jdk/src/solaris/native/sun/nio/ch/IOUtil.c +++ b/jdk/src/solaris/native/sun/nio/ch/IOUtil.c @@ -67,12 +67,9 @@ static int configureBlocking(int fd, jboolean blocking) { int flags = fcntl(fd, F_GETFL); + int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); - if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK)) - return fcntl(fd, F_SETFL, flags | O_NONBLOCK); - else if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK)) - return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); - return 0; + return (flags == newflags) ? 0 : fcntl(fd, F_SETFL, newflags); } JNIEXPORT void JNICALL @@ -83,27 +80,25 @@ Java_sun_nio_ch_IOUtil_configureBlocking(JNIEnv *env, jclass clazz, JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); } -JNIEXPORT void JNICALL -Java_sun_nio_ch_IOUtil_initPipe(JNIEnv *env, jobject this, - jintArray intArray, jboolean block) +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_IOUtil_makePipe(JNIEnv *env, jobject this, jboolean blocking) { int fd[2]; - jint *ptr = 0; if (pipe(fd) < 0) { JNU_ThrowIOExceptionWithLastError(env, "Pipe failed"); - return; + return 0; } - if (block == JNI_FALSE) { + if (blocking == JNI_FALSE) { if ((configureBlocking(fd[0], JNI_FALSE) < 0) || (configureBlocking(fd[1], JNI_FALSE) < 0)) { JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed"); + close(fd[0]); + close(fd[1]); + return 0; } } - ptr = (*env)->GetPrimitiveArrayCritical(env, intArray, 0); - ptr[0] = fd[0]; - ptr[1] = fd[1]; - (*env)->ReleasePrimitiveArrayCritical(env, intArray, ptr, 0); + return ((jlong) fd[0] << 32) | (jlong) fd[1]; } JNIEXPORT jboolean JNICALL @@ -131,21 +126,22 @@ convertReturnVal(JNIEnv *env, jint n, jboolean reading) { if (n > 0) /* Number of bytes written */ return n; - if (n < 0) { - if (errno == EAGAIN) - return IOS_UNAVAILABLE; - if (errno == EINTR) - return IOS_INTERRUPTED; - } - if (n == 0) { + else if (n == 0) { if (reading) { return IOS_EOF; /* EOF is -1 in javaland */ } else { return 0; } } - JNU_ThrowIOExceptionWithLastError(env, "Read/write failed"); - return IOS_THROWN; + else if (errno == EAGAIN) + return IOS_UNAVAILABLE; + else if (errno == EINTR) + return IOS_INTERRUPTED; + else { + const char *msg = reading ? "Read failed" : "Write failed"; + JNU_ThrowIOExceptionWithLastError(env, msg); + return IOS_THROWN; + } } /* Declared in nio_util.h for use elsewhere in NIO */ @@ -155,21 +151,22 @@ convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading) { if (n > 0) /* Number of bytes written */ return n; - if (n < 0) { - if (errno == EAGAIN) - return IOS_UNAVAILABLE; - if (errno == EINTR) - return IOS_INTERRUPTED; - } - if (n == 0) { + else if (n == 0) { if (reading) { return IOS_EOF; /* EOF is -1 in javaland */ } else { return 0; } } - JNU_ThrowIOExceptionWithLastError(env, "Read/write failed"); - return IOS_THROWN; + else if (errno == EAGAIN) + return IOS_UNAVAILABLE; + else if (errno == EINTR) + return IOS_INTERRUPTED; + else { + const char *msg = reading ? "Read failed" : "Write failed"; + JNU_ThrowIOExceptionWithLastError(env, msg); + return IOS_THROWN; + } } jint From 1cef1a3806b9d2a6cd33b745bbf0b1256be68643 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Wed, 1 Sep 2010 17:37:45 -0700 Subject: [PATCH 07/27] 6977887: (doc) Java 6 API missing info about encoding parameter in storeToXML method Reviewed-by: sherman --- jdk/src/share/classes/java/util/Properties.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/java/util/Properties.java b/jdk/src/share/classes/java/util/Properties.java index 4012f2f5e6c..6f9c562e4f8 100644 --- a/jdk/src/share/classes/java/util/Properties.java +++ b/jdk/src/share/classes/java/util/Properties.java @@ -912,9 +912,13 @@ class Properties extends Hashtable { * *

The specified stream remains open after this method returns. * - * @param os the output stream on which to emit the XML document. - * @param comment a description of the property list, or null - * if no comment is desired. + * @param os the output stream on which to emit the XML document. + * @param comment a description of the property list, or null + * if no comment is desired. + * @param encoding the name of a supported + * + * character encoding + * * @throws IOException if writing to the specified output stream * results in an IOException. * @throws NullPointerException if os is null, From 2fdbbbae4e3d2dca9b786a506269ee14bde2f6f9 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 3 Sep 2010 13:11:54 +0100 Subject: [PATCH 08/27] 6965072: Need API to create SDP sockets Reviewed-by: michaelm --- jdk/make/com/Makefile | 2 +- jdk/make/com/oracle/Makefile | 34 +++ jdk/make/com/oracle/net/Makefile | 39 ++++ jdk/make/docs/NON_CORE_PKGS.gmk | 5 +- jdk/make/java/net/FILES_c.gmk | 4 - jdk/make/java/net/Makefile | 5 +- jdk/make/java/net/mapfile-vers | 3 +- jdk/make/java/nio/FILES_java.gmk | 1 + jdk/make/sun/net/FILES_java.gmk | 7 +- jdk/src/share/classes/com/oracle/net/Sdp.java | 201 ++++++++++++++++++ .../share/classes/java/net/SdpSocketImpl.java | 49 +++++ .../share/classes/java/net/ServerSocket.java | 9 + .../share/classes/sun/net/sdp/SdpSupport.java | 81 +++++++ jdk/src/share/classes/sun/nio/ch/Secrets.java | 63 ++++++ .../sun/nio/ch/ServerSocketChannelImpl.java | 9 +- .../classes/sun/nio/ch/SocketChannelImpl.java | 13 ++ jdk/src/solaris/classes/sun/net/NetHooks.java | 29 +-- .../sun/net/{spi => sdp}/SdpProvider.java | 22 +- .../classes/sun/nio/ch/InheritedChannel.java | 2 +- .../{spi/SdpProvider.c => sdp/SdpSupport.c} | 73 +++++-- jdk/test/com/oracle/net/Sanity.java | 142 +++++++++++++ jdk/test/com/oracle/net/sanity.sh | 66 ++++++ jdk/test/sun/net/sdp/ProbeIB.java | 15 +- jdk/test/sun/net/sdp/sanity.sh | 21 +- 24 files changed, 806 insertions(+), 89 deletions(-) create mode 100644 jdk/make/com/oracle/Makefile create mode 100644 jdk/make/com/oracle/net/Makefile create mode 100644 jdk/src/share/classes/com/oracle/net/Sdp.java create mode 100644 jdk/src/share/classes/java/net/SdpSocketImpl.java create mode 100644 jdk/src/share/classes/sun/net/sdp/SdpSupport.java create mode 100644 jdk/src/share/classes/sun/nio/ch/Secrets.java rename jdk/src/solaris/classes/sun/net/{spi => sdp}/SdpProvider.java (95%) rename jdk/src/solaris/native/sun/net/{spi/SdpProvider.c => sdp/SdpSupport.c} (66%) create mode 100644 jdk/test/com/oracle/net/Sanity.java create mode 100644 jdk/test/com/oracle/net/sanity.sh diff --git a/jdk/make/com/Makefile b/jdk/make/com/Makefile index baf56b3ddb0..37472ea3f3a 100644 --- a/jdk/make/com/Makefile +++ b/jdk/make/com/Makefile @@ -31,7 +31,7 @@ BUILDDIR = .. PRODUCT = com include $(BUILDDIR)/common/Defs.gmk -SUBDIRS = sun +SUBDIRS = sun oracle include $(BUILDDIR)/common/Subdirs.gmk all build clean clobber:: diff --git a/jdk/make/com/oracle/Makefile b/jdk/make/com/oracle/Makefile new file mode 100644 index 00000000000..7c70dc78270 --- /dev/null +++ b/jdk/make/com/oracle/Makefile @@ -0,0 +1,34 @@ +# +# Copyright (c) 2010, 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. +# + +BUILDDIR = ../.. +PRODUCT = oracle +include $(BUILDDIR)/common/Defs.gmk + +SUBDIRS = net +include $(BUILDDIR)/common/Subdirs.gmk + +all build clean clobber:: + $(SUBDIRS-loop) diff --git a/jdk/make/com/oracle/net/Makefile b/jdk/make/com/oracle/net/Makefile new file mode 100644 index 00000000000..5fd30761699 --- /dev/null +++ b/jdk/make/com/oracle/net/Makefile @@ -0,0 +1,39 @@ +# +# Copyright (c) 2010, 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. +# + +BUILDDIR = ../../.. +PRODUCT = oracle +include $(BUILDDIR)/common/Defs.gmk + +# +# Files to compile +# +AUTO_FILES_JAVA_DIRS = com/oracle/net + +# +# Rules +# +include $(BUILDDIR)/common/Classes.gmk + diff --git a/jdk/make/docs/NON_CORE_PKGS.gmk b/jdk/make/docs/NON_CORE_PKGS.gmk index 6639eecf893..180241483c1 100644 --- a/jdk/make/docs/NON_CORE_PKGS.gmk +++ b/jdk/make/docs/NON_CORE_PKGS.gmk @@ -91,6 +91,8 @@ SCTPAPI_PKGS = com.sun.nio.sctp TRACING_PKGS = com.sun.tracing \ com.sun.tracing.dtrace +ORACLENET_PKGS = com.oracle.net + # non-core packages in rt.jar NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(MGMT_PKGS) \ @@ -101,5 +103,6 @@ NON_CORE_PKGS = $(DOMAPI_PKGS) \ $(HTTPSERVER_PKGS) \ $(SMARTCARDIO_PKGS) \ $(TRACING_PKGS) \ - $(SCTPAPI_PKGS) + $(SCTPAPI_PKGS) \ + $(ORACLENET_PKGS) diff --git a/jdk/make/java/net/FILES_c.gmk b/jdk/make/java/net/FILES_c.gmk index 642244915af..29ce70a6e68 100644 --- a/jdk/make/java/net/FILES_c.gmk +++ b/jdk/make/java/net/FILES_c.gmk @@ -39,10 +39,6 @@ FILES_c = \ ResolverConfigurationImpl.c \ DefaultProxySelector.c -ifeq ($(PLATFORM), solaris) - FILES_c += SdpProvider.c -endif - ifeq ($(PLATFORM), linux) FILES_c += linux_close.c endif diff --git a/jdk/make/java/net/Makefile b/jdk/make/java/net/Makefile index 0021087cbcf..db034f2511e 100644 --- a/jdk/make/java/net/Makefile +++ b/jdk/make/java/net/Makefile @@ -44,6 +44,8 @@ ifeq ($(PLATFORM), windows) endif FILES_c += NTLMAuthSequence.c FILES_c += NetworkInterface_winXP.c +else + FILES_c += SdpSupport.c endif FILES_export = \ @@ -84,7 +86,8 @@ endif # # Find platform specific native code # -vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi +vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm \ + $(PLATFORM_SRC)/native/sun/net/sdp $(PLATFORM_SRC)/native/sun/net/spi # # Include rules diff --git a/jdk/make/java/net/mapfile-vers b/jdk/make/java/net/mapfile-vers index fbcf905d173..0e9a46755d4 100644 --- a/jdk/make/java/net/mapfile-vers +++ b/jdk/make/java/net/mapfile-vers @@ -88,9 +88,10 @@ SUNWprivate_1.1 { Java_java_net_PlainDatagramSocketImpl_setTimeToLive; Java_sun_net_dns_ResolverConfigurationImpl_localDomain0; Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0; + Java_sun_net_sdp_SdpSupport_convert0; + Java_sun_net_sdp_SdpSupport_create0; Java_sun_net_spi_DefaultProxySelector_init; Java_sun_net_spi_DefaultProxySelector_getSystemProxy; - Java_sun_net_spi_SdpProvider_convert; NET_AllocSockaddr; NET_SockaddrToInetAddress; NET_SockaddrEqualsInetAddress; diff --git a/jdk/make/java/nio/FILES_java.gmk b/jdk/make/java/nio/FILES_java.gmk index 4ad955d87aa..4d89db04a49 100644 --- a/jdk/make/java/nio/FILES_java.gmk +++ b/jdk/make/java/nio/FILES_java.gmk @@ -199,6 +199,7 @@ FILES_src = \ sun/nio/ch/PipeImpl.java \ sun/nio/ch/PollArrayWrapper.java \ sun/nio/ch/Reflect.java \ + sun/nio/ch/Secrets.java \ sun/nio/ch/SelectionKeyImpl.java \ sun/nio/ch/SelectorImpl.java \ sun/nio/ch/SelectorProviderImpl.java \ diff --git a/jdk/make/sun/net/FILES_java.gmk b/jdk/make/sun/net/FILES_java.gmk index 3eba9b01a17..1fcec35f4e4 100644 --- a/jdk/make/sun/net/FILES_java.gmk +++ b/jdk/make/sun/net/FILES_java.gmk @@ -53,6 +53,7 @@ FILES_java = \ sun/net/ftp/FtpProtocolException.java \ sun/net/ftp/impl/FtpClient.java \ sun/net/ftp/impl/DefaultFtpClientProvider.java \ + sun/net/sdp/SdpSupport.java \ sun/net/spi/DefaultProxySelector.java \ sun/net/spi/nameservice/NameServiceDescriptor.java \ sun/net/spi/nameservice/NameService.java \ @@ -136,8 +137,6 @@ FILES_java = \ ifeq ($(PLATFORM), windows) FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java -endif - -ifeq ($(PLATFORM), solaris) - FILES_java += sun/net/spi/SdpProvider.java +else + FILES_java += sun/net/sdp/SdpProvider.java endif diff --git a/jdk/src/share/classes/com/oracle/net/Sdp.java b/jdk/src/share/classes/com/oracle/net/Sdp.java new file mode 100644 index 00000000000..32316073828 --- /dev/null +++ b/jdk/src/share/classes/com/oracle/net/Sdp.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.oracle.net; + +import java.net.Socket; +import java.net.ServerSocket; +import java.net.SocketImpl; +import java.net.SocketImplFactory; +import java.net.SocketException; +import java.nio.channels.SocketChannel; +import java.nio.channels.ServerSocketChannel; +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.lang.reflect.Constructor; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.InvocationTargetException; + +import sun.net.sdp.SdpSupport; + +/** + * This class consists exclusively of static methods that Sockets or Channels to + * sockets that support the InfiniBand Sockets Direct Protocol (SDP). + */ + +public final class Sdp { + private Sdp() { } + + /** + * The package-privage ServerSocket(SocketImpl) constructor + */ + private static final Constructor serverSocketCtor; + static { + try { + serverSocketCtor = (Constructor) + ServerSocket.class.getDeclaredConstructor(SocketImpl.class); + setAccessible(serverSocketCtor); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** + * The package-private SdpSocketImpl() constructor + */ + private static final Constructor socketImplCtor; + static { + try { + Class cl = Class.forName("java.net.SdpSocketImpl", true, null); + socketImplCtor = (Constructor)cl.getDeclaredConstructor(); + setAccessible(socketImplCtor); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + private static void setAccessible(final AccessibleObject o) { + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + o.setAccessible(true); + return null; + } + }); + } + + /** + * SDP enabled Socket. + */ + private static class SdpSocket extends Socket { + SdpSocket(SocketImpl impl) throws SocketException { + super(impl); + } + } + + /** + * Creates a SDP enabled SocketImpl + */ + private static SocketImpl createSocketImpl() { + try { + return socketImplCtor.newInstance(); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + throw new AssertionError(x); + } + } + + /** + * Creates an unconnected and unbound SDP socket. The {@code Socket} is + * associated with a {@link java.net.SocketImpl} of the system-default type. + * + * @return a new Socket + * + * @throws UnsupportedOperationException + * If SDP is not supported + * @throws IOException + * If an I/O error occurs + */ + public static Socket openSocket() throws IOException { + SocketImpl impl = createSocketImpl(); + return new SdpSocket(impl); + } + + /** + * Creates an unbound SDP server socket. The {@code ServerSocket} is + * associated with a {@link java.net.SocketImpl} of the system-default type. + * + * @return a new ServerSocket + * + * @throws UnsupportedOperationException + * If SDP is not supported + * @throws IOException + * If an I/O error occurs + */ + public static ServerSocket openServerSocket() throws IOException { + // create ServerSocket via package-private constructor + SocketImpl impl = createSocketImpl(); + try { + return serverSocketCtor.newInstance(impl); + } catch (IllegalAccessException x) { + throw new AssertionError(x); + } catch (InstantiationException x) { + throw new AssertionError(x); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) + throw (IOException)cause; + if (cause instanceof RuntimeException) + throw (RuntimeException)cause; + throw new RuntimeException(x); + } + } + + /** + * Opens a socket channel to a SDP socket. + * + *

The channel will be associated with the system-wide default + * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. + * + * @return a new SocketChannel + * + * @throws UnsupportedOperationException + * If SDP is not supported or not supported by the default selector + * provider + * @throws IOException + * If an I/O error occurs. + */ + public static SocketChannel openSocketChannel() throws IOException { + FileDescriptor fd = SdpSupport.createSocket(); + return sun.nio.ch.Secrets.newSocketChannel(fd); + } + + /** + * Opens a socket channel to a SDP socket. + * + *

The channel will be associated with the system-wide default + * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}. + * + * @return a new ServerSocketChannel + * + * @throws UnsupportedOperationException + * If SDP is not supported or not supported by the default selector + * provider + * @throws IOException + * If an I/O error occurs + */ + public static ServerSocketChannel openServerSocketChannel() + throws IOException + { + FileDescriptor fd = SdpSupport.createSocket(); + return sun.nio.ch.Secrets.newServerSocketChannel(fd); + } +} diff --git a/jdk/src/share/classes/java/net/SdpSocketImpl.java b/jdk/src/share/classes/java/net/SdpSocketImpl.java new file mode 100644 index 00000000000..b5b023e2433 --- /dev/null +++ b/jdk/src/share/classes/java/net/SdpSocketImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, 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. + */ + +package java.net; + +import java.io.IOException; +import java.io.FileDescriptor; + +import sun.net.sdp.SdpSupport; + +/** + * SocketImpl that supports the SDP protocol + */ +class SdpSocketImpl extends PlainSocketImpl { + SdpSocketImpl() { } + + @Override + protected void create(boolean stream) throws IOException { + if (!stream) + throw new UnsupportedOperationException("Must be a stream socket"); + fd = SdpSupport.createSocket(); + if (socket != null) + socket.setCreated(); + if (serverSocket != null) + serverSocket.setCreated(); + } +} diff --git a/jdk/src/share/classes/java/net/ServerSocket.java b/jdk/src/share/classes/java/net/ServerSocket.java index 8189d8aa4f0..d4b44e4ccb2 100644 --- a/jdk/src/share/classes/java/net/ServerSocket.java +++ b/jdk/src/share/classes/java/net/ServerSocket.java @@ -68,6 +68,15 @@ class ServerSocket implements java.io.Closeable { */ private boolean oldImpl = false; + /** + * Package-private constructor to create a ServerSocket associated with + * the given SocketImpl. + */ + ServerSocket(SocketImpl impl) { + this.impl = impl; + impl.setServerSocket(this); + } + /** * Creates an unbound server socket. * diff --git a/jdk/src/share/classes/sun/net/sdp/SdpSupport.java b/jdk/src/share/classes/sun/net/sdp/SdpSupport.java new file mode 100644 index 00000000000..5baca6e4925 --- /dev/null +++ b/jdk/src/share/classes/sun/net/sdp/SdpSupport.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010, 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. + */ + +package sun.net.sdp; + +import java.io.IOException; +import java.io.FileDescriptor; +import java.security.AccessController; + +import sun.misc.SharedSecrets; +import sun.misc.JavaIOFileDescriptorAccess; + + +/** + * This class defines methods for creating SDP sockets or "converting" existing + * file descriptors, referencing (unbound) TCP sockets, to SDP. + */ + +public final class SdpSupport { + private static final String os = AccessController + .doPrivileged(new sun.security.action.GetPropertyAction("os.name")); + private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux"))); + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + + private SdpSupport() { } + + /** + * Creates a SDP socket, returning file descriptor referencing the socket. + */ + public static FileDescriptor createSocket() throws IOException { + if (!isSupported) + throw new UnsupportedOperationException("SDP not supported on this platform"); + int fdVal = create0(); + FileDescriptor fd = new FileDescriptor(); + fdAccess.set(fd, fdVal); + return fd; + } + + /** + * Converts an existing file descriptor, that references an unbound TCP socket, + * to SDP. + */ + public static void convertSocket(FileDescriptor fd) throws IOException { + if (!isSupported) + throw new UnsupportedOperationException("SDP not supported on this platform"); + int fdVal = fdAccess.get(fd); + convert0(fdVal); + } + + private static native int create0() throws IOException; + + private static native void convert0(int fd) throws IOException; + + static { + AccessController.doPrivileged( + new sun.security.action.LoadLibraryAction("net")); + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/Secrets.java b/jdk/src/share/classes/sun/nio/ch/Secrets.java new file mode 100644 index 00000000000..f76ab1d75a0 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/ch/Secrets.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, 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. + */ + +package sun.nio.ch; + +import java.nio.channels.SocketChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.spi.SelectorProvider; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Provides access to implementation private constructors and methods. + */ + +public final class Secrets { + private Secrets() { } + + private static SelectorProvider provider() { + SelectorProvider p = SelectorProvider.provider(); + if (!(p instanceof SelectorProviderImpl)) + throw new UnsupportedOperationException(); + return p; + } + + public static SocketChannel newSocketChannel(FileDescriptor fd) { + try { + return new SocketChannelImpl(provider(), fd, false); + } catch (IOException ioe) { + throw new AssertionError(ioe); + } + } + + public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) { + try { + return new ServerSocketChannelImpl(provider(), fd, false); + } catch (IOException ioe) { + throw new AssertionError(ioe); + } + } +} diff --git a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 8df9ae4ca4a..3685d3a7c68 100644 --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -80,21 +80,24 @@ class ServerSocketChannelImpl // -- End of fields protected by stateLock - public ServerSocketChannelImpl(SelectorProvider sp) throws IOException { + ServerSocketChannelImpl(SelectorProvider sp) throws IOException { super(sp); this.fd = Net.serverSocket(true); this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; } - public ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd) + ServerSocketChannelImpl(SelectorProvider sp, + FileDescriptor fd, + boolean bound) throws IOException { super(sp); this.fd = fd; this.fdVal = IOUtil.fdVal(fd); this.state = ST_INUSE; - localAddress = Net.localAddress(fd); + if (bound) + localAddress = Net.localAddress(fd); } public ServerSocket socket() { diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index 7d42d7d0096..c8b93b7c6f7 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -103,6 +103,19 @@ class SocketChannelImpl this.state = ST_UNCONNECTED; } + SocketChannelImpl(SelectorProvider sp, + FileDescriptor fd, + boolean bound) + throws IOException + { + super(sp); + this.fd = fd; + this.fdVal = IOUtil.fdVal(fd); + this.state = ST_UNCONNECTED; + if (bound) + this.localAddress = Net.localAddress(fd); + } + // Constructor for sockets obtained from server sockets // SocketChannelImpl(SelectorProvider sp, diff --git a/jdk/src/solaris/classes/sun/net/NetHooks.java b/jdk/src/solaris/classes/sun/net/NetHooks.java index 06a11e54264..bc4a60b72eb 100644 --- a/jdk/src/solaris/classes/sun/net/NetHooks.java +++ b/jdk/src/solaris/classes/sun/net/NetHooks.java @@ -73,28 +73,7 @@ public final class NetHooks { * be changed to use the ServiceLoader facility to allow the deployment of * other providers. */ - private static Provider loadProvider(final String cn) { - return AccessController - .doPrivileged(new PrivilegedAction() { - @Override public Provider run() { - Class c; - try { - c = (Class)Class.forName(cn, true, null); - } catch (ClassNotFoundException x) { - return null; - } - try { - return c.newInstance(); - } catch (IllegalAccessException x) { - throw new AssertionError(x); - } catch (InstantiationException x) { - throw new AssertionError(x); - } - }}); - } - private static final Provider provider = AccessController - .doPrivileged(new GetPropertyAction("os.name")).equals("SunOS") ? - loadProvider("sun.net.spi.SdpProvider") : null; + private static final Provider provider = new sun.net.sdp.SdpProvider(); /** * Invoke prior to binding a TCP socket. @@ -104,8 +83,7 @@ public final class NetHooks { int port) throws IOException { - if (provider != null) - provider.implBeforeTcpBind(fdObj, address, port); + provider.implBeforeTcpBind(fdObj, address, port); } /** @@ -116,7 +94,6 @@ public final class NetHooks { int port) throws IOException { - if (provider != null) - provider.implBeforeTcpConnect(fdObj, address, port); + provider.implBeforeTcpConnect(fdObj, address, port); } } diff --git a/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java b/jdk/src/solaris/classes/sun/net/sdp/SdpProvider.java similarity index 95% rename from jdk/src/solaris/classes/sun/net/spi/SdpProvider.java rename to jdk/src/solaris/classes/sun/net/sdp/SdpProvider.java index b2e7a0f591b..0fcec598726 100644 --- a/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java +++ b/jdk/src/solaris/classes/sun/net/sdp/SdpProvider.java @@ -23,7 +23,7 @@ * questions. */ -package sun.net.spi; +package sun.net.sdp; import sun.net.NetHooks; import java.net.InetAddress; @@ -34,9 +34,10 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintStream; +import java.security.AccessController; -import sun.misc.SharedSecrets; -import sun.misc.JavaIOFileDescriptorAccess; +import sun.net.sdp.SdpSupport; +import sun.security.action.GetPropertyAction; /** * A NetHooks provider that converts sockets from the TCP to SDP protocol prior @@ -44,9 +45,6 @@ import sun.misc.JavaIOFileDescriptorAccess; */ public class SdpProvider extends NetHooks.Provider { - private static final JavaIOFileDescriptorAccess fdAccess = - SharedSecrets.getJavaIOFileDescriptorAccess(); - // maximum port private static final int MAX_PORT = 65535; @@ -59,7 +57,8 @@ public class SdpProvider extends NetHooks.Provider { public SdpProvider() { // if this property is not defined then there is nothing to do. - String file = System.getProperty("com.sun.sdp.conf"); + String file = AccessController.doPrivileged( + new GetPropertyAction("com.sun.sdp.conf")); if (file == null) { this.enabled = false; this.rules = null; @@ -78,7 +77,8 @@ public class SdpProvider extends NetHooks.Provider { // check if debugging is enabled PrintStream out = null; - String logfile = System.getProperty("com.sun.sdp.debug"); + String logfile = AccessController.doPrivileged( + new GetPropertyAction("com.sun.sdp.debug")); if (logfile != null) { out = System.out; if (logfile.length() > 0) { @@ -297,8 +297,7 @@ public class SdpProvider extends NetHooks.Provider { boolean matched = false; for (Rule rule: rules) { if (rule.match(action, address, port)) { - int fd = fdAccess.get(fdObj); - convert(fd); + SdpSupport.convertSocket(fdObj); matched = true; break; } @@ -333,7 +332,4 @@ public class SdpProvider extends NetHooks.Provider { if (enabled) convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port); } - - // -- native methods -- - private static native void convert(int fd) throws IOException; } diff --git a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java index a834f6f31df..ff51aa052ca 100644 --- a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java +++ b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java @@ -96,7 +96,7 @@ class InheritedChannel { FileDescriptor fd) throws IOException { - super(sp, fd); + super(sp, fd, true); } protected void implCloseSelectableChannel() throws IOException { diff --git a/jdk/src/solaris/native/sun/net/spi/SdpProvider.c b/jdk/src/solaris/native/sun/net/sdp/SdpSupport.c similarity index 66% rename from jdk/src/solaris/native/sun/net/spi/SdpProvider.c rename to jdk/src/solaris/native/sun/net/sdp/SdpSupport.c index 5b927404606..dd2750be5f7 100644 --- a/jdk/src/solaris/native/sun/net/spi/SdpProvider.c +++ b/jdk/src/solaris/native/sun/net/sdp/SdpSupport.c @@ -25,9 +25,16 @@ #include #include +#include -#if defined(__solaris__) && !defined(PROTO_SDP) -#define PROTO_SDP 257 +#if defined(__solaris__) + #if !defined(PROTO_SDP) + #define PROTO_SDP 257 + #endif +#elif defined(__linux__) + #if !defined(AF_INET_SDP) + #define AF_INET_SDP 27 + #endif #endif #include "jni.h" @@ -40,20 +47,61 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) -JNIEXPORT void JNICALL -Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd) + +/** + * Creates a SDP socket. + */ +static int create(JNIEnv* env) { -#ifdef PROTO_SDP -#ifdef AF_INET6 + int s; + +#if defined(__solaris__) + #ifdef AF_INET6 int domain = ipv6_available() ? AF_INET6 : AF_INET; -#else + #else int domain = AF_INET; + #endif + s = socket(domain, SOCK_STREAM, PROTO_SDP); +#elif defined(__linux__) + /** + * IPv6 not supported by SDP on Linux + */ + if (ipv6_available()) { + JNU_ThrowIOException(env, "IPv6 not supported"); + return; + } + s = socket(AF_INET_SDP, SOCK_STREAM, 0); +#else + /* not supported on other platforms at this time */ + s = -1; + errno = EPROTONOSUPPORT; #endif - int s = socket(domain, SOCK_STREAM, PROTO_SDP); - if (s < 0) { + + if (s < 0) JNU_ThrowIOExceptionWithLastError(env, "socket"); - } else { - int arg, len, res; + return s; +} + +/** + * Creates a SDP socket, returning file descriptor referencing the socket. + */ +JNIEXPORT jint JNICALL +Java_sun_net_sdp_SdpSupport_create0(JNIEnv *env, jclass cls) +{ + return create(env); +} + +/** + * Converts an existing file descriptor, that references an unbound TCP socket, + * to SDP. + */ +JNIEXPORT void JNICALL +Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd) +{ + int s = create(env); + if (s >= 0) { + socklen_t len; + int arg, res; struct linger linger; /* copy socket options that are relevant to SDP */ @@ -72,7 +120,4 @@ Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd) JNU_ThrowIOExceptionWithLastError(env, "dup2"); RESTARTABLE(close(s), res); } -#else - JNU_ThrowInternalError(env, "should not reach here"); -#endif } diff --git a/jdk/test/com/oracle/net/Sanity.java b/jdk/test/com/oracle/net/Sanity.java new file mode 100644 index 00000000000..c4c97152779 --- /dev/null +++ b/jdk/test/com/oracle/net/Sanity.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2010, 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. + * + * 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. + */ + +import com.oracle.net.Sdp; + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.*; + +/** + * Exercise com.oracle.net.Sdp with each IP address plumbed to InfiniBand + * interfaces listed in a given file. + */ + +public class Sanity { + public static void main(String[] args) throws Exception { + // The file is a list of interfaces to test. + Scanner s = new Scanner(new File(args[0])); + try { + while (s.hasNextLine()) { + String link = s.nextLine(); + NetworkInterface ni = NetworkInterface.getByName(link); + if (ni != null) { + Enumeration addrs = ni.getInetAddresses(); + while (addrs.hasMoreElements()) { + InetAddress addr = addrs.nextElement(); + System.out.format("Testing %s: %s\n", link, addr.getHostAddress()); + test(addr); + } + } + } + } finally { + s.close(); + } + } + + static void test(InetAddress addr) throws Exception { + // Test SocketChannel and ServerSocketChannel + ServerSocketChannel ssc = Sdp.openServerSocketChannel(); + try { + ssc.socket().bind(new InetSocketAddress(addr, 0)); + int port = ssc.socket().getLocalPort(); + + // SocketChannel.connect (implicit bind) + SocketChannel client = Sdp.openSocketChannel(); + try { + client.connect(new InetSocketAddress(addr, port)); + SocketChannel peer = ssc.accept(); + try { + testConnection(Channels.newOutputStream(client), + Channels.newInputStream(peer)); + } finally { + peer.close(); + } + } finally { + client.close(); + } + + // SocketChannel.connect (explicit bind) + client = Sdp.openSocketChannel(); + try { + client.socket().bind(new InetSocketAddress(addr, 0)); + client.connect(new InetSocketAddress(addr, port)); + ssc.accept().close(); + } finally { + client.close(); + } + } finally { + ssc.close(); + } + + // Test Socket and ServerSocket + ServerSocket ss = Sdp.openServerSocket(); + try { + ss.bind(new InetSocketAddress(addr, 0)); + int port = ss.getLocalPort(); + + // Socket.connect (implicit bind) + Socket s = Sdp.openSocket(); + try { + s.connect(new InetSocketAddress(addr, port)); + Socket peer = ss.accept(); + try { + testConnection(s.getOutputStream(), peer.getInputStream()); + } finally { + peer.close(); + } + } finally { + s.close(); + } + + // Socket.connect (explicit bind) + s = Sdp.openSocket(); + try { + s.bind(new InetSocketAddress(addr, 0)); + s.connect(new InetSocketAddress(addr, port)); + ss.accept().close(); + } finally { + s.close(); + } + } finally { + ss.close(); + } + } + + static void testConnection(OutputStream out, InputStream in) + throws IOException + { + byte[] msg = "hello".getBytes(); + out.write(msg); + + byte[] ba = new byte[100]; + int nread = 0; + while (nread < msg.length) { + int n = in.read(ba); + if (n < 0) + throw new IOException("EOF not expected!"); + nread += n; + } + } +} diff --git a/jdk/test/com/oracle/net/sanity.sh b/jdk/test/com/oracle/net/sanity.sh new file mode 100644 index 00000000000..b54d866b4fa --- /dev/null +++ b/jdk/test/com/oracle/net/sanity.sh @@ -0,0 +1,66 @@ +# +# Copyright (c) 2010, 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. +# +# 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. +# + +# @test +# @bug 6965072 +# @summary Unit test for SDP support +# @build Sanity +# @run shell sanity.sh + +IB_LINKS=ib.links + +OS=`uname -s` +case "$OS" in + SunOS ) + /usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS} + if [ $? != 0 ]; then + echo "Unable to get InfiniBand parition link information" + exit 0 + fi + ;; + Linux ) + if [ ! -f /proc/net/sdp ]; then + echo "InfiniBand SDP module not installed" + exit 0 + fi + egrep "^[ \t]+ib" /proc/net/dev|cut -d':' -f1|tr -d '\t ' > ${IB_LINKS} + ;; + * ) + echo "This test only runs on Solaris or Linux" + exit 0 + ;; +esac + +if [ -z "$TESTJAVA" ]; then + JAVA=java + TESTCLASSES=. + TESTSRC=. +else + JAVA="${TESTJAVA}/bin/java" +fi + +CLASSPATH=${TESTCLASSES}:${TESTSRC} +export CLASSPATH + +# Run sanity test (IPv4-only for now) +$JAVA -Djava.net.preferIPv4Stack=true Sanity ${IB_LINKS} diff --git a/jdk/test/sun/net/sdp/ProbeIB.java b/jdk/test/sun/net/sdp/ProbeIB.java index 34244b84b0d..0f1535fce14 100644 --- a/jdk/test/sun/net/sdp/ProbeIB.java +++ b/jdk/test/sun/net/sdp/ProbeIB.java @@ -34,21 +34,16 @@ import java.util.Enumeration; public class ProbeIB { public static void main(String[] args) throws IOException { - Scanner s = new Scanner(new File("/etc/path_to_inst")); + Scanner s = new Scanner(new File(args[0])); try { while (s.hasNextLine()) { - String line = s.nextLine(); - if (line.startsWith("#")) - continue; - String[] fields = line.split("\\s+"); - if (!fields[2].equals("\"ibd\"")) - continue; - String name = fields[2].substring(1, fields[2].length()-1) + fields[1]; - NetworkInterface ni = NetworkInterface.getByName(name); + String link = s.nextLine(); + NetworkInterface ni = NetworkInterface.getByName(link); if (ni != null) { Enumeration addrs = ni.getInetAddresses(); while (addrs.hasMoreElements()) { - System.out.println(addrs.nextElement().getHostAddress()); + InetAddress addr = addrs.nextElement(); + System.out.println(addr.getHostAddress()); } } } diff --git a/jdk/test/sun/net/sdp/sanity.sh b/jdk/test/sun/net/sdp/sanity.sh index e1a209ba347..f35425b46f2 100644 --- a/jdk/test/sun/net/sdp/sanity.sh +++ b/jdk/test/sun/net/sdp/sanity.sh @@ -33,14 +33,15 @@ if [ "$OS" != "SunOS" ]; then echo "This is a Solaris-only test" exit 0 fi -SDPADM=/usr/sbin/sdpadm -if [ ! -f ${SDPADM} ]; then - echo "SDP not available" - exit 0 -fi -${SDPADM} status|grep Enabled -if [ $? != 0 ]; then - echo "SDP not enabled" + +IB_LINKS=ib.links +IB_ADDRS=ib.addrs + +# Display IB partition link information +# (requires Solaris 11, will fail on Solaris 10) +/usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS} +if [ $? != 0 ]; then + echo "Unable to get IB parition link information" exit 0 fi @@ -56,13 +57,13 @@ CLASSPATH=${TESTCLASSES}:${TESTSRC} export CLASSPATH # Probe for IP addresses plumbed to IB interfaces -$JAVA -Djava.net.preferIPv4Stack=true ProbeIB > ib_addrs +$JAVA -Djava.net.preferIPv4Stack=true ProbeIB ${IB_LINKS} > ${IB_ADDRS} # Create sdp.conf SDPCONF=sdp.conf rm ${SDPCONF} touch ${SDPCONF} -cat ib_addrs | while read ADDR +cat ${IB_ADDRS} | while read ADDR do echo "bind ${ADDR} *" > ${SDPCONF} echo "connect ${ADDR} *" >> ${SDPCONF} From ef7b8cbc9eae35bc35625de155b41d4fe794c038 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 3 Sep 2010 07:59:21 -0700 Subject: [PATCH 09/27] 6981001: (launcher) EnsureJREInstallation is not being called in order Reviewed-by: darcy --- jdk/src/windows/bin/java_md.c | 7 +-- .../{VerifyExceptions.java => MiscTests.java} | 43 +++++++++++++++---- 2 files changed, 38 insertions(+), 12 deletions(-) rename jdk/test/tools/launcher/{VerifyExceptions.java => MiscTests.java} (60%) diff --git a/jdk/src/windows/bin/java_md.c b/jdk/src/windows/bin/java_md.c index 62cc3006005..abd887c94d5 100644 --- a/jdk/src/windows/bin/java_md.c +++ b/jdk/src/windows/bin/java_md.c @@ -105,15 +105,15 @@ CreateExecutionEnvironment(int *pargc, char ***pargv, exit(1); } - /* Do this before we read jvm.cfg */ - EnsureJreInstallation(jrepath); - /* Find out where the JRE is that we will be using. */ if (!GetJREPath(jrepath, so_jrepath)) { JLI_ReportErrorMessage(JRE_ERROR1); exit(2); } + /* Do this before we read jvm.cfg and after jrepath is initialized */ + EnsureJreInstallation(jrepath); + /* Find the specified JVM type */ if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) { JLI_ReportErrorMessage(CFG_ERROR7); @@ -213,6 +213,7 @@ EnsureJreInstallation(const char* jrepath) } /* Does our bundle directory exist ? */ JLI_Snprintf(tmpbuf, sizeof(tmpbuf), "%s\\lib\\bundles", jrepath); + JLI_TraceLauncher("EnsureJreInstallation: %s\n", tmpbuf); if (stat(tmpbuf, &s) != 0) { return; } diff --git a/jdk/test/tools/launcher/VerifyExceptions.java b/jdk/test/tools/launcher/MiscTests.java similarity index 60% rename from jdk/test/tools/launcher/VerifyExceptions.java rename to jdk/test/tools/launcher/MiscTests.java index 166ffff9b1b..654a56a01f4 100644 --- a/jdk/test/tools/launcher/VerifyExceptions.java +++ b/jdk/test/tools/launcher/MiscTests.java @@ -23,19 +23,22 @@ /* * @test - * @bug 6856415 - * @summary Checks to ensure that proper exceptions are thrown by java - * @compile -XDignore.symbol.file VerifyExceptions.java TestHelper.java - * @run main VerifyExceptions + * @bug 6856415 6981001 + * @summary Miscellaneous tests, Exceptions, EnsureJRE etc. + * @compile -XDignore.symbol.file MiscTests.java TestHelper.java + * @run main MiscTests */ import java.io.File; import java.io.FileNotFoundException; +import java.util.HashMap; +import java.util.Map; -public class VerifyExceptions { +public class MiscTests { + // 6856415: Checks to ensure that proper exceptions are thrown by java static void test6856415() { // No pkcs library on win-x64, so we bail out. if (TestHelper.is64Bit && TestHelper.isWindows) { @@ -53,13 +56,35 @@ public class VerifyExceptions { } catch (FileNotFoundException fnfe) { throw new RuntimeException(fnfe); } - TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javacCmd, + TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javaCmd, "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak"); - tr.checkNegative(); - tr.contains("Exception in thread \"main\" java.security.AccessControlException: access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.security.pkcs11\")\")"); + for (String s : tr.testOutput) { + System.out.println(s); + } + if (!tr.contains("java.security.AccessControlException:" + + " access denied (\"java.lang.RuntimePermission\"" + + " \"accessClassInPackage.sun.security.pkcs11\")")) { + System.out.println(tr.status); + } + } + // 6981001 : Check EnsureJreInstallation is ok, note we cannot + // thoroughly test this function, we simply do our best. + static void test6981001() { + if (TestHelper.is64Bit || !TestHelper.isWindows) { + return; + } + Map env = new HashMap(); + env.put("_JAVA_LAUNCHER_DEBUG", "true"); + TestHelper.TestResult tr = TestHelper.doExec(env, TestHelper.javaCmd); + if (!tr.contains(TestHelper.JAVAHOME + "\\lib\\bundles")) { + System.out.println(tr.status); + } } - public static void main(String... args) { test6856415(); + test6981001(); + if (TestHelper.testExitValue != 0) { + throw new Error(TestHelper.testExitValue + " tests failed"); } } +} From 7d47787007fbe6b258338547d7bd9c663a4ee03d Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 3 Sep 2010 15:00:10 -0700 Subject: [PATCH 10/27] 4881419: The type of X[].clone() should be X[] Reviewed-by: martin --- jdk/src/share/classes/java/lang/Object.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/lang/Object.java b/jdk/src/share/classes/java/lang/Object.java index 2e1011a60da..c730db44e23 100644 --- a/jdk/src/share/classes/java/lang/Object.java +++ b/jdk/src/share/classes/java/lang/Object.java @@ -189,7 +189,9 @@ public class Object { * specific cloning operation. First, if the class of this object does * not implement the interface {@code Cloneable}, then a * {@code CloneNotSupportedException} is thrown. Note that all arrays - * are considered to implement the interface {@code Cloneable}. + * are considered to implement the interface {@code Cloneable} and that + * the return type of the {@code clone} method of an array type {@code T[]} + * is {@code T[]} where T is any reference or primitive type. * Otherwise, this method creates a new instance of the class of this * object and initializes all its fields with exactly the contents of * the corresponding fields of this object, as if by assignment; the From a239e8e46209f684a2b88170e1cf9db9f7d99941 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Sat, 4 Sep 2010 12:21:56 -0400 Subject: [PATCH 11/27] 6861385: Updated SQLException subclasses to clarify that they may be thrown for vendor specific conditions Reviewed-by: alanb --- .../share/classes/java/sql/SQLDataException.java | 13 ++++++++----- .../SQLIntegrityConstraintViolationException.java | 10 +++++++--- .../sql/SQLInvalidAuthorizationSpecException.java | 12 ++++++++---- .../sql/SQLNonTransientConnectionException.java | 10 ++++++---- .../classes/java/sql/SQLSyntaxErrorException.java | 9 ++++++--- .../java/sql/SQLTransactionRollbackException.java | 13 ++++++++----- .../java/sql/SQLTransientConnectionException.java | 11 ++++++----- 7 files changed, 49 insertions(+), 29 deletions(-) diff --git a/jdk/src/share/classes/java/sql/SQLDataException.java b/jdk/src/share/classes/java/sql/SQLDataException.java index 813b9949782..add946bec4b 100644 --- a/jdk/src/share/classes/java/sql/SQLDataException.java +++ b/jdk/src/share/classes/java/sql/SQLDataException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,10 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '22'. This indicates - * various data errors, including but not limited to not-allowed conversion, division by 0 - * and invalid arguments to functions. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '22', or under vendor-specified conditions. This indicates + * various data errors, including but not limited to data conversion errors, + * division by 0, and invalid arguments to functions. + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLDataException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java b/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java index 0c7160d2675..6bbef40696a 100644 --- a/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java +++ b/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,9 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '23'. This indicates that an integrity + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '23', or under vendor-specified conditions. + * This indicates that an integrity * constraint (foreign key, primary key or unique key) has been violated. - * + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLIntegrityConstraintViolationException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java b/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java index 34ccfe13301..c1a029be878 100644 --- a/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java +++ b/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,9 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '28'. This indicated that the - * authorization credentials presented during connection establishment are not valid. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '28', or under vendor-specified conditions. This indicates that + * the authorization credentials presented during connection establishment + * are not valid. + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLInvalidAuthorizationSpecException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java b/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java index 089f7f439ed..9ba550fa3ce 100644 --- a/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java +++ b/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,11 +26,13 @@ package java.sql; /** - *

The subclass of {@link SQLException} thrown for the SQLState - * class value '08', representing - * that the connection operation that failed will not succeed when + * The subclass of {@link SQLException} thrown for the SQLState + * class value '08', or under vendor-specified conditions. This + * indicates that the connection operation that failed will not succeed if * the operation is retried without the cause of the failure being corrected. *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLNonTransientConnectionException extends java.sql.SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java b/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java index a1865d93bbb..b50de575943 100644 --- a/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java +++ b/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,9 +26,12 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '42'. This indicates that the + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '42', or under vendor-specified conditions. This indicates that the * in-progress query has violated SQL syntax rules. - * + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLSyntaxErrorException extends SQLNonTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java b/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java index 9e05add35ad..38ced61e3e3 100644 --- a/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java +++ b/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -26,10 +26,13 @@ package java.sql; /** - * The subclass of {@link SQLException} thrown when the SQLState class value is '40'. This indicates that the - * current statement was automatically rolled back by the database becuase of deadlock or other - * transaction serialization failures. - * + * The subclass of {@link SQLException} thrown when the SQLState class value + * is '40', or under vendor-specified conditions. This indicates that the + * current statement was automatically rolled back by the database because + * of deadlock or other transaction serialization failures. + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLTransactionRollbackException extends SQLTransientException { diff --git a/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java b/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java index 865793c1559..3a0e8ea088d 100644 --- a/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java +++ b/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2006, 2010, 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 @@ -27,11 +27,12 @@ package java.sql; /** * The subclass of {@link SQLException} for the SQLState class - * value '08', representing - * that the connection operation that failed might be able to succeed when + * value '08', or under vendor-specified conditions. This indicates + * that the connection operation that failed might be able to succeed if * the operation is retried without any application-level changes. - *

- * + *

+ * Please consult your driver vendor documentation for the vendor-specified + * conditions for which this Exception may be thrown. * @since 1.6 */ public class SQLTransientConnectionException extends java.sql.SQLTransientException { From 96eebc523f2f04b6e4b58ed92f3b1e3232085a79 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Sat, 4 Sep 2010 13:56:27 -0400 Subject: [PATCH 12/27] 6843995: RowSet 1.1 updates Reviewed-by: darcy, valeriep --- .../com/sun/rowset/RowSetFactoryImpl.java | 69 +++ .../javax/sql/rowset/CachedRowSet.java | 86 ++-- .../javax/sql/rowset/RowSetFactory.java | 99 ++++ .../javax/sql/rowset/RowSetProvider.java | 305 ++++++++++++ .../classes/javax/sql/rowset/package.html | 30 +- .../javax/sql/rowset/spi/SyncFactory.java | 456 ++++++++++-------- .../javax/sql/rowset/spi/SyncProvider.java | 24 +- 7 files changed, 794 insertions(+), 275 deletions(-) create mode 100644 jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java create mode 100644 jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java create mode 100644 jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java diff --git a/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java b/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java new file mode 100644 index 00000000000..6f1c0fa385e --- /dev/null +++ b/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, 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. + */ + +package com.sun.rowset; + +import java.sql.SQLException; +import javax.sql.rowset.CachedRowSet; +import javax.sql.rowset.FilteredRowSet; +import javax.sql.rowset.JdbcRowSet; +import javax.sql.rowset.JoinRowSet; +import javax.sql.rowset.WebRowSet; +import javax.sql.rowset.RowSetFactory; + +/** + * This is the implementation specific class for the + * javax.sql.rowset.spi.RowSetFactory. This is the platform + * default implementation for the Java SE platform. + * + * @author Lance Andersen + * + * + * @version 1.7 + */ +public final class RowSetFactoryImpl implements RowSetFactory { + + public CachedRowSet createCachedRowSet() throws SQLException { + return new com.sun.rowset.CachedRowSetImpl(); + } + + public FilteredRowSet createFilteredRowSet() throws SQLException { + return new com.sun.rowset.FilteredRowSetImpl(); + } + + + public JdbcRowSet createJdbcRowSet() throws SQLException { + return new com.sun.rowset.JdbcRowSetImpl(); + } + + public JoinRowSet createJoinRowSet() throws SQLException { + return new com.sun.rowset.JoinRowSetImpl(); + } + + public WebRowSet createWebRowSet() throws SQLException { + return new com.sun.rowset.WebRowSetImpl(); + } + +} diff --git a/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java b/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java index c03d5534345..2a60bb3b7e7 100644 --- a/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java +++ b/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, 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 @@ -644,10 +644,10 @@ public interface CachedRowSet extends RowSet, Joinable { * of execute that takes a ResultSet object. * * @param data the ResultSet object containing the data - * to be read into this CachedRowSet object + * to be read into this CachedRowSet object * @throws SQLException if a null ResultSet object is supplied - * or this CachedRowSet object cannot - * retrieve the associated ResultSetMetaData object + * or this CachedRowSet object cannot + * retrieve the associated ResultSetMetaData object * @see #execute * @see java.sql.ResultSet * @see java.sql.ResultSetMetaData @@ -674,10 +674,10 @@ public interface CachedRowSet extends RowSet, Joinable { * to commit outstanding updates, those updates are lost. * * @param conn a standard JDBC Connection object with valid - * properties + * properties * @throws SQLException if an invalid Connection object is supplied - * or an error occurs in establishing the connection to the - * data source + * or an error occurs in establishing the connection to the + * data source * @see #populate * @see java.sql.Connection */ @@ -736,8 +736,8 @@ public interface CachedRowSet extends RowSet, Joinable { * * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying - * synchronization provider's writer fails to write the updates - * back to the data source + * synchronization provider's writer fails to write the updates + * back to the data source * @see #acceptChanges(java.sql.Connection) * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory @@ -807,8 +807,8 @@ public interface CachedRowSet extends RowSet, Joinable { * @param con a standard JDBC Connection object * @throws SQLException if the cursor is on the insert row * @throws SyncProviderException if the underlying - * synchronization provider's writer fails to write the updates - * back to the data source + * synchronization provider's writer fails to write the updates + * back to the data source * @see #acceptChanges() * @see javax.sql.RowSetWriter * @see javax.sql.rowset.spi.SyncFactory @@ -867,7 +867,7 @@ public interface CachedRowSet extends RowSet, Joinable { * the rowset's Java VM resources. * * @throws SQLException if an error occurs flushing the contents of this - * CachedRowSet object + * CachedRowSet object * @see javax.sql.RowSetListener#rowSetChanged * @see java.sql.ResultSet#close */ @@ -948,9 +948,9 @@ public interface CachedRowSet extends RowSet, Joinable { * * @param idx an int identifying the column to be checked for updates * @return true if the designated column has been visibly updated; - * false otherwise + * false otherwise * @throws SQLException if the cursor is on the insert row, before the first row, - * or after the last row + * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(int idx) throws SQLException; @@ -963,9 +963,9 @@ public interface CachedRowSet extends RowSet, Joinable { * @param columnName a String object giving the name of the * column to be checked for updates * @return true if the column has been visibly updated; - * false otherwise + * false otherwise * @throws SQLException if the cursor is on the insert row, before the first row, - * or after the last row + * or after the last row * @see java.sql.DatabaseMetaData#updatesAreDetected */ public boolean columnUpdated(String columnName) throws SQLException; @@ -1003,7 +1003,7 @@ public interface CachedRowSet extends RowSet, Joinable { *

* * @return a Collection object that contains the values in - * each row in this CachedRowSet object + * each row in this CachedRowSet object * @throws SQLException if an error occurs generating the collection * @see #toCollection(int) * @see #toCollection(String) @@ -1030,10 +1030,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param column an int indicating the column whose values * are to be represented in a Collection object * @return a Collection object that contains the values - * stored in the specified column of this CachedRowSet - * object + * stored in the specified column of this CachedRowSet + * object * @throws SQLException if an error occurs generating the collection or - * an invalid column id is provided + * an invalid column id is provided * @see #toCollection * @see #toCollection(String) */ @@ -1059,10 +1059,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param column a String object giving the name of the * column whose values are to be represented in a collection * @return a Collection object that contains the values - * stored in the specified column of this CachedRowSet - * object + * stored in the specified column of this CachedRowSet + * object * @throws SQLException if an error occurs generating the collection or - * an invalid column id is provided + * an invalid column id is provided * @see #toCollection * @see #toCollection(int) */ @@ -1100,7 +1100,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return the SyncProvider object that was set when the rowset * was instantiated, or if none was was set, the default provider * @throws SQLException if an error occurs while returning the - * SyncProvider object + * SyncProvider object * @see #setSyncProvider */ public SyncProvider getSyncProvider() throws SQLException; @@ -1127,7 +1127,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @param provider a String object giving the fully qualified class * name of a SyncProvider implementation * @throws SQLException if an error occurs while attempting to reset the - * SyncProvider implementation + * SyncProvider implementation * @see #getSyncProvider */ public void setSyncProvider(String provider) throws SQLException; @@ -1152,9 +1152,9 @@ public interface CachedRowSet extends RowSet, Joinable { * object to the rowset. * * @param md a RowSetMetaData object containing - * metadata about the columns in this CachedRowSet object + * metadata about the columns in this CachedRowSet object * @throws SQLException if invalid metadata is supplied to the - * rowset + * rowset */ public void setMetaData(RowSetMetaData md) throws SQLException; @@ -1183,7 +1183,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return a ResultSet object that contains the original value for * this CachedRowSet object * @throws SQLException if an error occurs producing the - * ResultSet object + * ResultSet object */ public ResultSet getOriginal() throws SQLException; @@ -1217,7 +1217,7 @@ public interface CachedRowSet extends RowSet, Joinable { * A call to setOriginalRow is irreversible. * * @throws SQLException if there is no current row or an error is - * encountered resetting the contents of the original row + * encountered resetting the contents of the original row * @see #getOriginalRow */ public void setOriginalRow() throws SQLException; @@ -1326,7 +1326,7 @@ public interface CachedRowSet extends RowSet, Joinable { * as this CachedRowSet object and that has a cursor over * the same data * @throws SQLException if an error occurs or cloning is not - * supported in the underlying platform + * supported in the underlying platform * @see javax.sql.RowSetEvent * @see javax.sql.RowSetListener */ @@ -1344,10 +1344,10 @@ public interface CachedRowSet extends RowSet, Joinable { * established must be maintained. * * @return a new RowSet object that is a deep copy - * of this CachedRowSet object and is - * completely independent of this CachedRowSet object + * of this CachedRowSet object and is + * completely independent of this CachedRowSet object * @throws SQLException if an error occurs in generating the copy of - * the of this CachedRowSet object + * the of this CachedRowSet object * @see #createShared * @see #createCopySchema * @see #createCopyNoConstraints @@ -1396,10 +1396,10 @@ public interface CachedRowSet extends RowSet, Joinable { * in the copy. * * @return a new CachedRowSet object that is a deep copy - * of this CachedRowSet object and is - * completely independent of this CachedRowSet object + * of this CachedRowSet object and is + * completely independent of this CachedRowSet object * @throws SQLException if an error occurs in generating the copy of - * the of this CachedRowSet object + * the of this CachedRowSet object * @see #createCopy * @see #createShared * @see #createCopySchema @@ -1445,7 +1445,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @return true if deleted rows are visible; * false otherwise * @throws SQLException if a rowset implementation is unable to - * to determine whether rows marked for deletion are visible + * to determine whether rows marked for deletion are visible * @see #setShowDeleted */ public boolean getShowDeleted() throws SQLException; @@ -1467,7 +1467,7 @@ public interface CachedRowSet extends RowSet, Joinable { * @param b true if deleted rows should be shown; * false otherwise * @exception SQLException if a rowset implementation is unable to - * to reset whether deleted rows should be visible + * to reset whether deleted rows should be visible * @see #getShowDeleted */ public void setShowDeleted(boolean b) throws SQLException; @@ -1523,9 +1523,12 @@ public interface CachedRowSet extends RowSet, Joinable { * set to false, the changes will not be committed until one of the * CachedRowSet interface transaction methods is called. * + * @deprecated Because this field is final (it is part of an interface), + * its value cannot be changed. * @see #commit * @see #rollback */ + @Deprecated public static final boolean COMMIT_ON_ACCEPT_CHANGES = true; /** @@ -1562,10 +1565,10 @@ public interface CachedRowSet extends RowSet, Joinable { * @param startRow the position in the ResultSet from where to start * populating the records in this CachedRowSet * @param rs the ResultSet object containing the data - * to be read into this CachedRowSet object + * to be read into this CachedRowSet object * @throws SQLException if a null ResultSet object is supplied - * or this CachedRowSet object cannot - * retrieve the associated ResultSetMetaData object + * or this CachedRowSet object cannot + * retrieve the associated ResultSetMetaData object * @see #execute * @see #populate(ResultSet) * @see java.sql.ResultSet @@ -1620,3 +1623,4 @@ public interface CachedRowSet extends RowSet, Joinable { public boolean previousPage() throws SQLException; } + diff --git a/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java b/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java new file mode 100644 index 00000000000..71d2ec531cf --- /dev/null +++ b/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010, 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. + */ + +package javax.sql.rowset; + +import java.sql.SQLException; + +/** + * An interface that defines the implementation of a factory that is used + * to obtain different types of {@code RowSet} implementations. + * + * @author Lance Andersen + * @since 1.7 + */ +public interface RowSetFactory{ + + /** + *

Creates a new instance of a CachedRowSet.

+ * + * @return A new instance of a CachedRowSet. + * + * @throws SQLException if a CachedRowSet cannot + * be created. + * + * @since 1.7 + */ + public CachedRowSet createCachedRowSet() throws SQLException; + + /** + *

Creates a new instance of a FilteredRowSet.

+ * + * @return A new instance of a FilteredRowSet. + * + * @throws SQLException if a FilteredRowSet cannot + * be created. + * + * @since 1.7 + */ + public FilteredRowSet createFilteredRowSet() throws SQLException; + + /** + *

Creates a new instance of a JdbcRowSet.

+ * + * @return A new instance of a JdbcRowSet. + * + * @throws SQLException if a JdbcRowSet cannot + * be created. + * + * @since 1.7 + */ + public JdbcRowSet createJdbcRowSet() throws SQLException; + + /** + *

Creates a new instance of a JoinRowSet.

+ * + * @return A new instance of a JoinRowSet. + * + * @throws SQLException if a JoinRowSet cannot + * be created. + * + * @since 1.7 + */ + public JoinRowSet createJoinRowSet() throws SQLException; + + /** + *

Creates a new instance of a WebRowSet.

+ * + * @return A new instance of a WebRowSet. + * + * @throws SQLException if a WebRowSet cannot + * be created. + * + * @since 1.7 + */ + public WebRowSet createWebRowSet() throws SQLException; + +} \ No newline at end of file diff --git a/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java new file mode 100644 index 00000000000..1a84161ce15 --- /dev/null +++ b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2010, 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. + */ + +package javax.sql.rowset; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.sql.SQLException; +import java.util.ServiceLoader; +import javax.sql.rowset.RowSetFactory; + +/** + * A factory API that enables applications to obtain a + * {@code RowSetFactory} implementation that can be used to create different + * types of {@code RowSet} implementations. + *

+ * Example: + *

+ *
+ * RowSetFactory aFactory = RowSetProvider.newFactory();
+ * CachedRowSet crs = aFactory.createCachedRowSet();
+ * ...
+ * RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);
+ * WebRowSet wrs = rsf.createWebRowSet();
+ * 
+ *

+ * Tracing of this class may be enabled by setting the System property + * {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}. + *

+ * + * @author Lance Andersen + * @since 1.7 + */ +public class RowSetProvider { + + private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug"; + private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl"; + private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory"; + /** + * Internal debug flag. + */ + private static boolean debug = true; + + + static { + // Check to see if the debug property is set + String val = getSystemProperty(ROWSET_DEBUG_PROPERTY); + // Allow simply setting the prop to turn on debug + debug = val != null && !"false".equals(val); + } + + + protected RowSetProvider () { + } + + /** + *

Creates a new instance of a RowSetFactory + * implementation. This method uses the following + * look up order to determine + * the RowSetFactory implementation class to load:

+ *
    + *
  • + * The System property {@code javax.sql.rowset.RowsetFactory}. For example: + *
      + *
    • + * -Djavax.sql.rowset.RowsetFactory=com.sun.rowset.RowSetFactoryImpl + *
    • + *
    + *
  • + * The ServiceLocator API. The ServiceLocator API will look + * for a classname in the file + * {@code META-INF/services/javax.sql.rowset.RowSetFactory} + * in jars available to the runtime. For example, to have the the RowSetFactory + * implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the + * entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be: + *
      + *
    • + * {@code com.sun.rowset.RowSetFactoryImpl } + *
    • + *
    + *
  • + *
  • + * Platform default RowSetFactory instance. + *
  • + *
+ * + *

Once an application has obtained a reference to a {@code RowSetFactory}, + * it can use the factory to obtain RowSet instances.

+ * + * @return New instance of a RowSetFactory + * + * @throws SQLException if the default factory class cannot be loaded, + * instantiated. The cause will be set to actual Exception + * + * @see ServiceLoader + * @since 1.7 + */ + public static RowSetFactory newFactory() + throws SQLException { + // Use the system property first + RowSetFactory factory = null; + String factoryClassName = null; + try { + trace("Checking for Rowset System Property..."); + factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME); + if (factoryClassName != null) { + trace("Found system property, value=" + factoryClassName); + factory = (RowSetFactory) getFactoryClass(factoryClassName, null, true).newInstance(); + } + } catch (ClassNotFoundException e) { + throw new SQLException( + "RowSetFactory: " + factoryClassName + " not found", e); + } catch (Exception e) { + throw new SQLException( + "RowSetFactory: " + factoryClassName + " could not be instantiated: " + e, + e); + } + + // Check to see if we found the RowSetFactory via a System property + if (factory == null) { + // If the RowSetFactory is not found via a System Property, now + // look it up via the ServiceLoader API and if not found, use the + // Java SE default. + factory = loadViaServiceLoader(); + factory = + factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory; + } + return (factory); + } + + /** + *

Creates a new instance of a RowSetFactory from the + * specified factory class name. + * This function is useful when there are multiple providers in the classpath. + * It gives more control to the application as it can specify which provider + * should be loaded.

+ * + *

Once an application has obtained a reference to a RowSetFactory + * it can use the factory to obtain RowSet instances.

+ * + * @param factoryClassName fully qualified factory class name that + * provides an implementation of javax.sql.rowset.RowSetFactory. + * + * @param cl ClassLoader used to load the factory + * class. If null current Thread's context + * classLoader is used to load the factory class. + * + * @return New instance of a RowSetFactory + * + * @throws SQLException if factoryClassName is + * null, or the factory class cannot be loaded, instantiated. + * + * @see #newFactory() + * + * @since 1.7 + */ + public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl) + throws SQLException { + + trace("***In newInstance()"); + try { + Class providerClass = getFactoryClass(factoryClassName, cl, false); + RowSetFactory instance = (RowSetFactory) providerClass.newInstance(); + if (debug) { + trace("Created new instance of " + providerClass + + " using ClassLoader: " + cl); + } + return instance; + } catch (ClassNotFoundException x) { + throw new SQLException( + "Provider " + factoryClassName + " not found", x); + } catch (Exception x) { + throw new SQLException( + "Provider " + factoryClassName + " could not be instantiated: " + x, + x); + } + } + + /* + * Returns the class loader to be used. + * @return The ClassLoader to use. + * + */ + static private ClassLoader getContextClassLoader() throws SecurityException { + return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() { + + public Object run() { + ClassLoader cl = null; + + cl = Thread.currentThread().getContextClassLoader(); + + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + return cl; + } + }); + } + + /** + * Attempt to load a class using the class loader supplied. If that fails + * and fall back is enabled, the current (i.e. bootstrap) class loader is + * tried. + * + * If the class loader supplied is null, first try using the + * context class loader followed by the current class loader. + * @return The class which was loaded + */ + static private Class getFactoryClass(String factoryClassName, ClassLoader cl, + boolean doFallback) throws ClassNotFoundException { + try { + if (cl == null) { + cl = getContextClassLoader(); + if (cl == null) { + throw new ClassNotFoundException(); + } else { + return cl.loadClass(factoryClassName); + } + } else { + return cl.loadClass(factoryClassName); + } + } catch (ClassNotFoundException e) { + if (doFallback) { + // Use current class loader + return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader()); + } else { + throw e; + } + } + } + + /** + * Use the ServiceLoader mechanism to load the default RowSetFactory + * @return default RowSetFactory Implementation + */ + static private RowSetFactory loadViaServiceLoader() { + RowSetFactory theFactory = null; + trace("***in loadViaServiceLoader()"); + for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) { + trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName()); + theFactory = factory; + break; + } + return theFactory; + + } + + /** + * Returns the requested System Property. If a {@code SecurityException} + * occurs, just return NULL + * @param propName - System property to retreive + * @return The System property value or NULL if the property does not exist + * or a {@code SecurityException} occurs. + */ + static private String getSystemProperty(final String propName) { + String property = null; + try { + property = (String) AccessController.doPrivileged(new PrivilegedAction() { + + public Object run() { + return System.getProperty(propName); + } + }); + } catch (SecurityException se) { + if (debug) { + se.printStackTrace(); + } + } + return property; + } + + /** + * Debug routine which will output tracing if the System Property + * -Djavax.sql.rowset.RowSetFactory.debug is set + * @param msg - The debug message to display + */ + private static void trace(String msg) { + if (debug) { + System.err.println("###RowSets: " + msg); + } + } +} diff --git a/jdk/src/share/classes/javax/sql/rowset/package.html b/jdk/src/share/classes/javax/sql/rowset/package.html index 41d00d565b5..8b905cd63aa 100644 --- a/jdk/src/share/classes/javax/sql/rowset/package.html +++ b/jdk/src/share/classes/javax/sql/rowset/package.html @@ -5,7 +5,7 @@