Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Are symbolic links supported? #245

Open
jmagesh opened this issue Aug 21, 2020 · 18 comments · May be fixed by #309
Open

Are symbolic links supported? #245

jmagesh opened this issue Aug 21, 2020 · 18 comments · May be fixed by #309

Comments

@jmagesh
Copy link

jmagesh commented Aug 21, 2020

If a file in a share is a symbolic link to another file on the same file system (e.g. created using the Windows mklink command) will the link be resolved when we try to read the SmbFile?

When we tried to do so, we get this error code:
0x8000002D : STATUS_STOPPED_ON_SYMLINK : The create operation stopped after reaching a symbolic link.

Stack trace:
[2020-06-16 02:30:25,850] DEBUG [-1462162349@qtp--1772318280-0] jcifs.smb.SmbTransportImpl Error code: 0x8000002D for Smb2CreateRequest [2020-06-16 02:30:25,851] DEBUG [-1462162349@qtp--1772318280-0] jcifs.smb.SmbTreeConnection Not retrying jcifs.smb.SmbException: 0x8000002D at jcifs.smb.SmbTransportImpl.checkStatus2(SmbTransportImpl.java:1462) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTransportImpl.checkStatus(SmbTransportImpl.java:1573) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTransportImpl.sendrecv(SmbTransportImpl.java:1028) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTransportImpl.send(SmbTransportImpl.java:1544) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbSessionImpl.send(SmbSessionImpl.java:409) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeImpl.send(SmbTreeImpl.java:472) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeConnection.send0(SmbTreeConnection.java:410) ~[jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeConnection.send(SmbTreeConnection.java:324) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeConnection.send(SmbTreeConnection.java:304) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeHandleImpl.send(SmbTreeHandleImpl.java:130) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbTreeHandleImpl.send(SmbTreeHandleImpl.java:117) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.withOpen(SmbFile.java:1792) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.withOpen(SmbFile.java:1761) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.withOpen(SmbFile.java:1755) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.queryPath(SmbFile.java:807) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.exists(SmbFile.java:890) [jcifs-ng-2.1.4.jar:?] at jcifs.smb.SmbFile.lastModified(SmbFile.java:1152) [jcifs-ng-2.1.4.jar:?]

Is this expected behavior? If so, is there any way to resolve symbolic links? Our understanding is that there is some support for DFS reparse points in jcifs-ng-2.1.4.

@mbechler
Copy link
Contributor

Unfortunately, at this point, there is no support for symlinks. This would definitely be a good addition for the next major version.

@jmagesh
Copy link
Author

jmagesh commented Aug 25, 2020

Thanks for the clarification @mbechler. Hope this is supported in the next major version.

@GregBragg
Copy link

Just bringing this to the top again... Just wondering when can we expect this functionality to be supported?

@mbechler
Copy link
Contributor

mbechler commented Jun 3, 2022

Unfortunately I haven't found much time to work on jcifs recently. And I have to say I somewhat fear that without some redesign this is either going to be inefficient or going to be equally messy and potentially buggy as DFS unfortunately currently is.

@GregBragg
Copy link

GregBragg commented Jun 4, 2022

Ok well I'm attempting to get this functionality in, just can't figure out where the response would be for the STATUS_STOPPED_ON_SYMLINK which according to the MS docs (first link), and I quote includes the symbolic link data, I just don't know where to get it from in the code.

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/ecd51ae2-478c-455b-8669-254b74208d3b

I'm trying to figure out where the symbolic link error response would be returned in the code and where I can grab it based on this document so it can be parsed and processed:

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/a8da655c-8b0b-415a-b726-16dc33fa5827

@mbechler
Copy link
Contributor

mbechler commented Jun 4, 2022

This should be part of the error response and parsed into the errorData field in

protected int readErrorResponse ( byte[] buffer, int bufferIndex ) throws SMBProtocolDecodingException {

still wrapped in the Error Context structure:

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/9ff8837c-c4f7-452b-9272-8818a119dae9

@GregBragg
Copy link

Ok thanks for the tip, I'll be looking into this soon. I looked at this class but must have missed it...

@GregBragg
Copy link

@mbechler can you give me some help on your SMBUtil.readInt2, SMBUtil.readInt4, SMBUtil.readInt8 methods for reading a byte array? I'm getting some unintended results when using these methods...

I'm trying to figure out how to read the symlink error response message based on this document:
https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/f15ae37d-a787-4bf2-9940-025a8c9c0022

Thanks!

@mbechler
Copy link
Contributor

mbechler commented Jun 7, 2022

These should read unsigned short, signed int, signed long (all little endian) from the specified absolute buffer position, so you'll need to keep track of position for yourself. See e.g.

public int decode ( byte[] buffer, int bufferIndex, int len ) throws SMBProtocolDecodingException {

for an example.

Potentially you might be running into a alignment/padding issue:
"Each SMB2 ERROR Context MUST start at an 8-byte aligned boundary relative to the start of the SMB2 ERROR Response."
However, the start of errorData should be 8 byte aligned as far as I can tell.

@GregBragg
Copy link

Ok awesome... that is what I assumed by looking at this code, however I wasn't getting the correct values from the errorData array.

Looking at the code for readErrorResponse in ServerMessageBlock2 it would appear I am missing the first 8 bytes of the message for the errorData value returned in the getErrorData method, which means I am reading from the wrong part of the array as I am missing the first 8 bytes.

I'll try another fix... I might need to update readErrorResponse or create another implementation of the same logic to capture all the bytes in the error response. Thanks!

@mbechler
Copy link
Contributor

mbechler commented Jun 7, 2022

Hm, at least on a quick glance the offset for errorData looks correct to me and therefore should point to the ErrorDataLength field of the first context structure.

@GregBragg
Copy link

Hm, at least on a quick glance the offset for errorData looks correct to me and therefore should point to the ErrorDataLength field of the first context structure.

Yeah it's correct from what I can tell from the specs... I think it has to do with the 8-byte aligned boundary, however I'm still investigating.

@GregBragg
Copy link

GregBragg commented Jun 8, 2022

Ok got it figured out... now I just need to figure out how to call the framework with the "real' path to the file or directory after getting it from the symlink error response PathBuffer variable.

@mbechler Any tips on reading/resolving the 'real' file or directory rather than the symlink?

@mbechler
Copy link
Contributor

mbechler commented Jun 9, 2022

You could probably do something like throw an exception with the link information (along the lines of DfsReferreal) and adjust the path somewhere within the retry logic in SmbTreeConnection.send().

But as I mentioned originally, this is were I believe things will likely to get quite messy. Are you thinking about caching the link information?

@GregBragg
Copy link

GregBragg commented Jun 10, 2022

Ok I’ll take a look at that example, thanks!

I have a new class written that will cache all the information needed after decoding the symlink error, just need to figure out how to do the redirect after the exception is caught.

I’ll eventually submit a PR for review once I get it figured out, however you can see my current progress in my fork.

@GregBragg
Copy link

@mbechler Just a status update on my progress... looks like I have a viable solution now, however I need to enhance my JUnit tests to cover all the bases.

Just need to understand how you configure your tests with parameterized values to a real SMB server, right now I have hardcoded values in my class.

@mbechler
Copy link
Contributor

There is a framework to run multiple congfiguration against multiple server versions and/or configuration.

With the system properties test.config.dir/test.config.file you can provide property files describing test targets.

One of my test target configuration for example:

test.mutations.exclude=noNTStatus,noSigning,forceSigning,legacyAuth,noUnicode,forceUnicode,noNTStatus,noNTSmbs,noUnicode-cp850,noUnicode-windows-1252,noLargeReadWrite,smb1

test.server=w2k19-single-dc.w2k19single.springfield
test.user.name=test1
test.user.domain=W2K19SINGLE.SPRINGFIELD
test.user.sdomain=W2K19SINGLE
test.user.password=***********
test.user.sid=S-1-5-21-3857529893-3941372170-2395057007-1103
test.share.guest=test-guest
test.share=test

test.domain=W2K19SINGLE.SPRINGFIELD
test.domain.netbios=W2K19SINGLE
test.domain.dc=w2k19-single-dc.w2k19single.springfield
test.domain.sid=S-1-5-21-3857529893-3941372170-2395057007

Not all of that is probably relevant for you (e.g. SIDs, test.mutations.exclude in this case disables all SMB1 testing as the server does not support it), but that should get you started.

Then you can create a Test class extending BaseCIFSTest and add that to the AllTests suite, or just add it to a suitable existing class, and access the properties through the base class (getRequiredProperty). There are some utilities, e.g. to get the configured default test share root, see BaseCIFSTest.

As your tests likely require manual setup, you'll probably need to add some additional properties, e.g. a location involving a symlink and potentially the expected target. This also allows skipping the test if the setup has not been performed or the target does not support symlinks.

@GregBragg GregBragg linked a pull request Jun 20, 2022 that will close this issue
@GregBragg
Copy link

GregBragg commented Jun 20, 2022

@mbechler PR #309 has been opened, please review at your convenience.

I ran AllTests against my file share server and all the file operations passed, only 12 tests failed in the whole suite due to permission errors or probably because I did not implement all the property settings that you mentioned, however I believe I have covered all the major tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants