[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