3

I was starting to benchmark how much performance we'd lose by using jCIFS instead of requiring our users to map drives manually themselves, but then I found that I couldn't even pass the first basic test of reading data from a file using jCIFS.

I boiled down my issue to a test problem:

import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import com.google.common.io.ByteStreams;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbFile;

public class TestCifs
{
    public static void main(String[] args) throws Exception
    {
        OutputStream output = ByteStreams.nullOutputStream();

        String domain = ""; // have tried the actual name too
        String user = "<your_user_here>";
        String pass = "<your_pass_here>";

        String relativePath = "path/to/100MiB";

        // Read via UNC path (Windows doing the SMB work.)
        Path uncFile = Paths.get("\\\\192.168.1.66\\Shared", relativePath);
        Files.copy(uncFile, output);

        // Read via jCIFS
        //TODO: Figure out if this is a real URL in which case we'd have to escape stuff.
        SmbFile smbFile = new SmbFile("smb://192.168.1.66/Shared/" + relativePath,
                                      new NtlmPasswordAuthentication(domain, user, pass));
        ByteStreams.copy(smbFile.getInputStream(), output);
    }
}

If I run this, it runs past the direct copy and then the jCIFS copy fails with:

Exception in thread "main" jcifs.smb.SmbAuthException: Logon failure: unknown user name or bad password.
    at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:546)
    at jcifs.smb.SmbTransport.send(SmbTransport.java:663)
    at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:390)
    at jcifs.smb.SmbSession.send(SmbSession.java:218)
    at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
    at jcifs.smb.SmbFile.doConnect(SmbFile.java:911)
    at jcifs.smb.SmbFile.connect(SmbFile.java:954)
    at jcifs.smb.SmbFile.connect0(SmbFile.java:880)
    at jcifs.smb.SmbFile.open0(SmbFile.java:972)
    at jcifs.smb.SmbFile.open(SmbFile.java:1006)
    at jcifs.smb.SmbFileInputStream.<init>(SmbFileInputStream.java:73)
    at jcifs.smb.SmbFileInputStream.<init>(SmbFileInputStream.java:65)
    at jcifs.smb.SmbFile.getInputStream(SmbFile.java:2844)
    at TestCifs.main(TestCifs.java:33)

The username and password I provided in user/pass are the same ones I used when authenticating with the server to mount its directory via Windows. I also tried using the name of the server as the domain to no effect. I'm really at a loss with this one and am about to look at something like Wireshark to figure out what is actually going wrong but maybe I'm doing something obviously wrong and someone here can point that out.

This is probably the relevant bit from jCIFS' own diagnostics for the failed login:

treeConnect: unc=\\192.168.1.66\SHARED,service=?????
sessionSetup: accountName=TESTER,primaryDomain=
NtlmContext[auth=TESTER,ntlmsspFlags=0x20080004,workstation=JCIFS1_183_42,isEstablished=false,state=1,serverChallenge=null,signingKey=null]
Type1Message[suppliedDomain=,suppliedWorkstation=JCIFS1_183_42,flags=0x20080205]
00000: 4E 54 4C 4D 53 53 50 00 01 00 00 00 05 22 08 20  |NTLMSSP......". |
00010: 00 00 00 00 00 00 00 00 0D 00 0D 00 20 00 00 00  |............ ...|
00020: 4A 43 49 46 53 31 5F 31 38 33 5F 34 32           |JCIFS1_183_42   |

