[jcifs] Fix for JCIFS NTLM HTTP Authentication and W2k3

Ti Lian Hwang lian_hwang.ti at fairprice.com.sg
Wed Jan 9 09:24:34 GMT 2008


The following is a possible fix to the infamous
NTLM HTTP Authentication against W2k3 problem.

It comes with a penalty of not reusing the NtlmPasswordAuthentication
objects and its transports.

Not exactly sure why it works, but it seems the preauthentication
somehow messes up the NtlmPasswordAuthentication object with
regards to the hash and challenges.

I've stress tested it with 4 simultaneous cmd windows,
running over 80 curl calls each, 
and setting jcifs.smb.client.soTimeout to 2000, forcing early expiration,
with no error.

The curl version used is

curl 7.16.1 (i386-pc-win32) libcurl/7.16.1 OpenSSL/0.9.8b zlib/1.2.3
Protocols: tftp ftp telnet dict ldap http file https ftps
Features: Largefile NTLM SSL libz

JCIFS 1.2.17 

jcifs.smb.NtlmPasswordAuthentication
------------------------------------

    public boolean equals( Object obj ) {
        if( obj instanceof NtlmPasswordAuthentication ) {
            NtlmPasswordAuthentication ntlm = (NtlmPasswordAuthentication)obj;
            if( ntlm.domain.toUpperCase().equals( domain.toUpperCase() ) &&
                        ntlm.username.toUpperCase().equals( username.toUpperCase() )) {
                if( hashesExternal && ntlm.hashesExternal ) {
                    return Arrays.equals( ansiHash, ntlm.ansiHash ) &&
                            // tlh - add next 2 lines
                            Arrays.equals( challenge, ntlm.challenge ) &&
                            Arrays.equals( clientChallenge, ntlm.clientChallenge ) &&
                                Arrays.equals( unicodeHash, ntlm.unicodeHash );
                    /* This still isn't quite right. If one npa object does not have external
                     * hashes and the other does then they will not be considered equal even
                     * though they may be.
                     */
                } else if( !hashesExternal && password.equals( ntlm.password )) {
                    return true;
                }
            }
        }
        return false;
    }

jcifs.smb.SmbSession
--------------------

    boolean matches( NtlmPasswordAuthentication auth ) {
        // tlh - return true only if ==
        return this.auth == auth ;
        // return this.auth == auth || this.auth.equals( auth );
    }

    void logoff( boolean inError ) {
synchronized( transport() ) {
        if( sessionSetup == false ) {
            return;
        }

        //tlh - remove all elements when tree disconnected
//        for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
//            SmbTree t = (SmbTree)e.nextElement();
//            t.treeDisconnect( inError );
//        }
        trees.removeAllElements();
        

        if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) {

            /*
             * Logoff And X Request / Response
             */

            SmbComLogoffAndX request = new SmbComLogoffAndX( null );
            request.uid = uid;
            try {
                transport.send( request, null );
            } catch( SmbException se ) {
            }
        }
        sessionSetup = false;
}
    }

jcifs.smb.SmbTransport
----------------------
 synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) {
/////////////////// see section below

        if (SO_TIMEOUT > 0 && sessionExpiration < (now = System.currentTimeMillis())) {
            sessionExpiration = now + SO_TIMEOUT;
            iter = sessions.listIterator();
            while( iter.hasNext() ) {
                ssn = (SmbSession)iter.next();
                if( ssn.expiration < now ) {
                    ssn.logoff( false );
                    // tlh - remove auths when done
                    iter.remove();
                }
            }
        }


More information about the jcifs mailing list