[jcifs] More classloader issues

Glass, Eric eric.glass at capitalone.com
Sat Dec 14 08:27:15 EST 2002

> I don't understand. If Webapp1 tries to access an SmbFile that will
> execute the static initializer in jcifs.Config which will add 
> 'jcifs' to
> the java.protocol.handler.pkgs System property. The jCIFS 
> classes should
> be available to the System class loader (that's our requirement). When
> the SmbFile constructor is called, the URL class (loaded from the
> System class loader) will see 'smb://' and try to find a handler. From
> the code you show below it should find jcifs.smb.Handler in the System
> class loader. Everything ok so far right?

This is correct -- with jCIFS loaded from the system classloader, a servlet
would be able to use SMB URLs properly as described above.  This will solve
the MalformedURLExceptions when attempting to create SMB URLs under both
Tomcat and Resin (under just about any environment, actually).  Tomcat's
issue is different, but somewhat related.

> > 
> > The problem will arise under Tomcat when NtlmFilter is 
> loaded; it will find
> > the implementation under the system classloader, but 
> NtlmFilter will be
> > unable to find javax.servlet.Filter (which is loaded under 
> the common
> > classloader).  This will cause a NoClassDefFoundError, specifically:
> But the container will be trying to load classes in the Webapp class
> loader. So when accessing jcifs.http.NtlmHttpFilter it will fail as it
> will in the Shared and Common class loaders before 
> successfully loading
> from the System class loader. Now when resolving the 
> javax.servlet.Filter
> baseclass and other servlet classes will it try from the Webapp
> classloader again or degenerate to the classloader from which it just
> loaded jcifs.http.NtlmHttpFilter? I don't see the security risk in
> starting from the original context loader again.

It's not as much a matter of security as it is visibility; what happens is:

a) The container tries to load jcifs.http.NtlmHttpFilter via the webapp

b) The webapp classloader fails (since jCIFS is installed in the system
classloader); classloading is delegated to the parent (the "shared"

c) The shared classloader fails, and classloading is delegated to the parent
(the "common" classloader).

d) The common classloader fails, and classloading is delegated to the system

e) The system classloader successfully locates jcifs.http.NtlmHttpFilter,
and begins to define the class.

f) As part of the class definition process, the system classloader attempts
to locate and load the superclass (javax.servlet.Filter).  This process is
independent of the loading of NtlmHttpFilter; the system classloader is
unaware of the existence of the descendant classloaders (common, shared, and
webapp).  Since the system classloader is the defining classloader for
NtlmHttpFilter, that is where the search begins (and, as it turns out, ends
with a failure).

This is kind of a simplification; in reality only the webapp classloader
attempts to load the class before delegating to the parent (the normal JDK
behavior is to delegate to the parent first, and load the class only if the
parent cannot find it; the servlet spec reverses this behavior for the
webapp classloader to allow web applications to override container-wide
classes).  But the end result is the same; webapp fails, and delegates to
shared, which delegates to common, which delegates to system, which
succeeds.  While defining the NtlmHttpFilter class, system attempts to load
javax.servlet.Filter, and fails.

Basically each classloader is only aware of its parent, and has no means of
knowing if any child classloaders exist.

> Also getting jcifs.smb.Handler installed in the System class loader is
> a completely separate issue right? There's really no relation between
> the problems other than their both being "class loading" issues.

That is correct, with the caveat being that putting jcifs.smb.Handler in the
system classloader also puts NtlmHttpFilter in the system classloader (since
they are packaged together), which causes the Tomcat issue.  To resolve it,
Tomcat users have to make sure that the core servlet classes are available
in either the same classloader as jCIFS or an ancestor; this involves
leaving jcifs.http.* under the webapp classloader (as a separate jar) or
moving "servlet.jar" into the system classloader with the jCIFS jar.

> Ok, this is good info but I don't think it will ever be necessary. Our
> requirement is that the jCIFS jar be available to the System
> classloader. This basically equites to putting it in the 
> containers top
> level lib directory and possibly adding it explicitly to the container
> CLASSPATH. Whatever the case, the code will likely have AllPermission
> or similar.

Probably a safe assumption.

> I just need to establish the simplest "correct" installation 
> procedure. So
> far, ensuring the jar is loaded by the System class loader 
> and that it's
> codeBase has the necesary PropertyPermission should work. If 
> anyone wants
> a more finely grained procedure they can be referred to these messages
> in the archive.

Possibly a note for Tomcat users to relocate the servlet.jar, or a note to
see the FAQ.  Other than that, this should suffice.

The information transmitted herewith is sensitive information intended only
for use by the individual or entity to which it is addressed. If the reader
of this message is not the intended recipient, you are hereby notified that
any review, retransmission, dissemination, distribution, copying or other
use of, or taking of any action in reliance upon this information is
strictly prohibited. If you have received this communication in error,
please contact the sender and delete the material from your computer.

More information about the jcifs mailing list