SmbComSessionSetupAndX[command=SMB_COM_SESSION_SETUP_ANDX,received=false,errorCode=0,flags=0x0018,flags2=0xC803,signSeq=0,tid=0,pid=21886,uid=0,mid=2,wordCount=12,byteCount=77,andxCommand=0xFF,andxOffset=0,snd_buf_size=16644,maxMpxCount=10,VC_NUMBER=1,sessionKey=0,lmHash.length=0,ntHash.length=0,capabilities=-2147483564,accountName=null,primaryDomain=null,NATIVE_OS=Windows 8,NATIVE_LANMAN=jCIFS]
00000: FF 53 4D 42 73 00 00 00 00 18 03 C8 00 00 00 00  |ÿSMBs......È....|
00010: 00 00 00 00 00 00 00 00 00 00 7E 55 00 00 02 00  |..........~U....|
00020: 0C FF 00 DE DE 04 41 0A 00 01 00 00 00 00 00 2D  |.ÿ.ÞÞ.A........-|
00030: 00 00 00 00 00 54 00 00 80 4D 00 4E 54 4C 4D 53  |.....T...M.NTLMS|
00040: 53 50 00 01 00 00 00 05 22 08 20 00 00 00 00 00  |SP......". .....|
00050: 00 00 00 0D 00 0D 00 20 00 00 00 4A 43 49 46 53  |....... ...JCIFS|
00060: 31 5F 31 38 33 5F 34 32 57 00 69 00 6E 00 64 00  |1_183_42W.i.n.d.|
00070: 6F 00 77 00 73 00 20 00 38 00 00 00 6A 00 43 00  |o.w.s. .8...j.C.|
00080: 49 00 46 00 53 00 00 00                          |I.F.S...        |

New data read: Transport1[0.0.0.0<00>/192.168.1.66:445]
00000: FF 53 4D 42 73 6D 00 00 C0 80 41 C8 00 00 00 00  |ÿSMBsm..À.AÈ....|
00010: 00 00 00 00 00 00 00 00 00 00 7E 55 00 00 02 00  |..........~U....|

SmbComSessionSetupAndXResponse[command=SMB_COM_SESSION_SETUP_ANDX,received=false,errorCode=Logon failure: unknown user name or bad password.,flags=0x0080,flags2=0xC841,signSeq=0,tid=0,pid=21886,uid=0,mid=2,wordCount=0,byteCount=0,andxCommand=0xFF,andxOffset=0,isLoggedInAsGuest=false,nativeOs=,nativeLanMan=,primaryDomain=]
00000: FF 53 4D 42 73 6D 00 00 C0 80 41 C8 00 00 00 00  |ÿSMBsm..À.AÈ....|
00010: 00 00 00 00 00 00 00 00 00 00 7E 55 00 00 02 00  |..........~U....|
00020: 00 00 00                                         |...             |

It seems like it isn't putting the username into the message at all, so maybe I'm looking at a bug, but if it's really doing this, surely it would have been noticed by someone else before...

Workarounds already attempted:

  • Putting authentication info into the URL instead of the auth object.
  • Calling SmbSession.logon before trying to access the SmbFile. In this situation, you just get the error from logon instead.
  • Setting a default authenticator using NtlmAuthenticator.setDefault(). In this situation, you see it call the authenticator to get the auth details but then seemingly throw away the info and make the request with no username.
Hakanai
  • 12,010
  • 10
  • 62
  • 132

1 Answers1

0

I fought with this for over an hour but was finally able to get it working using the full URL string as opposed to the NtlmPasswordAuthentication object. I can't say why this is the case, but potentially it's doing some weird stuff to the username and/or password before passing it into the connection string.

In case anyone needs it, here is the URL format I used, which included the domain:

smb://domain;username:password@server/share/path
fudge
  • 189
  • 1
  • 6
  • 18
  • 1
    Just beware of using that in production because it will increase the chance of accidentally exposing the password. I had even tried that at the time of asking the question though and it hadn't helped, so I'm guessing a bunch of time has passed and jCIFS fixed something. – Hakanai Feb 16 '23 at 02:38
  • Yes that's definitely true. Just in case anyone sees this, I also found some features in this updated fork of jCIFS that helped resolved some issues: https://github.com/AgNO3/jcifs-ng – fudge Feb 16 '23 at 14:41
  • 1
    For new versions you can use : SingletonContext context = SingletonContext.getInstance(); Credentials credentials=new NtlmPasswordAuthenticator(null,USERNAME,PASSWORD); CIFSContext testCtx = context.withCredentials(credentials); SmbFile smbFile = new SmbFile(PATH, testCtx); – Amine ABBAOUI Mar 27 '23 at 13:21