Exception in thread "main" java.net.MalformedURLException: unknown protocol: smb
at java.net.URL.(URL.java:480)
at java.net.URL.(URL.java:376)
at java.net.URL.(URL.java:330)
at jcifs.smb.SmbFile.(SmbFile.java:355)
...
More specifically, the SMB URL protocol handler (jcifs.smb.Handler) is used by the java.net.URL class to provide the Java "smb://" URL implementation. There are two possible reasons why this handler is not being recognized.
1) The current security policy is preventing jCIFS from setting the java.protocol.handler.pkgs system property which is required to install the SMB URL protocol handler. For example, some servlet containers install a security manager or restrictive policy file. In this case, add the jCIFS jar file to the container's CLASSPATH because servlet containers usually associate a policy file with the class files of web applications. Otherwise, the specific (minimum) grant required by jCIFS to successfully install the SMB URL protocol handler is:
If jCIFS is not permitted to write this system property, the SecurityException throw will be caught and a message will be printed to System.err (prior to jcifs-0.7.0b10 it was not ignored). Alternatively the property can also be set using a VM command line parameter:permission java.util.PropertyPermission "java.protocol.handler.pkgs", "read, write";
This should permit the URL protocol handler to be installed regardless of what security policy is installed.java -Djava.protocol.handler.pkgs=jcifs ...
Note: There appears to be a bug in the Sun One J2EE Application Server servlet container that makes it incompatible with the jCIFS NtlmHttpFilter. This is described in this message and others by Eric.
2) The jCIFS jar file is not in a suitable location. Even if the java.protocol.handler.pkgs property is set successfully, the java.net.URL class must then access the jcifs.smb.Handler class. But if the jCIFS classes are loaded by a different class loader this handler will not be found and again, you will get the "unknown protocol: smb" exception. It is very common for servlet containers to load classes for a web-app class loader other than the System class loader. Like the first scenario, the solution is to add the jCIFS jar file to the container's CLASSPATH and not the WEB-INF/lib directory of the web app.
Incidentally, the URL class will also generate exceptions like the following if jcifs-0.7.0b4 or later is used without Java 1.3 or above. Either upgrade Java or use jcifs-0.6.x which will work with Java 1.1 and has largely the same functionality minus that found in the jcifs.http package.
jcifs-0.7.0b4+ requires Java 1.3 or above. You are running 1.2.2
Exception in thread "main" java.lang.NoSuchMethodError: java.net.URL: method getAuthority()Ljava/lang/String; not found
at jcifs.smb.Handler.parseURL(Handler.java:52)
at java.net.URL.(Compiled Code)
at java.net.URL.(URL.java:364)
at java.net.URL.(URL.java:308)
at jcifs.smb.SmbFile.(SmbFile.java:355)
...
UnknownHostExceptions right from
the start. What am I doing wrong?
[miallen@prodlinux jcifs]$ java List smb://server/share
Exception in thread "main" java.net.UnknownHostException: SERVER<20>
at jcifs.netbios.NbtAddress.doNameQuery(NbtAddress.java, Compiled Code)
at jcifs.netbios.NbtAddress.getByName(NbtAddress.java, Compiled Code)
at jcifs.smb.SmbFile.<init>(SmbFile.java, Compiled Code)
at jcifs.smb.SmbFile.<init>(SmbFile.java, Compiled Code)
at List.main(List.java, Compiled Code)
For jCIFS to access another computer's files and services the
target must be running a CIFS server over a NetBIOS LAN. This is
exactly the case with 90% of MS Windows networks as CIFS over NetBIOS
is MS's native networking setup. In this environment jCIFS should
work flawlessly. However the above UnknownHostException
is occurring because the name of the target computer cannot be resolved.
There could be many reasons why this is happening.
Breakdown of Possible Problems:
The computer name is misspelled or the machine is off. Doah!
Larger computer networks are divided up into "subnets".
In this case a WINS server is required to resolve hostnames
(although fully qualified DNS names will work as well). The
jcifs.netbios.wins property must be set to the IP
address of the WINS server for your network.
See the Setting Client Properties page for information on how to set jCIFS properties. Also see the Setting Name Resolution Properties page for more detail about resolver properties and what they do. You might also ask your network administrator about what NetBIOS name services are available or check the Network Settings of a nearby MS Windows host for this information.
Not all operating systems have CIFS servers running. Generally Windows NT, Windows 95/98/ME/2000/XP, Samba on UNIX, and possibly OS/2 should work fine (although you can run jCIFS from any Java2 platform). The best way to confirm that the target is in fact running a CIFS server is to try to "share" a folder on the target machine and access files on it from another machine (see Diagnostics below). Otherwise you may need to configure it to run a CIFS server ( e.g. Samba on Linux) or get third party software (e.g. Thursby Software's Dave for MacOS).
This is rarely encountered but you may need to set the
jcifs.netbios.scope property. Ask your network
administrator if "NetBIOS Scope" is being used and look at
the Network Settings of nearby machines. It will just be a string
like 'CHEM_BLDNG' or 'scope.com' or
similar. See the Setting Name
Resolution Properties page for more information about scope and
other properties that control hostname resolution.
You have your hostname in the host file mapped to the 127.0.0.1 address. I actually did this once. For some reason my /etc/hosts file looked like:
(I think Red Hat Linux 6.2 at least ship with this configuration.)127.0.0.1 nano localhost.localdomain localhost
With log=ALL on, look at the dynamically generated
name in the address cache lines. If you see the 127.0.0.1 address
being used, this will definitely cause you problems (and not just
with jCIFS).
JCIFS0_1_69<00> JCIFS0_1_69/127.0.0.1
Taking the host name nano out of the localhost
line solved the problem for me but for some reason it only worked
after reinitializing the network (I rebooted actually).
[PS: I have always tested jCIFS in an environment where the Bind DNS package was used including at home. If you're running a stand-alone machine with no named running, removing the hostname from your /etc/hosts file may not be appropriate.]
If you are using the
-Djcifs.properties=<filename.prp> command line
option, make sure you spell it correctly or the properties file
will silently be ignored, including any important name service
properties within it.
Summary:
In general, if jCIFS is producing unwarranted
UnknownHostExceptions, you will need to find out a little
more about your network. Be sure to read the Setting Client
Properties section from the API
Documentation and pay close attention to the
jcifs.netbios.wins property. Connecting to Windows
machines on the local subnet should work even without setting the WINS
property. To connect to a machine on another subnet you can use the
IP address of the host (eg. smb://192.168.1.15/someshare)
or set the jcifs.netbios.wins property. Also, Windows 98
and similar do not have the CIFS server running by default -- you must
"Allow others access to my files" under Control Panel >
Network Settings. Below are some diagnostics that you can try.
Finally, you can always send an e-mail to the mailing list at jcifs@samba.org.
Diagnosis:
First check to see if your local hostname resolves properly. On UNIX you should look at your /etc/hosts file to make sure it's not mapped to 127.0.0.1. Otherwise just try pinging yourself. The below shows a problem. It should really be resolving to the real IP.
[miallen@nano miallen]$ ping nano PING nano (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data. // WRONG 64 bytes from nano (127.0.0.1): icmp_seq=0 ttl=255 time=0.1 ms 64 bytes from nano (127.0.0.1): icmp_seq=1 ttl=255 time=0.1 ms
There are many ways to test the machines on your network for the
necessary NetBIOS name services. If you have a Windows machine
available you can use nbtstat and ipconfig.
On Linux and UNIX you can use ifconfig and
nmblookup (nmblookup is from the Samba package). More
specifically:
At a command prompt run:
C:\> ipconfig
or
C:\> ipconfig /all
to confirm your IP address(e.g. 192.168.1.15) and then do:
C:\> nbtstat -A 192.168.1.15
You should get the netbios hostname of the machine as well as some
other useful information. You can now do this on other hosts as well
provided you know their IP addresses. If this is working, jCIFS should
work flawlessly (if the necessary properties are set correctly).
The Samba suite has a similar tool that you can use on Linux and UNIX. Again, first verify your IP address with:
$ /sbin/ifconfig
and then do:
$ nmblookup -A 192.168.1.15
If any of the above fails you need to look closer at your network
settings or have a discussion with your network administrator. But if
you determine that the NetBIOS service is in fact listening on the
targets of interest you can use the net command on
Windows, smbclient on Linux/UNIX, or jCIFS to test
connecting to services:
C:\> net use * \\servername\share
or
$ smbclient -L //servername
and
$ smbclient //servername/share
Note: If you authenticate with a domain, the -W flag of
smbclient is required. For example:
$ smbclient //servername/share -W chemgrp -U mike
If after trying all of this, you are still having problems, send a
message to the mailing list at jcifs@samba.org that describes
your problem, what type of host your trying to connect to, and
preferably a full trace of the problem by using -Dlog=ALL
like:
$ java -Dlog=ALL List smb://server/share
Note: Search and replace your network password before posting any
jCIFS dialog.
IOExceptions?
java.io.IOException: Network is unreachable
at java.net.PlainDatagramSocketImpl.send(Native Method)
at java.net.DatagramSocket.send(DatagramSocket.java, Compiled Code)
at jcifs.netbios.NameServiceClient.send(NameServiceClient.java, Compiled Code)
at jcifs.netbios.NameServiceClient.getByName(NameServiceClient.java, Compiled Code)
at jcifs.netbios.NbtAddress.doNameQuery(NbtAddress.java, Compiled Code)
at jcifs.netbios.NbtAddress.getByName(NbtAddress.java, Compiled Code)
at jcifs.smb.SmbFile.<init>(SmbFile.java, Compiled Code)
at jcifs.smb.SmbFile.<init>(SmbFile.java, Compiled Code)
at Exists.main(Exists.java, Compiled Code)
To set the broadcast address, use the
jcifs.netbios.baddr property. This can be as easy as
adding baddr=192.168.1.255 or similar to your properties
(perhaps with -D on the commandline). You can
definatively find out what your broadcast address is by running the
ipconfig command on Windows or ifconfig on
Unix (Linux at least). See the Setting JCIFS
Properties page for details.
C:\> ipconfig
or
C:\> ipconfig /all
On Linux:
$ /sbin/ifconfig
To authenticate arbitrary credentials with the jCIFS 0.7 series and later, the jcifs.smb.Session.logon() method can be used like:
UniAddress mydomaincontroller = UniAddress.getByName( "192.168.1.15" );
NtlmPasswordAuthentication mycreds = new NtlmPasswordAuthentication( "ntdom", "user", "pass" );
try {
SmbSession.logon( mydomaincontoller, mycreds );
// SUCCESS
return true;
} catch( SmbAuthException sae ) {
// AUTHENTICATION FAILURE
return false;
} catch( SmbException se ) {
// NETWORK PROBLEMS?
se.printStackTrace();
}
If the jCIFS 0.6.x series is being used something like the following might be adequate:
try {
SmbFile dummy = new SmbFile( "smb://ntdom;user:pass@192.168.1.15/IPC$" );
dummy.exists();
// SUCCESS
return true;
} catch( SmbAuthException sae ) {
// AUTHENTICATION FAILURE
return false;
} catch( SmbException se ) {
// NETWORK PROBLEMS?
se.printStackTrace();
}