[jcifs] preventing soTimeout NT_STATUS_ACCESS_VIOLATION w/ NTLM

Tapperson Kevin Kevin.Tapperson at hcahealthcare.com
Wed Jun 15 15:43:40 GMT 2005


I have had success in preventing jcifs from throwing an SmbAuthException with the NT_STATUS_ACCESS_VIOLATION ("Invalid access to memory location") error code in association with an soTimeout event by implementing a reference counter for NTLM HTTP authentication requests in the SmbTransport class.  The following changes described below were done on the jcifs_1.1.10 code base.  I checked the jcifs_1.2.0 code base to see how different the changes would be for it.  The only major difference is the change in the SmbTransport.run() method.  (In 1.2.0, the changes below to SmbTransport would need to go into the Transport class and the Transport.disconnect() method.)

I also noticed in jcifs_1.2.0 that the Transport.loop() method (portions equivalent to the old SmbTransport.run() method) no longer distinguishes between an InterruptedIOException and an IOException; it instead uses the exception message to determine if the error is a "hard" error or an soTimeout event.  I would strongly caution against doing this.  In my experience, exception messages are often different on various platforms and may differ by JVM vendor as well (Sun vs. IBM).  In particular, I have seen that socket-related exception messages appear to differ quite significantly.


I added the following code to SmbTransport:
    private int refCount = 0;

    synchronized void incRefCount() {
        refCount++;
    }

    synchronized void decRefCount() {
        refCount--;
    }

And changed the following catch block in SmbTransport.run() as follows:
            } catch( InterruptedIOException iioe ) {
                if( responseTable.size() == 0 ) {
                    if( refCount == 0 ) {                                       //refCount
                        tryClose( false );
                    } else if( log.level > 1 ) {                                //refCount
                        log.println( "soTimeout has occured but there are " +   //refCount
                                refCount + " references to this transport socket" ); //refCount
                    }                                                           //refCount
                } else if( log.level > 1 ) {
                    log.println( "soTimeout has occured but there are " +
                            responseTable.size() + " pending requests" );
                }
            }

I changed the following methods in SmbSession as follows:
    private static NtlmChallenge interrogate( NbtAddress addr ) throws SmbException {
        UniAddress dc = new UniAddress( addr );
        SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
        if (USERNAME == null) {
            trans.negotiate();
            if (SmbTransport.log.level > 2)
                SmbTransport.log.println(
                    "Default credentials (jcifs.smb.client.username/password)" +
                    " not specified. SMB signing may not work propertly." +
                    "  Skipping DC interrogation." );
        } else {
            SmbSession ssn = trans.getSmbSession( NtlmPasswordAuthentication.DEFAULT );
            ssn.getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
        }
        trans.incrementReferenceCount();                                        //refCount
        return new NtlmChallenge( trans.server.encryptionKey, dc );
    }

    public static byte[] getChallenge( UniAddress dc, int port )
                throws SmbException, UnknownHostException {
        SmbTransport trans = SmbTransport.getSmbTransport( dc, port );
        trans.negotiate();
        trans.incrementReferenceCount();                                        //refCount
        return trans.server.encryptionKey;
    }

    public static void logon( UniAddress dc, int port,
                        NtlmPasswordAuthentication auth ) throws SmbException {
        SmbTree tree = SmbTransport.getSmbTransport( dc, port ).getSmbSession( auth ).getSmbTree( LOGON_SHARE, null );
        try {                                                                   //refCount
            if( LOGON_SHARE == null ) {
                tree.treeConnect( null, null );
            } else {
                Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY );
                Trans2FindFirst2Response resp = new Trans2FindFirst2Response();
                tree.sendTransaction( req, resp );
            }
        } finally {                                                             //refCount
            tree.session.transport.decrementReferenceCount();                   //refCount
        }                                                                       //refCount
    }


-------------- next part --------------
HTML attachment scrubbed and removed


More information about the jcifs mailing list