6893238: Move NTLM and SPNEGO implementations into separate packages
authorchegar
Wed, 21 Oct 2009 15:41:42 +0100
changeset 4157 558590fb3b49
parent 4061 35a627ad2443
child 4158 0b4d21bc8b5c
6893238: Move NTLM and SPNEGO implementations into separate packages Reviewed-by: michaelm, alanb
jdk/make/java/net/Makefile
jdk/make/sun/net/FILES_java.gmk
jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java
jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java
jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java
jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java
jdk/src/share/classes/sun/net/www/protocol/http/NegotiateCallbackHandler.java
jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java
jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java
jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java
jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java
jdk/src/share/classes/sun/security/jgss/GSSUtil.java
jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthSequence.java
jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java
jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java
jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
jdk/src/windows/native/sun/net/www/protocol/http/NTLMAuthSequence.c
jdk/src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c
--- a/jdk/make/java/net/Makefile	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/make/java/net/Makefile	Wed Oct 21 15:41:42 2009 +0100
@@ -83,7 +83,7 @@
 #
 # Find platform specific native code
 #
-vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http $(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/spi
 
 #
 # Include rules
--- a/jdk/make/sun/net/FILES_java.gmk	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/make/sun/net/FILES_java.gmk	Wed Oct 21 15:41:42 2009 +0100
@@ -89,11 +89,12 @@
 	sun/net/www/protocol/http/AuthScheme.java \
 	sun/net/www/protocol/http/BasicAuthentication.java \
 	sun/net/www/protocol/http/DigestAuthentication.java \
-	sun/net/www/protocol/http/NTLMAuthentication.java \
 	sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
 	sun/net/www/protocol/http/NegotiateAuthentication.java \
-	sun/net/www/protocol/http/NegotiatorImpl.java \
-	sun/net/www/protocol/http/NegotiateCallbackHandler.java \
+	sun/net/www/protocol/http/Negotiator.java \
+	sun/net/www/protocol/http/ntlm/NTLMAuthentication.java \
+	sun/net/www/protocol/http/spnego/NegotiatorImpl.java \
+	sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java \
 	sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java \
 	sun/net/www/protocol/https/HttpsClient.java \
 	sun/net/www/protocol/https/DefaultHostnameVerifier.java \
@@ -128,7 +129,7 @@
 	sun/net/idn/StringPrep.java
 
 ifeq ($(PLATFORM), windows)
-    FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java 
+    FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java 
 endif
 
 ifeq ($(PLATFORM), solaris)
--- a/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Wed Oct 21 15:41:42 2009 +0100
@@ -25,12 +25,10 @@
 
 package sun.net.www.protocol.http;
 
-import java.io.*;
-import java.net.*;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.PasswordAuthentication;
+import java.net.URL;
 import java.util.HashMap;
 
 import sun.net.www.HeaderParser;
@@ -51,12 +49,12 @@
 //      policy in HttpURLConnection.  A failure on baz.foo.com shouldn't
 //      uncache foo.com!
 
-abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
+public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
 
     // Constants saying what kind of authroization this is.  This determines
     // the namespace in the hash table lookup.
-    static final char SERVER_AUTHENTICATION = 's';
-    static final char PROXY_AUTHENTICATION = 'p';
+    public static final char SERVER_AUTHENTICATION = 's';
+    public static final char PROXY_AUTHENTICATION = 'p';
 
     /**
      * If true, then simultaneous authentication requests to the same realm/proxy
@@ -188,7 +186,7 @@
     String path;
 
     /** Use this constructor only for proxy entries */
-    AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
+    public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
         this.type = type;
         this.authScheme = authScheme;
         this.protocol = "";
@@ -211,7 +209,7 @@
      * Constructor used to limit the authorization to the path within
      * the URL. Use this constructor for origin server entries.
      */
-    AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
+    public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
         this.type = type;
         this.authScheme = authScheme;
         this.protocol = url.getProtocol().toLowerCase();
@@ -358,13 +356,19 @@
     /**
      * @return true if this authentication supports preemptive authorization
      */
-    abstract boolean supportsPreemptiveAuthorization();
+    public abstract boolean supportsPreemptiveAuthorization();
 
     /**
      * @return the name of the HTTP header this authentication wants set.
      *          This is used for preemptive authorization.
      */
-    abstract String getHeaderName();
+    public String getHeaderName() {
+        if (type == SERVER_AUTHENTICATION) {
+            return "Authorization";
+        } else {
+            return "Proxy-authorization";
+        }
+    }
 
     /**
      * Calculates and returns the authentication header value based
@@ -375,7 +379,7 @@
      * @return the value of the HTTP header this authentication wants set.
      *          Used for preemptive authorization.
      */
-    abstract String getHeaderValue(URL url, String method);
+    public abstract String getHeaderValue(URL url, String method);
 
     /**
      * Set header(s) on the given connection.  Subclasses must override
@@ -386,7 +390,7 @@
      * @param raw The raw header field (if needed)
      * @return true if all goes well, false if no headers were set.
      */
-    abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
+    public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
 
     /**
      * Check if the header indicates that the current auth. parameters are stale.
@@ -396,7 +400,7 @@
      * returning false means we have to go back to the user to ask for a new
      * username password.
      */
-    abstract boolean isAuthorizationStale (String header);
+    public abstract boolean isAuthorizationStale (String header);
 
     /**
      * Give a key for hash table lookups.
--- a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Wed Oct 21 15:41:42 2009 +0100
@@ -131,22 +131,12 @@
     /**
      * @return true if this authentication supports preemptive authorization
      */
-    boolean supportsPreemptiveAuthorization() {
+    @Override
+    public boolean supportsPreemptiveAuthorization() {
         return true;
     }
 
     /**
-     * @return the name of the HTTP header this authentication wants set
-     */
-    String getHeaderName() {
-        if (type == SERVER_AUTHENTICATION) {
-            return "Authorization";
-        } else {
-            return "Proxy-authorization";
-        }
-    }
-
-    /**
      * Set header(s) on the given connection. This will only be called for
      * definitive (i.e. non-preemptive) authorization.
      * @param conn The connection to apply the header(s) to
@@ -154,7 +144,8 @@
      * @param raw The raw header values for this connection, if needed.
      * @return true if all goes well, false if no headers were set.
      */
-    boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
+    @Override
+    public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
         conn.setAuthenticationProperty(getHeaderName(), getHeaderValue(null,null));
         return true;
     }
@@ -162,7 +153,8 @@
     /**
      * @return the value of the HTTP header this authentication wants set
      */
-    String getHeaderValue(URL url, String method) {
+    @Override
+    public String getHeaderValue(URL url, String method) {
         /* For Basic the authorization string does not depend on the request URL
          * or the request method
          */
@@ -174,7 +166,8 @@
      * In other words there is no possibility to reuse the credentials.
      * They are always either valid or invalid.
      */
-    boolean isAuthorizationStale (String header) {
+    @Override
+    public boolean isAuthorizationStale (String header) {
         return false;
     }
 
--- a/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Wed Oct 21 15:41:42 2009 +0100
@@ -200,22 +200,12 @@
     /**
      * @return true if this authentication supports preemptive authorization
      */
-    boolean supportsPreemptiveAuthorization() {
+    @Override
+    public boolean supportsPreemptiveAuthorization() {
         return true;
     }
 
     /**
-     * @return the name of the HTTP header this authentication wants set
-     */
-    String getHeaderName() {
-        if (type == SERVER_AUTHENTICATION) {
-            return "Authorization";
-        } else {
-            return "Proxy-Authorization";
-        }
-    }
-
-    /**
      * Reclaculates the request-digest and returns it.
      *
      * <P> Used in the common case where the requestURI is simply the
@@ -229,7 +219,8 @@
      *
      * @return the value of the HTTP header this authentication wants set
      */
-    String getHeaderValue(URL url, String method) {
+    @Override
+    public String getHeaderValue(URL url, String method) {
         return getHeaderValueImpl(url.getFile(), method);
     }
 
@@ -259,7 +250,8 @@
      * returning false means we have to go back to the user to ask for a new
      * username password.
      */
-    boolean isAuthorizationStale (String header) {
+    @Override
+    public boolean isAuthorizationStale (String header) {
         HeaderParser p = new HeaderParser (header);
         String s = p.findValue ("stale");
         if (s == null || !s.equals("true"))
@@ -279,7 +271,8 @@
      * @param raw Raw header values for this connection, if needed.
      * @return true if all goes well, false if no headers were set.
      */
-    boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
+    @Override
+    public boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
         params.setNonce (p.findValue("nonce"));
         params.setOpaque (p.findValue("opaque"));
         params.setQop (p.findValue("qop"));
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Wed Oct 21 15:41:42 2009 +0100
@@ -243,7 +243,7 @@
     private boolean tryTransparentNTLMProxy = true;
 
     /* Used by Windows specific code */
-    Object authObj;
+    private Object authObj;
 
     /* Set if the user is manually setting the Authorization or Proxy-Authorization headers */
     boolean isUserServerAuth;
@@ -332,6 +332,15 @@
         return logger;
     }
 
+    /* Used for Windows NTLM implementation */
+    public Object authObj() {
+        return authObj;
+    }
+
+    public void authObj(Object authObj) {
+        this.authObj = authObj;
+    }
+
     /*
      * checks the validity of http message header and throws
      * IllegalArgumentException if invalid.
@@ -2529,7 +2538,7 @@
     // Set a property for authentication.  This can safely disregard
     // the connected test.
     //
-    void setAuthenticationProperty(String key, String value) {
+    public void setAuthenticationProperty(String key, String value) {
         checkMessageHeader(key, value);
         requests.set(key, value);
     }
--- a/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java	Wed Oct 21 15:41:42 2009 +0100
@@ -36,7 +36,7 @@
  */
 class NTLMAuthenticationProxy {
     private static Method supportsTA;
-    private static final String clazzStr = "sun.net.www.protocol.http.NTLMAuthentication";
+    private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication";
     private static final String supportsTAStr = "supportsTransparentAuth";
 
     static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
--- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Wed Oct 21 15:41:42 2009 +0100
@@ -25,17 +25,13 @@
 
 package sun.net.www.protocol.http;
 
+import java.net.URL;
+import java.io.IOException;
+import java.net.Authenticator.RequestorType;
 import java.util.HashMap;
-
 import sun.net.www.HeaderParser;
 import sun.misc.BASE64Decoder;
 import sun.misc.BASE64Encoder;
-import sun.util.logging.PlatformLogger;
-
-import java.net.URL;
-import java.io.IOException;
-import java.net.Authenticator.RequestorType;
-import java.lang.reflect.Constructor;
 import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
 import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
 
@@ -78,7 +74,8 @@
     /**
      * @return true if this authentication supports preemptive authorization
      */
-    boolean supportsPreemptiveAuthorization() {
+    @Override
+    public boolean supportsPreemptiveAuthorization() {
         return false;
     }
 
@@ -104,34 +101,24 @@
             return supported.get(hostname);
         }
 
-        try {
-            Negotiator neg = Negotiator.getSupported(hci);
+        Negotiator neg = Negotiator.getNegotiator(hci);
+        if (neg != null) {
             supported.put(hostname, true);
             // the only place cache.put is called. here we can make sure
             // the object is valid and the oneToken inside is not null
             cache.put(hostname, neg);
             return true;
-        } catch(Exception e) {
+        } else {
             supported.put(hostname, false);
             return false;
         }
     }
 
     /**
-     * @return the name of the HTTP header this authentication wants to set
-     */
-    String getHeaderName() {
-        if (type == SERVER_AUTHENTICATION) {
-            return "Authorization";
-        } else {
-            return "Proxy-Authorization";
-        }
-    }
-
-    /**
      * Not supported. Must use the setHeaders() method
      */
-    String getHeaderValue(URL url, String method) {
+    @Override
+    public String getHeaderValue(URL url, String method) {
         throw new RuntimeException ("getHeaderValue not supported");
     }
 
@@ -143,7 +130,8 @@
      * returning false means we have to go back to the user to ask for a new
      * username password.
      */
-    boolean isAuthorizationStale (String header) {
+    @Override
+    public boolean isAuthorizationStale (String header) {
         return false; /* should not be called for Negotiate */
     }
 
@@ -155,7 +143,8 @@
      * @param raw The raw header field.
      * @return true if all goes well, false if no headers were set.
      */
-    synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
+    @Override
+    public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
 
         try {
             String response;
@@ -177,7 +166,7 @@
     /**
      * return the first token.
      * @returns the token
-     * @throws IOException if <code>Negotiator.getSupported()</code> or
+     * @throws IOException if <code>Negotiator.getNegotiator()</code> or
      *                     <code>Negotiator.firstToken()</code> failed.
      */
     private byte[] firstToken() throws IOException {
@@ -191,11 +180,9 @@
             }
         }
         if (negotiator == null) {
-            try {
-                negotiator = Negotiator.getSupported(hci);
-            } catch(Exception e) {
+            negotiator = Negotiator.getNegotiator(hci);
+            if (negotiator == null) {
                 IOException ioe = new IOException("Cannot initialize Negotiator");
-                ioe.initCause(e);
                 throw ioe;
             }
         }
@@ -228,55 +215,3 @@
     // Currently we ignore this header.
 
 }
-
-/**
- * This abstract class is a bridge to connect NegotiteAuthentication and
- * NegotiatorImpl, so that JAAS and JGSS calls can be made
- */
-abstract class Negotiator {
-    static Negotiator getSupported(HttpCallerInfo hci)
-                throws Exception {
-
-        // These lines are equivalent to
-        //     return new NegotiatorImpl(hci);
-        // The current implementation will make sure NegotiatorImpl is not
-        // directly referenced when compiling, thus smooth the way of building
-        // the J2SE platform where HttpURLConnection is a bootstrap class.
-        //
-        // Makes NegotiatorImpl, and the security classes it references, a
-        // runtime dependency rather than a static one.
-
-        Class clazz;
-        Constructor c;
-        try {
-            clazz = Class.forName("sun.net.www.protocol.http.NegotiatorImpl", true, null);
-            c = clazz.getConstructor(HttpCallerInfo.class);
-        } catch (ClassNotFoundException cnfe) {
-            finest(cnfe);
-            throw cnfe;
-        } catch (ReflectiveOperationException roe) {
-            // if the class is there then something seriously wrong if
-            // the constructor is not.
-            throw new AssertionError(roe);
-        }
-
-        try {
-            return (Negotiator) (c.newInstance(hci));
-        } catch (ReflectiveOperationException roe) {
-            finest(roe);
-            Throwable t = roe.getCause();
-            if (t != null && t instanceof Exception)
-                finest((Exception)t);
-            throw roe;
-        }
-    }
-
-    abstract byte[] firstToken() throws IOException;
-
-    abstract byte[] nextToken(byte[] in) throws IOException;
-
-    static void finest(Exception e) {
-        PlatformLogger logger = HttpURLConnection.getHttpLogger();
-        logger.finest("NegotiateAuthentication: " + e);
-    }
-}
--- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiateCallbackHandler.java	Mon Oct 19 16:31:48 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright 2005-2009 Sun Microsystems, 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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.net.www.protocol.http;
-import java.io.IOException;
-import java.net.Authenticator;
-import java.net.PasswordAuthentication;
-import java.util.Arrays;
-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;
-
-/**
- * @since 1.6
- * Special callback handler used in JGSS for the HttpCaller.
- */
-public class NegotiateCallbackHandler implements CallbackHandler {
-
-    private String username;
-    private char[] password;
-
-    private final HttpCallerInfo hci;
-
-    public NegotiateCallbackHandler(HttpCallerInfo hci) {
-        this.hci = hci;
-    }
-
-    public void handle(Callback[] callbacks) throws
-            UnsupportedCallbackException, IOException {
-        for (int i=0; i<callbacks.length; i++) {
-            Callback callBack = callbacks[i];
-
-            if (callBack instanceof NameCallback) {
-                if (username == null) {
-                    PasswordAuthentication passAuth =
-                            Authenticator.requestPasswordAuthentication(
-                            hci.host, hci.addr, hci.port, hci.protocol,
-                            hci.prompt, hci.scheme, hci.url, hci.authType);
-                    username = passAuth.getUserName();
-                    password = passAuth.getPassword();
-                }
-                NameCallback nameCallback =
-                        (NameCallback)callBack;
-                nameCallback.setName(username);
-
-            } else if (callBack instanceof PasswordCallback) {
-                PasswordCallback passwordCallback =
-                        (PasswordCallback)callBack;
-                if (password == null) {
-                    PasswordAuthentication passAuth =
-                            Authenticator.requestPasswordAuthentication(
-                            hci.host, hci.addr, hci.port, hci.protocol,
-                            hci.prompt, hci.scheme, hci.url, hci.authType);
-                    username = passAuth.getUserName();
-                    password = passAuth.getPassword();
-                }
-                passwordCallback.setPassword(password);
-                Arrays.fill(password, ' ');
-            } else {
-                throw new UnsupportedCallbackException(callBack,
-                        "Call back not supported");
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/Negotiator.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2009 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * This abstract class is a bridge to connect NegotiteAuthentication and
+ * NegotiatorImpl, so that JAAS and JGSS calls can be made
+ */
+public abstract class Negotiator {
+    static Negotiator getNegotiator(HttpCallerInfo hci) {
+
+        // These lines are equivalent to
+        // return new NegotiatorImpl(hci);
+        // The current implementation will make sure NegotiatorImpl is not
+        // directly referenced when compiling, thus smooth the way of building
+        // the J2SE platform where HttpURLConnection is a bootstrap class.
+        //
+        // Makes NegotiatorImpl, and the security classes it references, a
+        // runtime dependency rather than a static one.
+
+        Class clazz;
+        Constructor c;
+        try {
+            clazz = Class.forName("sun.net.www.protocol.http.spnego.NegotiatorImpl", true, null);
+            c = clazz.getConstructor(HttpCallerInfo.class);
+        } catch (ClassNotFoundException cnfe) {
+            finest(cnfe);
+            return null;
+        } catch (ReflectiveOperationException roe) {
+            // if the class is there then something seriously wrong if
+            // the constructor is not.
+            throw new AssertionError(roe);
+        }
+
+        try {
+            return (Negotiator) (c.newInstance(hci));
+        } catch (ReflectiveOperationException roe) {
+            finest(roe);
+            Throwable t = roe.getCause();
+            if (t != null && t instanceof Exception)
+                finest((Exception)t);
+            return null;
+        }
+    }
+
+    public abstract byte[] firstToken() throws IOException;
+
+    public abstract byte[] nextToken(byte[] in) throws IOException;
+
+    private static void finest(Exception e) {
+        PlatformLogger logger = HttpURLConnection.getHttpLogger();
+        logger.finest("NegotiateAuthentication: " + e);
+    }
+}
+
--- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java	Mon Oct 19 16:31:48 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/*
- * Copyright 2005-2009 Sun Microsystems, 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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.net.www.protocol.http;
-
-import java.io.IOException;
-
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSName;
-import org.ietf.jgss.Oid;
-
-import sun.security.jgss.GSSManagerImpl;
-import sun.security.jgss.GSSUtil;
-import sun.security.jgss.HttpCaller;
-
-/**
- * This class encapsulates all JAAS and JGSS API calls in a separate class
- * outside NegotiateAuthentication.java so that J2SE build can go smoothly
- * without the presence of it.
- *
- * @author weijun.wang@sun.com
- * @since 1.6
- */
-public class NegotiatorImpl extends Negotiator {
-
-    private static final boolean DEBUG =
-        java.security.AccessController.doPrivileged(
-              new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
-
-    private GSSContext context;
-    private byte[] oneToken;
-
-    /**
-     * Initialize the object, which includes:<ul>
-     * <li>Find out what GSS mechanism to use from the system property
-     * <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO
-     * <li>Creating the GSSName for the target host, "HTTP/"+hostname
-     * <li>Creating GSSContext
-     * <li>A first call to initSecContext</ul>
-     */
-    private void init(HttpCallerInfo hci) throws GSSException {
-        final Oid oid;
-
-        if (hci.scheme.equalsIgnoreCase("Kerberos")) {
-            // we can only use Kerberos mech when the scheme is kerberos
-            oid = GSSUtil.GSS_KRB5_MECH_OID;
-        } else {
-            String pref = java.security.AccessController.doPrivileged(
-                    new java.security.PrivilegedAction<String>() {
-                        public String run() {
-                            return System.getProperty(
-                                "http.auth.preference",
-                                "spnego");
-                        }
-                    });
-            if (pref.equalsIgnoreCase("kerberos")) {
-                oid = GSSUtil.GSS_KRB5_MECH_OID;
-            } else {
-                // currently there is no 3rd mech we can use
-                oid = GSSUtil.GSS_SPNEGO_MECH_OID;
-            }
-        }
-
-        GSSManagerImpl manager = new GSSManagerImpl(
-                new HttpCaller(hci));
-
-        // RFC 4559 4.1 uses uppercase service name "HTTP".
-        // RFC 4120 6.2.1 demands the host be lowercase
-        String peerName = "HTTP@" + hci.host.toLowerCase();
-
-        GSSName serverName = manager.createName(peerName,
-                GSSName.NT_HOSTBASED_SERVICE);
-        context = manager.createContext(serverName,
-                                        oid,
-                                        null,
-                                        GSSContext.DEFAULT_LIFETIME);
-
-        // In order to support credential delegation in HTTP/SPNEGO,
-        // we always request it before initSecContext. The current
-        // implementation will check the OK-AS-DELEGATE flag inside
-        // the service ticket of the web server, and only enable
-        // delegation when this flag is set. This check is only
-        // performed when the GSS caller is CALLER_HTTP_NEGOTIATE,
-        // so all other normal GSS-API calls are not affected.
-
-        context.requestCredDeleg(true);
-        oneToken = context.initSecContext(new byte[0], 0, 0);
-    }
-
-    /**
-     * Constructor
-     * @throws java.io.IOException If negotiator cannot be constructed
-     */
-    public NegotiatorImpl(HttpCallerInfo hci) throws IOException {
-        try {
-            init(hci);
-        } catch (GSSException e) {
-            if (DEBUG) {
-                System.out.println("Negotiate support not initiated, will " +
-                        "fallback to other scheme if allowed. Reason:");
-                e.printStackTrace();
-            }
-            IOException ioe = new IOException("Negotiate support not initiated");
-            ioe.initCause(e);
-            throw ioe;
-        }
-    }
-
-    /**
-     * Return the first token of GSS, in SPNEGO, it's called NegTokenInit
-     * @return the first token
-     */
-    public byte[] firstToken() {
-        return oneToken;
-    }
-
-    /**
-     * Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg
-     * @param token the token received from server
-     * @return the next token
-     * @throws java.io.IOException if the token cannot be created successfully
-     */
-    public byte[] nextToken(byte[] token) throws IOException {
-        try {
-            return context.initSecContext(token, 0, token.length);
-        } catch (GSSException e) {
-            if (DEBUG) {
-                System.out.println("Negotiate support cannot continue. Reason:");
-                e.printStackTrace();
-            }
-            IOException ioe = new IOException("Negotiate support cannot continue");
-            ioe.initCause(e);
-            throw ioe;
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2005-2009 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http.spnego;
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.util.Arrays;
+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 sun.net.www.protocol.http.HttpCallerInfo;
+
+/**
+ * @since 1.6
+ * Special callback handler used in JGSS for the HttpCaller.
+ */
+public class NegotiateCallbackHandler implements CallbackHandler {
+
+    private String username;
+    private char[] password;
+
+    private final HttpCallerInfo hci;
+
+    public NegotiateCallbackHandler(HttpCallerInfo hci) {
+        this.hci = hci;
+    }
+
+    public void handle(Callback[] callbacks) throws
+            UnsupportedCallbackException, IOException {
+        for (int i=0; i<callbacks.length; i++) {
+            Callback callBack = callbacks[i];
+
+            if (callBack instanceof NameCallback) {
+                if (username == null) {
+                    PasswordAuthentication passAuth =
+                            Authenticator.requestPasswordAuthentication(
+                            hci.host, hci.addr, hci.port, hci.protocol,
+                            hci.prompt, hci.scheme, hci.url, hci.authType);
+                    username = passAuth.getUserName();
+                    password = passAuth.getPassword();
+                }
+                NameCallback nameCallback =
+                        (NameCallback)callBack;
+                nameCallback.setName(username);
+
+            } else if (callBack instanceof PasswordCallback) {
+                PasswordCallback passwordCallback =
+                        (PasswordCallback)callBack;
+                if (password == null) {
+                    PasswordAuthentication passAuth =
+                            Authenticator.requestPasswordAuthentication(
+                            hci.host, hci.addr, hci.port, hci.protocol,
+                            hci.prompt, hci.scheme, hci.url, hci.authType);
+                    username = passAuth.getUserName();
+                    password = passAuth.getPassword();
+                }
+                passwordCallback.setPassword(password);
+                Arrays.fill(password, ' ');
+            } else {
+                throw new UnsupportedCallbackException(callBack,
+                        "Call back not supported");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/spnego/NegotiatorImpl.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2005-2009 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http.spnego;
+
+import java.io.IOException;
+
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+import sun.net.www.protocol.http.HttpCallerInfo;
+import sun.net.www.protocol.http.Negotiator;
+import sun.security.jgss.GSSManagerImpl;
+import sun.security.jgss.GSSUtil;
+import sun.security.jgss.HttpCaller;
+
+/**
+ * This class encapsulates all JAAS and JGSS API calls in a separate class
+ * outside NegotiateAuthentication.java so that J2SE build can go smoothly
+ * without the presence of it.
+ *
+ * @author weijun.wang@sun.com
+ * @since 1.6
+ */
+public class NegotiatorImpl extends Negotiator {
+
+    private static final boolean DEBUG =
+        java.security.AccessController.doPrivileged(
+              new sun.security.action.GetBooleanAction("sun.security.krb5.debug"));
+
+    private GSSContext context;
+    private byte[] oneToken;
+
+    /**
+     * Initialize the object, which includes:<ul>
+     * <li>Find out what GSS mechanism to use from the system property
+     * <code>http.negotiate.mechanism.oid</code>, defaults SPNEGO
+     * <li>Creating the GSSName for the target host, "HTTP/"+hostname
+     * <li>Creating GSSContext
+     * <li>A first call to initSecContext</ul>
+     */
+    private void init(HttpCallerInfo hci) throws GSSException {
+        final Oid oid;
+
+        if (hci.scheme.equalsIgnoreCase("Kerberos")) {
+            // we can only use Kerberos mech when the scheme is kerberos
+            oid = GSSUtil.GSS_KRB5_MECH_OID;
+        } else {
+            String pref = java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<String>() {
+                        public String run() {
+                            return System.getProperty(
+                                "http.auth.preference",
+                                "spnego");
+                        }
+                    });
+            if (pref.equalsIgnoreCase("kerberos")) {
+                oid = GSSUtil.GSS_KRB5_MECH_OID;
+            } else {
+                // currently there is no 3rd mech we can use
+                oid = GSSUtil.GSS_SPNEGO_MECH_OID;
+            }
+        }
+
+        GSSManagerImpl manager = new GSSManagerImpl(
+                new HttpCaller(hci));
+
+        // RFC 4559 4.1 uses uppercase service name "HTTP".
+        // RFC 4120 6.2.1 demands the host be lowercase
+        String peerName = "HTTP@" + hci.host.toLowerCase();
+
+        GSSName serverName = manager.createName(peerName,
+                GSSName.NT_HOSTBASED_SERVICE);
+        context = manager.createContext(serverName,
+                                        oid,
+                                        null,
+                                        GSSContext.DEFAULT_LIFETIME);
+
+        // In order to support credential delegation in HTTP/SPNEGO,
+        // we always request it before initSecContext. The current
+        // implementation will check the OK-AS-DELEGATE flag inside
+        // the service ticket of the web server, and only enable
+        // delegation when this flag is set. This check is only
+        // performed when the GSS caller is CALLER_HTTP_NEGOTIATE,
+        // so all other normal GSS-API calls are not affected.
+
+        context.requestCredDeleg(true);
+        oneToken = context.initSecContext(new byte[0], 0, 0);
+    }
+
+    /**
+     * Constructor
+     * @throws java.io.IOException If negotiator cannot be constructed
+     */
+    public NegotiatorImpl(HttpCallerInfo hci) throws IOException {
+        try {
+            init(hci);
+        } catch (GSSException e) {
+            if (DEBUG) {
+                System.out.println("Negotiate support not initiated, will " +
+                        "fallback to other scheme if allowed. Reason:");
+                e.printStackTrace();
+            }
+            IOException ioe = new IOException("Negotiate support not initiated");
+            ioe.initCause(e);
+            throw ioe;
+        }
+    }
+
+    /**
+     * Return the first token of GSS, in SPNEGO, it's called NegTokenInit
+     * @return the first token
+     */
+    @Override
+    public byte[] firstToken() {
+        return oneToken;
+    }
+
+    /**
+     * Return the rest tokens of GSS, in SPNEGO, it's called NegTokenTarg
+     * @param token the token received from server
+     * @return the next token
+     * @throws java.io.IOException if the token cannot be created successfully
+     */
+    @Override
+    public byte[] nextToken(byte[] token) throws IOException {
+        try {
+            return context.initSecContext(token, 0, token.length);
+        } catch (GSSException e) {
+            if (DEBUG) {
+                System.out.println("Negotiate support cannot continue. Reason:");
+                e.printStackTrace();
+            }
+            IOException ioe = new IOException("Negotiate support cannot continue");
+            ioe.initCause(e);
+            throw ioe;
+        }
+    }
+}
--- a/jdk/src/share/classes/sun/security/jgss/GSSUtil.java	Mon Oct 19 16:31:48 2009 -0700
+++ b/jdk/src/share/classes/sun/security/jgss/GSSUtil.java	Wed Oct 21 15:41:42 2009 +0100
@@ -237,7 +237,7 @@
 
         CallbackHandler cb = null;
         if (caller instanceof HttpCaller) {
-            cb = new sun.net.www.protocol.http.NegotiateCallbackHandler(
+            cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler(
                     ((HttpCaller)caller).info());
         } else {
             String defaultHandler =
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2005-2008 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http.ntlm;
+
+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;
+import sun.net.www.protocol.http.AuthScheme;
+import sun.net.www.protocol.http.HttpURLConnection;
+
+/**
+ * NTLMAuthentication:
+ *
+ * @author Michael McMahon
+ */
+
+/*
+ * NTLM authentication is nominally based on the framework defined in RFC2617,
+ * but differs from the standard (Basic & Digest) schemes as follows:
+ *
+ * 1. A complete authentication requires three request/response transactions
+ *    as shown below:
+ *            REQ ------------------------------->
+ *            <---- 401 (signalling NTLM) --------
+ *
+ *            REQ (with type1 NTLM msg) --------->
+ *            <---- 401 (with type 2 NTLM msg) ---
+ *
+ *            REQ (with type3 NTLM msg) --------->
+ *            <---- OK ---------------------------
+ *
+ * 2. The scope of the authentication is the TCP connection (which must be kept-alive)
+ *    after the type2 response is received. This means that NTLM does not work end-to-end
+ *    through a proxy, rather between client and proxy, or between client and server (with no proxy)
+ */
+
+public class NTLMAuthentication extends AuthenticationInfo {
+    private static final long serialVersionUID = -2403849171106437142L;
+
+    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 */
+
+    static {
+        defaultDomain = java.security.AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
+                                                      "domain"));
+    };
+
+    public static boolean supportsTransparentAuth () {
+        return false;
+    }
+
+    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<String>() {
+                public String run() {
+                    String localhost;
+                    try {
+                        localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
+                    } catch (UnknownHostException e) {
+                         localhost = "localhost";
+                    }
+                    return localhost;
+                }
+            });
+            int x = hostname.indexOf ('.');
+            if (x != -1) {
+                hostname = hostname.substring (0, x);
+            }
+            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;
+        }
+    };
+
+    PasswordAuthentication pw;
+    String username;
+    String ntdomain;
+    String password;
+
+    /**
+     * Create a NTLMAuthentication:
+     * Username may be specified as domain<BACKSLASH>username in the application Authenticator.
+     * If this notation is not used, then the domain will be taken
+     * from a system property: "http.auth.ntlm.domain".
+     */
+    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+                AuthScheme.NTLM,
+                url,
+                "");
+        init (pw);
+    }
+
+    private void init (PasswordAuthentication pw) {
+        this.pw = pw;
+        String s = pw.getUserName();
+        int i = s.indexOf ('\\');
+        if (i == -1) {
+            username = s;
+            ntdomain = defaultDomain;
+        } else {
+            ntdomain = s.substring (0, i).toUpperCase();
+            username = s.substring (i+1);
+        }
+        password = new String (pw.getPassword());
+        init0();
+    }
+
+   /**
+    * Constructor used for proxy entries
+    */
+    public NTLMAuthentication(boolean isProxy, String host, int port,
+                                PasswordAuthentication pw) {
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+                AuthScheme.NTLM,
+                host,
+                port,
+                "");
+        init (pw);
+    }
+
+    /**
+     * @return true if this authentication supports preemptive authorization
+     */
+    @Override
+    public boolean supportsPreemptiveAuthorization() {
+        return false;
+    }
+
+    /**
+     * Not supported. Must use the setHeaders() method
+     */
+    @Override
+    public String getHeaderValue(URL url, String method) {
+        throw new RuntimeException ("getHeaderValue not supported");
+    }
+
+    /**
+     * Check if the header indicates that the current auth. parameters are stale.
+     * If so, then replace the relevant field with the new value
+     * and return true. Otherwise return false.
+     * returning true means the request can be retried with the same userid/password
+     * returning false means we have to go back to the user to ask for a new
+     * username password.
+     */
+    @Override
+    public boolean isAuthorizationStale (String header) {
+        return false; /* should not be called for ntlm */
+    }
+
+    /**
+     * Set header(s) on the given connection.
+     * @param conn The connection to apply the header(s) to
+     * @param p A source of header values for this connection, not used because
+     *          HeaderParser converts the fields to lower case, use raw instead
+     * @param raw The raw header field.
+     * @return true if all goes well, false if no headers were set.
+     */
+    @Override
+    public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
+
+        try {
+            String response;
+            if (raw.length() < 6) { /* NTLM<sp> */
+                response = buildType1Msg ();
+            } else {
+                String msg = raw.substring (5); /* skip NTLM<sp> */
+                response = buildType3Msg (msg);
+            }
+            conn.setAuthenticationProperty(getHeaderName(), response);
+            return true;
+        } catch (IOException e) {
+            return false;
+        } catch (GeneralSecurityException e) {
+            return false;
+        }
+    }
+
+    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);
+        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<in.length; i++ ) {
+            in[i] = input[i]<0 ? input[i]+256: input[i];
+        }
+        byte[] out = new byte[8];
+        out[0] = (byte)in[off+0];
+        out[1] = (byte)(((in[off+0] << 7) & 0xFF) | (in[off+1] >> 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);
+        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 () {
+        return 1024;
+    }
+}
--- a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthSequence.java	Mon Oct 19 16:31:48 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright 2002 Sun Microsystems, 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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.net.www.protocol.http;
-
-import java.io.IOException;
-import sun.misc.BASE64Encoder;
-import sun.misc.BASE64Decoder;
-
-/*
- * Hooks into Windows implementation of NTLM.
- * This class will be replaced if a cross-platform version of NTLM
- * is implemented in the future.
- */
-
-public class NTLMAuthSequence {
-
-    private String username;
-    private String password;
-    private String ntdomain;
-    private int state;
-    private long crdHandle;
-    private long ctxHandle;
-
-    static {
-        initFirst();
-    }
-
-    NTLMAuthSequence (String username, String password, String ntdomain)
-    throws IOException
-    {
-        this.username = username;
-        this.password = password;
-        this.ntdomain = ntdomain;
-        state = 0;
-        crdHandle = getCredentialsHandle (username, ntdomain, password);
-        if (crdHandle == 0) {
-            throw new IOException ("could not get credentials handle");
-        }
-    }
-
-    public String getAuthHeader (String token) throws IOException {
-        byte[] input = null;
-        if (token != null)
-            input = (new BASE64Decoder()).decodeBuffer(token);
-        byte[] b = getNextToken (crdHandle, input);
-        if (b == null)
-            throw new IOException ("Internal authentication error");
-        return (new B64Encoder()).encode (b);
-    }
-
-    private native static void initFirst ();
-
-    private native long getCredentialsHandle (String user, String domain, String password);
-
-    private native byte[] getNextToken (long crdHandle, byte[] lastToken);
-}
-
-class B64Encoder extends BASE64Encoder {
-    protected int bytesPerLine () {
-        return 1024;
-    }
-}
--- a/jdk/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java	Mon Oct 19 16:31:48 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,195 +0,0 @@
-/*
- * Copyright 2002-2005 Sun Microsystems, 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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.net.www.protocol.http;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.PasswordAuthentication;
-import java.net.UnknownHostException;
-import java.net.URL;
-import sun.net.www.HeaderParser;
-
-/**
- * NTLMAuthentication:
- *
- * @author Michael McMahon
- */
-
-class NTLMAuthentication extends AuthenticationInfo {
-
-    private static final long serialVersionUID = 100L;
-
-    private String hostname;
-    private static String defaultDomain; /* Domain to use if not specified by user */
-
-    static {
-        defaultDomain = java.security.AccessController.doPrivileged(
-            new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
-                                                      "domain"));
-    };
-
-    private void init0() {
-
-        hostname = java.security.AccessController.doPrivileged(
-            new java.security.PrivilegedAction<String>() {
-            public String run() {
-                String localhost;
-                try {
-                    localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
-                } catch (UnknownHostException e) {
-                     localhost = "localhost";
-                }
-                return localhost;
-            }
-        });
-        int x = hostname.indexOf ('.');
-        if (x != -1) {
-            hostname = hostname.substring (0, x);
-        }
-    }
-
-    String username;
-    String ntdomain;
-    String password;
-
-    /**
-     * Create a NTLMAuthentication:
-     * Username may be specified as domain<BACKSLASH>username in the application Authenticator.
-     * If this notation is not used, then the domain will be taken
-     * from a system property: "http.auth.ntlm.domain".
-     */
-    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
-        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              AuthScheme.NTLM,
-              url,
-              "");
-        init (pw);
-    }
-
-    private void init (PasswordAuthentication pw) {
-        this.pw = pw;
-        if (pw != null) {
-            String s = pw.getUserName();
-            int i = s.indexOf ('\\');
-            if (i == -1) {
-                username = s;
-                ntdomain = defaultDomain;
-            } else {
-                ntdomain = s.substring (0, i).toUpperCase();
-                username = s.substring (i+1);
-            }
-            password = new String (pw.getPassword());
-        } else {
-            /* credentials will be acquired from OS */
-            username = null;
-            ntdomain = null;
-            password = null;
-        }
-        init0();
-    }
-
-   /**
-    * Constructor used for proxy entries
-    */
-    public NTLMAuthentication(boolean isProxy, String host, int port,
-                                PasswordAuthentication pw) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
-              AuthScheme.NTLM,
-              host,
-              port,
-              "");
-        init (pw);
-    }
-
-    /**
-     * @return true if this authentication supports preemptive authorization
-     */
-    boolean supportsPreemptiveAuthorization() {
-        return false;
-    }
-
-    /**
-     * @return true if NTLM supported transparently (no password needed, SSO)
-     */
-    static boolean supportsTransparentAuth() {
-        return true;
-    }
-
-    /**
-     * @return the name of the HTTP header this authentication wants set
-     */
-    String getHeaderName() {
-        if (type == SERVER_AUTHENTICATION) {
-            return "Authorization";
-        } else {
-            return "Proxy-authorization";
-        }
-    }
-
-    /**
-     * Not supported. Must use the setHeaders() method
-     */
-    String getHeaderValue(URL url, String method) {
-        throw new RuntimeException ("getHeaderValue not supported");
-    }
-
-    /**
-     * Check if the header indicates that the current auth. parameters are stale.
-     * If so, then replace the relevant field with the new value
-     * and return true. Otherwise return false.
-     * returning true means the request can be retried with the same userid/password
-     * returning false means we have to go back to the user to ask for a new
-     * username password.
-     */
-    boolean isAuthorizationStale (String header) {
-        return false; /* should not be called for ntlm */
-    }
-
-    /**
-     * Set header(s) on the given connection.
-     * @param conn The connection to apply the header(s) to
-     * @param p A source of header values for this connection, not used because
-     *          HeaderParser converts the fields to lower case, use raw instead
-     * @param raw The raw header field.
-     * @return true if all goes well, false if no headers were set.
-     */
-    synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
-
-        try {
-            NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj;
-            if (seq == null) {
-                seq = new NTLMAuthSequence (username, password, ntdomain);
-                conn.authObj = seq;
-            }
-            String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
-            conn.setAuthenticationProperty(getHeaderName(), response);
-            return true;
-        } catch (IOException e) {
-            return false;
-        }
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2002 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http.ntlm;
+
+import java.io.IOException;
+import sun.misc.BASE64Encoder;
+import sun.misc.BASE64Decoder;
+
+/*
+ * Hooks into Windows implementation of NTLM.
+ * This class will be replaced if a cross-platform version of NTLM
+ * is implemented in the future.
+ */
+
+public class NTLMAuthSequence {
+
+    private String username;
+    private String password;
+    private String ntdomain;
+    private int state;
+    private long crdHandle;
+    private long ctxHandle;
+
+    static {
+        initFirst();
+    }
+
+    NTLMAuthSequence (String username, String password, String ntdomain)
+    throws IOException
+    {
+        this.username = username;
+        this.password = password;
+        this.ntdomain = ntdomain;
+        state = 0;
+        crdHandle = getCredentialsHandle (username, ntdomain, password);
+        if (crdHandle == 0) {
+            throw new IOException ("could not get credentials handle");
+        }
+    }
+
+    public String getAuthHeader (String token) throws IOException {
+        byte[] input = null;
+        if (token != null)
+            input = (new BASE64Decoder()).decodeBuffer(token);
+        byte[] b = getNextToken (crdHandle, input);
+        if (b == null)
+            throw new IOException ("Internal authentication error");
+        return (new B64Encoder()).encode (b);
+    }
+
+    private native static void initFirst ();
+
+    private native long getCredentialsHandle (String user, String domain, String password);
+
+    private native byte[] getNextToken (long crdHandle, byte[] lastToken);
+}
+
+class B64Encoder extends BASE64Encoder {
+    protected int bytesPerLine () {
+        return 1024;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2002-2005 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www.protocol.http.ntlm;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.PasswordAuthentication;
+import java.net.UnknownHostException;
+import java.net.URL;
+import sun.net.www.HeaderParser;
+import sun.net.www.protocol.http.AuthenticationInfo;
+import sun.net.www.protocol.http.AuthScheme;
+import sun.net.www.protocol.http.HttpURLConnection;
+
+/**
+ * NTLMAuthentication:
+ *
+ * @author Michael McMahon
+ */
+
+public class NTLMAuthentication extends AuthenticationInfo {
+
+    private static final long serialVersionUID = 100L;
+
+    private String hostname;
+    private static String defaultDomain; /* Domain to use if not specified by user */
+
+    static {
+        defaultDomain = java.security.AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("http.auth.ntlm.domain",
+                                                      "domain"));
+    };
+
+    private void init0() {
+
+        hostname = java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<String>() {
+            public String run() {
+                String localhost;
+                try {
+                    localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
+                } catch (UnknownHostException e) {
+                     localhost = "localhost";
+                }
+                return localhost;
+            }
+        });
+        int x = hostname.indexOf ('.');
+        if (x != -1) {
+            hostname = hostname.substring (0, x);
+        }
+    }
+
+    String username;
+    String ntdomain;
+    String password;
+
+    /**
+     * Create a NTLMAuthentication:
+     * Username may be specified as domain<BACKSLASH>username in the application Authenticator.
+     * If this notation is not used, then the domain will be taken
+     * from a system property: "http.auth.ntlm.domain".
+     */
+    public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+              AuthScheme.NTLM,
+              url,
+              "");
+        init (pw);
+    }
+
+    private void init (PasswordAuthentication pw) {
+        this.pw = pw;
+        if (pw != null) {
+            String s = pw.getUserName();
+            int i = s.indexOf ('\\');
+            if (i == -1) {
+                username = s;
+                ntdomain = defaultDomain;
+            } else {
+                ntdomain = s.substring (0, i).toUpperCase();
+                username = s.substring (i+1);
+            }
+            password = new String (pw.getPassword());
+        } else {
+            /* credentials will be acquired from OS */
+            username = null;
+            ntdomain = null;
+            password = null;
+        }
+        init0();
+    }
+
+   /**
+    * Constructor used for proxy entries
+    */
+    public NTLMAuthentication(boolean isProxy, String host, int port,
+                                PasswordAuthentication pw) {
+        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
+              AuthScheme.NTLM,
+              host,
+              port,
+              "");
+        init (pw);
+    }
+
+    /**
+     * @return true if this authentication supports preemptive authorization
+     */
+    @Override
+    public boolean supportsPreemptiveAuthorization() {
+        return false;
+    }
+
+    /**
+     * @return true if NTLM supported transparently (no password needed, SSO)
+     */
+    public static boolean supportsTransparentAuth() {
+        return true;
+    }
+
+    /**
+     * Not supported. Must use the setHeaders() method
+     */
+    @Override
+    public String getHeaderValue(URL url, String method) {
+        throw new RuntimeException ("getHeaderValue not supported");
+    }
+
+    /**
+     * Check if the header indicates that the current auth. parameters are stale.
+     * If so, then replace the relevant field with the new value
+     * and return true. Otherwise return false.
+     * returning true means the request can be retried with the same userid/password
+     * returning false means we have to go back to the user to ask for a new
+     * username password.
+     */
+    @Override
+    public boolean isAuthorizationStale (String header) {
+        return false; /* should not be called for ntlm */
+    }
+
+    /**
+     * Set header(s) on the given connection.
+     * @param conn The connection to apply the header(s) to
+     * @param p A source of header values for this connection, not used because
+     *          HeaderParser converts the fields to lower case, use raw instead
+     * @param raw The raw header field.
+     * @return true if all goes well, false if no headers were set.
+     */
+    @Override
+    public synchronized boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw) {
+
+        try {
+            NTLMAuthSequence seq = (NTLMAuthSequence)conn.authObj();
+            if (seq == null) {
+                seq = new NTLMAuthSequence (username, password, ntdomain);
+                conn.authObj(seq);
+            }
+            String response = "NTLM " + seq.getAuthHeader (raw.length()>6?raw.substring(5):null);
+            conn.setAuthenticationProperty(getHeaderName(), response);
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+}
--- a/jdk/src/windows/native/sun/net/www/protocol/http/NTLMAuthSequence.c	Mon Oct 19 16:31:48 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,311 +0,0 @@
-/*
- * Copyright 2002-2008 Sun Microsystems, 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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-#include <jni.h>
-#include <windows.h>
-#include <rpc.h>
-#include <winsock.h>
-#include <lm.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <tchar.h>
-#include <fcntl.h>
-
-#include "jni_util.h"
-
-#define SECURITY_WIN32
-#include "sspi.h"
-
-
-/*
- * OS calls loaded from DLL on intialization
- */
-
-static FREE_CREDENTIALS_HANDLE_FN pFreeCredentialsHandle;
-static ACQUIRE_CREDENTIALS_HANDLE_FN pAcquireCredentialsHandle;
-static FREE_CONTEXT_BUFFER_FN pFreeContextBuffer;
-static INITIALIZE_SECURITY_CONTEXT_FN pInitializeSecurityContext;
-static COMPLETE_AUTH_TOKEN_FN pCompleteAuthToken;
-static DELETE_SECURITY_CONTEXT_FN pDeleteSecurityContext;
-
-static void endSequence (PCredHandle credHand, PCtxtHandle ctxHandle);
-
-static jfieldID ntlm_ctxHandleID;
-static jfieldID ntlm_crdHandleID;
-
-static HINSTANCE lib = NULL;
-
-JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_initFirst
-(JNIEnv *env, jclass clazz)
-{
-    OSVERSIONINFO   version;
-    UCHAR libName[MAX_PATH];
-
-    ntlm_ctxHandleID = (*env)->GetFieldID(env, clazz, "ctxHandle", "J");
-    ntlm_crdHandleID = (*env)->GetFieldID(env, clazz, "crdHandle", "J");
-
-    version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
-    GetVersionEx (&version);
-
-    if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-        strcpy (libName, "security.dll" );
-    }
-    else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
-        strcpy (libName, "secur32.dll" );
-    }
-
-    lib = LoadLibrary (libName);
-
-    pFreeCredentialsHandle
-        = (FREE_CREDENTIALS_HANDLE_FN) GetProcAddress(
-        lib, "FreeCredentialsHandle" );
-
-    pAcquireCredentialsHandle
-        = (ACQUIRE_CREDENTIALS_HANDLE_FN) GetProcAddress(
-        lib, "AcquireCredentialsHandleA" );
-
-    pFreeContextBuffer
-        = (FREE_CONTEXT_BUFFER_FN) GetProcAddress(
-        lib, "FreeContextBuffer" );
-
-    pInitializeSecurityContext
-        = (INITIALIZE_SECURITY_CONTEXT_FN) GetProcAddress(
-        lib, "InitializeSecurityContextA" );
-
-    pCompleteAuthToken
-        = (COMPLETE_AUTH_TOKEN_FN) GetProcAddress(
-        lib, "CompleteAuthToken" );
-
-    pDeleteSecurityContext
-        = (DELETE_SECURITY_CONTEXT_FN) GetProcAddress(
-        lib, "DeleteSecurityContext" );
-
-}
-
-/*
- * Class:     sun_net_www_protocol_http_NTLMAuthSequence
- * Method:    getCredentialsHandle
- * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
- */
-
-JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_getCredentialsHandle
-(JNIEnv *env, jobject this, jstring user, jstring domain, jstring password)
-{
-    SEC_WINNT_AUTH_IDENTITY   AuthId;
-    SEC_WINNT_AUTH_IDENTITY * pAuthId;
-    const CHAR        *pUser = 0;
-    const CHAR        *pDomain = 0;
-    const CHAR        *pPassword = 0;
-    CredHandle      *pCred;
-    TimeStamp            ltime;
-    jboolean         isCopy;
-    SECURITY_STATUS      ss;
-
-    if (user != 0) {
-        pUser = JNU_GetStringPlatformChars(env, user, &isCopy);
-        if (pUser == NULL)
-            return 0;  // pending Exception
-    }
-    if (domain != 0) {
-        pDomain = JNU_GetStringPlatformChars(env, domain, &isCopy);
-        if (pDomain == NULL) {
-            if (pUser != NULL)
-                JNU_ReleaseStringPlatformChars(env, user, pUser);
-            return 0;  // pending Exception
-        }
-    }
-    if (password != 0) {
-        pPassword = JNU_GetStringPlatformChars(env, password, &isCopy);
-        if (pPassword == NULL) {
-            if(pUser != NULL)
-                JNU_ReleaseStringPlatformChars(env, user, pUser);
-            if(pDomain != NULL)
-                JNU_ReleaseStringPlatformChars(env, domain, pDomain);
-            return 0;  // pending Exception
-        }
-    }
-    pCred = (CredHandle *)malloc(sizeof (CredHandle));
-
-    if ( ((pUser != NULL) || (pPassword != NULL)) || (pDomain != NULL)) {
-        pAuthId = &AuthId;
-
-        memset( &AuthId, 0, sizeof( AuthId ));
-
-        if ( pUser != NULL ) {
-            AuthId.User       = (unsigned char *) pUser;
-            AuthId.UserLength = strlen( pUser );
-        }
-
-        if ( pPassword != NULL ) {
-            AuthId.Password       = (unsigned char *) pPassword;
-            AuthId.PasswordLength = strlen( pPassword );
-        }
-
-        if ( pDomain != NULL ) {
-            AuthId.Domain       = (unsigned char *) pDomain;
-            AuthId.DomainLength = strlen( pDomain );
-        }
-
-        AuthId.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
-    } else {
-        pAuthId = NULL;
-    }
-
-    ss = pAcquireCredentialsHandle(
-        NULL, "NTLM", SECPKG_CRED_OUTBOUND,
-        NULL, pAuthId, NULL, NULL,
-        pCred, &ltime
-        );
-
-    /* Release resources held by JNU_GetStringPlatformChars */
-    if (pUser != NULL)
-        JNU_ReleaseStringPlatformChars(env, user, pUser);
-    if (pPassword != NULL)
-        JNU_ReleaseStringPlatformChars(env, password, pPassword);
-    if (pDomain != NULL)
-        JNU_ReleaseStringPlatformChars(env, domain, pDomain);
-
-    if (ss == 0) {
-        return (jlong) pCred;
-    } else {
-        return 0;
-    }
-}
-
-JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_NTLMAuthSequence_getNextToken
-(JNIEnv *env, jobject this, jlong crdHandle, jbyteArray lastToken)
-{
-
-    VOID        *pInput = 0;
-    DWORD            inputLen;
-    CHAR         buffOut[512];
-    jboolean         isCopy;
-    SECURITY_STATUS      ss;
-    SecBufferDesc        OutBuffDesc;
-    SecBuffer            OutSecBuff;
-    SecBufferDesc        InBuffDesc;
-    SecBuffer            InSecBuff;
-    ULONG                ContextAttributes;
-    CredHandle      *pCred = (CredHandle *)crdHandle;
-    CtxtHandle      *pCtx;
-    CtxtHandle      *newContext;
-    TimeStamp            ltime;
-    jbyteArray       result;
-
-
-    pCtx = (CtxtHandle *) (*env)->GetLongField (env, this, ntlm_ctxHandleID);
-    if (pCtx == 0) { /* first call */
-        newContext = (CtxtHandle *)malloc(sizeof(CtxtHandle));
-        (*env)->SetLongField (env, this, ntlm_ctxHandleID, (jlong)newContext);
-    } else {
-        newContext = pCtx;
-    }
-
-    OutBuffDesc.ulVersion = 0;
-    OutBuffDesc.cBuffers  = 1;
-    OutBuffDesc.pBuffers  = &OutSecBuff;
-
-    OutSecBuff.cbBuffer   = 512;
-    OutSecBuff.BufferType = SECBUFFER_TOKEN;
-    OutSecBuff.pvBuffer   = buffOut;
-
-    /*
-     *  Prepare our Input buffer - Note the server is expecting the client's
-     *  negotiation packet on the first call
-     */
-
-    if (lastToken != 0)
-    {
-        pInput = (VOID *)(*env)->GetByteArrayElements(env, lastToken, &isCopy);
-        inputLen = (*env)->GetArrayLength(env, lastToken);
-
-        InBuffDesc.ulVersion = 0;
-        InBuffDesc.cBuffers  = 1;
-        InBuffDesc.pBuffers  = &InSecBuff;
-
-        InSecBuff.cbBuffer       = inputLen;
-        InSecBuff.BufferType = SECBUFFER_TOKEN;
-        InSecBuff.pvBuffer       = pInput;
-    }
-
-    /*
-     *  will return success when its done but we still
-     *  need to send the out buffer if there are bytes to send
-     */
-
-    ss = pInitializeSecurityContext(
-        pCred, pCtx, NULL, 0, 0, SECURITY_NATIVE_DREP,
-        lastToken ? &InBuffDesc : NULL, 0, newContext, &OutBuffDesc,
-        &ContextAttributes, &ltime
-    );
-
-    if (pInput != 0) {
-        (*env)->ReleaseByteArrayElements(env, lastToken, pInput, JNI_ABORT);
-    }
-
-    if (ss < 0) {
-        endSequence (pCred, pCtx);
-        return 0;
-    }
-
-    if ((ss == SEC_I_COMPLETE_NEEDED) || (ss == SEC_I_COMPLETE_AND_CONTINUE) ) {
-        ss = pCompleteAuthToken( pCtx, &OutBuffDesc );
-
-        if (ss < 0) {
-            endSequence (pCred, pCtx);
-            return 0;
-        }
-    }
-
-    if ( OutSecBuff.cbBuffer > 0 ) {
-        jbyteArray ret = (*env)->NewByteArray(env, OutSecBuff.cbBuffer);
-        (*env)->SetByteArrayRegion(env, ret, 0, OutSecBuff.cbBuffer,
-                OutSecBuff.pvBuffer);
-        if (lastToken != 0) // 2nd stage
-            endSequence (pCred, pCtx);
-        result = ret;
-    }
-
-    if ((ss != SEC_I_CONTINUE_NEEDED) && (ss == SEC_I_COMPLETE_AND_CONTINUE)) {
-        endSequence (pCred, pCtx);
-    }
-
-    return result;
-}
-
-static void endSequence (PCredHandle credHand, PCtxtHandle ctxHandle) {
-    if (credHand != 0) {
-        pFreeCredentialsHandle (credHand);
-        free (credHand);
-    }
-
-    if (ctxHandle != 0) {
-        pDeleteSecurityContext(ctxHandle);
-        free (ctxHandle);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c	Wed Oct 21 15:41:42 2009 +0100
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2002-2008 Sun Microsystems, 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <jni.h>
+#include <windows.h>
+#include <rpc.h>
+#include <winsock.h>
+#include <lm.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tchar.h>
+#include <fcntl.h>
+
+#include "jni_util.h"
+
+#define SECURITY_WIN32
+#include "sspi.h"
+
+
+/*
+ * OS calls loaded from DLL on intialization
+ */
+
+static FREE_CREDENTIALS_HANDLE_FN pFreeCredentialsHandle;
+static ACQUIRE_CREDENTIALS_HANDLE_FN pAcquireCredentialsHandle;
+static FREE_CONTEXT_BUFFER_FN pFreeContextBuffer;
+static INITIALIZE_SECURITY_CONTEXT_FN pInitializeSecurityContext;
+static COMPLETE_AUTH_TOKEN_FN pCompleteAuthToken;
+static DELETE_SECURITY_CONTEXT_FN pDeleteSecurityContext;
+
+static void endSequence (PCredHandle credHand, PCtxtHandle ctxHandle);
+
+static jfieldID ntlm_ctxHandleID;
+static jfieldID ntlm_crdHandleID;
+
+static HINSTANCE lib = NULL;
+
+JNIEXPORT void JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_initFirst
+(JNIEnv *env, jclass clazz)
+{
+    OSVERSIONINFO   version;
+    UCHAR libName[MAX_PATH];
+
+    ntlm_ctxHandleID = (*env)->GetFieldID(env, clazz, "ctxHandle", "J");
+    ntlm_crdHandleID = (*env)->GetFieldID(env, clazz, "crdHandle", "J");
+
+    version.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+    GetVersionEx (&version);
+
+    if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+        strcpy (libName, "security.dll" );
+    }
+    else if (version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
+        strcpy (libName, "secur32.dll" );
+    }
+
+    lib = LoadLibrary (libName);
+
+    pFreeCredentialsHandle
+        = (FREE_CREDENTIALS_HANDLE_FN) GetProcAddress(
+        lib, "FreeCredentialsHandle" );
+
+    pAcquireCredentialsHandle
+        = (ACQUIRE_CREDENTIALS_HANDLE_FN) GetProcAddress(
+        lib, "AcquireCredentialsHandleA" );
+
+    pFreeContextBuffer
+        = (FREE_CONTEXT_BUFFER_FN) GetProcAddress(
+        lib, "FreeContextBuffer" );
+
+    pInitializeSecurityContext
+        = (INITIALIZE_SECURITY_CONTEXT_FN) GetProcAddress(
+        lib, "InitializeSecurityContextA" );
+
+    pCompleteAuthToken
+        = (COMPLETE_AUTH_TOKEN_FN) GetProcAddress(
+        lib, "CompleteAuthToken" );
+
+    pDeleteSecurityContext
+        = (DELETE_SECURITY_CONTEXT_FN) GetProcAddress(
+        lib, "DeleteSecurityContext" );
+
+}
+
+/*
+ * Class:     sun_net_www_protocol_http_NTLMAuthSequence
+ * Method:    getCredentialsHandle
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J
+ */
+
+JNIEXPORT jlong JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_getCredentialsHandle
+(JNIEnv *env, jobject this, jstring user, jstring domain, jstring password)
+{
+    SEC_WINNT_AUTH_IDENTITY   AuthId;
+    SEC_WINNT_AUTH_IDENTITY * pAuthId;
+    const CHAR        *pUser = 0;
+    const CHAR        *pDomain = 0;
+    const CHAR        *pPassword = 0;
+    CredHandle      *pCred;
+    TimeStamp            ltime;
+    jboolean         isCopy;
+    SECURITY_STATUS      ss;
+
+    if (user != 0) {
+        pUser = JNU_GetStringPlatformChars(env, user, &isCopy);
+        if (pUser == NULL)
+            return 0;  // pending Exception
+    }
+    if (domain != 0) {
+        pDomain = JNU_GetStringPlatformChars(env, domain, &isCopy);
+        if (pDomain == NULL) {
+            if (pUser != NULL)
+                JNU_ReleaseStringPlatformChars(env, user, pUser);
+            return 0;  // pending Exception
+        }
+    }
+    if (password != 0) {
+        pPassword = JNU_GetStringPlatformChars(env, password, &isCopy);
+        if (pPassword == NULL) {
+            if(pUser != NULL)
+                JNU_ReleaseStringPlatformChars(env, user, pUser);
+            if(pDomain != NULL)
+                JNU_ReleaseStringPlatformChars(env, domain, pDomain);
+            return 0;  // pending Exception
+        }
+    }
+    pCred = (CredHandle *)malloc(sizeof (CredHandle));
+
+    if ( ((pUser != NULL) || (pPassword != NULL)) || (pDomain != NULL)) {
+        pAuthId = &AuthId;
+
+        memset( &AuthId, 0, sizeof( AuthId ));
+
+        if ( pUser != NULL ) {
+            AuthId.User       = (unsigned char *) pUser;
+            AuthId.UserLength = strlen( pUser );
+        }
+
+        if ( pPassword != NULL ) {
+            AuthId.Password       = (unsigned char *) pPassword;
+            AuthId.PasswordLength = strlen( pPassword );
+        }
+
+        if ( pDomain != NULL ) {
+            AuthId.Domain       = (unsigned char *) pDomain;
+            AuthId.DomainLength = strlen( pDomain );
+        }
+
+        AuthId.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+    } else {
+        pAuthId = NULL;
+    }
+
+    ss = pAcquireCredentialsHandle(
+        NULL, "NTLM", SECPKG_CRED_OUTBOUND,
+        NULL, pAuthId, NULL, NULL,
+        pCred, &ltime
+        );
+
+    /* Release resources held by JNU_GetStringPlatformChars */
+    if (pUser != NULL)
+        JNU_ReleaseStringPlatformChars(env, user, pUser);
+    if (pPassword != NULL)
+        JNU_ReleaseStringPlatformChars(env, password, pPassword);
+    if (pDomain != NULL)
+        JNU_ReleaseStringPlatformChars(env, domain, pDomain);
+
+    if (ss == 0) {
+        return (jlong) pCred;
+    } else {
+        return 0;
+    }
+}
+
+JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequence_getNextToken
+(JNIEnv *env, jobject this, jlong crdHandle, jbyteArray lastToken)
+{
+
+    VOID        *pInput = 0;
+    DWORD            inputLen;
+    CHAR         buffOut[512];
+    jboolean         isCopy;
+    SECURITY_STATUS      ss;
+    SecBufferDesc        OutBuffDesc;
+    SecBuffer            OutSecBuff;
+    SecBufferDesc        InBuffDesc;
+    SecBuffer            InSecBuff;
+    ULONG                ContextAttributes;
+    CredHandle      *pCred = (CredHandle *)crdHandle;
+    CtxtHandle      *pCtx;
+    CtxtHandle      *newContext;
+    TimeStamp            ltime;
+    jbyteArray       result;
+
+
+    pCtx = (CtxtHandle *) (*env)->GetLongField (env, this, ntlm_ctxHandleID);
+    if (pCtx == 0) { /* first call */
+        newContext = (CtxtHandle *)malloc(sizeof(CtxtHandle));
+        (*env)->SetLongField (env, this, ntlm_ctxHandleID, (jlong)newContext);
+    } else {
+        newContext = pCtx;
+    }
+
+    OutBuffDesc.ulVersion = 0;
+    OutBuffDesc.cBuffers  = 1;
+    OutBuffDesc.pBuffers  = &OutSecBuff;
+
+    OutSecBuff.cbBuffer   = 512;
+    OutSecBuff.BufferType = SECBUFFER_TOKEN;
+    OutSecBuff.pvBuffer   = buffOut;
+
+    /*
+     *  Prepare our Input buffer - Note the server is expecting the client's
+     *  negotiation packet on the first call
+     */
+
+    if (lastToken != 0)
+    {
+        pInput = (VOID *)(*env)->GetByteArrayElements(env, lastToken, &isCopy);
+        inputLen = (*env)->GetArrayLength(env, lastToken);
+
+        InBuffDesc.ulVersion = 0;
+        InBuffDesc.cBuffers  = 1;
+        InBuffDesc.pBuffers  = &InSecBuff;
+
+        InSecBuff.cbBuffer       = inputLen;
+        InSecBuff.BufferType = SECBUFFER_TOKEN;
+        InSecBuff.pvBuffer       = pInput;
+    }
+
+    /*
+     *  will return success when its done but we still
+     *  need to send the out buffer if there are bytes to send
+     */
+
+    ss = pInitializeSecurityContext(
+        pCred, pCtx, NULL, 0, 0, SECURITY_NATIVE_DREP,
+        lastToken ? &InBuffDesc : NULL, 0, newContext, &OutBuffDesc,
+        &ContextAttributes, &ltime
+    );
+
+    if (pInput != 0) {
+        (*env)->ReleaseByteArrayElements(env, lastToken, pInput, JNI_ABORT);
+    }
+
+    if (ss < 0) {
+        endSequence (pCred, pCtx);
+        return 0;
+    }
+
+    if ((ss == SEC_I_COMPLETE_NEEDED) || (ss == SEC_I_COMPLETE_AND_CONTINUE) ) {
+        ss = pCompleteAuthToken( pCtx, &OutBuffDesc );
+
+        if (ss < 0) {
+            endSequence (pCred, pCtx);
+            return 0;
+        }
+    }
+
+    if ( OutSecBuff.cbBuffer > 0 ) {
+        jbyteArray ret = (*env)->NewByteArray(env, OutSecBuff.cbBuffer);
+        (*env)->SetByteArrayRegion(env, ret, 0, OutSecBuff.cbBuffer,
+                OutSecBuff.pvBuffer);
+        if (lastToken != 0) // 2nd stage
+            endSequence (pCred, pCtx);
+        result = ret;
+    }
+
+    if ((ss != SEC_I_CONTINUE_NEEDED) && (ss == SEC_I_COMPLETE_AND_CONTINUE)) {
+        endSequence (pCred, pCtx);
+    }
+
+    return result;
+}
+
+static void endSequence (PCredHandle credHand, PCtxtHandle ctxHandle) {
+    if (credHand != 0) {
+        pFreeCredentialsHandle (credHand);
+        free (credHand);
+    }
+
+    if (ctxHandle != 0) {
+        pDeleteSecurityContext(ctxHandle);
+        free (ctxHandle);
+    }
+}