-
Notifications
You must be signed in to change notification settings - Fork 73
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
STATUS_ACCESS_DENIED when write by dfs path before read #170
Comments
continue #85 For example: import smbclient
import time
smbclient.open_file(r'\\mycompany.com\DFS\share\1.TXT').read() # file 1.TXT need exist
smbclient.open_file(r'\\mycompany.com\DFS\share\2.TXT', 'w').write('123456') # all right, 123456 > 2.TXT
time.sleep(61)
smbclient.open_file(r'\\mycompany.com\DFS\share\2.TXT', 'w').write('777777') # cause STATUS_ACCESS_DENIED exception As we known in #85: Now i allways read first before write, but in several case it cause exception still. Suggested solution: remember that path if DFS if it discovered once, and than when referral was expired only refresh it. |
I've commented on this a bit more under #171 (comment). Ultimately this seems to be a problem with the DFS server not returning the expected error codes as part of the DFS protocol specification. There are workarounds in place, like setting |
Hello Jordan. Nice to hear you! But you are wrong, there is no workarounds. But i think that I found the problem! if domain_referral:
# Use the dc hint as the source for the root referral request
ipc_tree = get_smb_tree(u"\\%s\\IPC$" % domain_referral.dc_hint, **get_kwargs)[0]
referral_response = dfs_request(ipc_tree, "\\%s\\%s" % (path_split[0], path_split[1])) in my case path_split[0], path_split[1] = get_smb_tree( |
Ah my apologies, I assumed this was still the same problem as before. I guess at this point I need to try and understand your environment a bit better because I do not understand how the current code would fail. It is meant to first enumerate the root DFS servers by asking for DFS server with the path To replicate this scenario I have a domain called This is what happens when I run import smbclient
smbclient.ClientConfig(domain_controller="dc01.domain.test")
with smbclient.open_file(r"\\domain.test\DFS\server2022\temp\test.txt", mode="w") as fd:
fd.write("test")
So while your workaround to adjust the DFS Request to do If you have enough permissions you should be able to get a view of the DFS namespace of your environment and see if it matches up with my test environment or whether I'm missing something. Feel free to send through the latest Wireshark capture from a scenario that replicates your problem and one where the workaround fixes it. |
Thanks, I’ll try and set up a domain environment with Server 2012 R2 and see if I can get the same problem. Does it work if you try opening a write fd on either host directly and not through DFS? |
Yes, if i write directly to server share without using DFS everything works fine: import smbclient
smbclient.ClientConfig(domain_controller='node4.mycompany.com',)
smbclient.open_file(r'\\fs-u40\Report$\1.TXT', 'w').write('123456') If I add into smbclient._pool.get_smb_tree after DFS root resolution request to DFS root host for referral to dfs end share: if len(path_split) > 2:
# Use dfs root referral hint as source for the end share request
ipc_tree = get_smb_tree(u"\\%s\\IPC$" % referral.target_hint.target_path, **get_kwargs)[0]
referral_response = dfs_request(ipc_tree, "\\%s\\%s\\%s" % (path_split[0], path_split[1], path_split[2]))
client_config.cache_referral(referral_response)
referral = client_config.lookup_referral(path_split)
if not referral:
raise ObjectPathNotFound() everything works! What do you think about it? I know about dfs not enough. Can shares be connected not to dfs root but to other shares connected to dfs root? |
Some additions. if I require file from destination server (it is dfs root in addition) FS-U40 by using DFS name: it doesn't work at all import smbclient
smbclient.ClientConfig(domain_controller='node4.mycompany.com')
smbclient.open_file(r'\\fs-u40\Report$\1.TXT', 'r').read() # cause exception 'NoneType' object is not iterable
smbclient.open_file(r'\\fs-u40\Report$\1.TXT', 'w').write('123456') # cause STATUS_ACCESS_DENIED
Case with 158: info = client_config.cache_referral(referral)
159: # info = client_config.lookup_referral([p for p in raw_path.split("\\") if p])
160: connection_kwargs = getattr(raw_io, '_%s__kwargs' % type(raw_io).__name__, {})
161:
162: for target in info: if I uncomment row 159 with And then everything as expected:
|
I understand why it might work for your use case but I need to look further into the DFS specs to see what should be done. I'll also have to see what Windows does in cases like this. For that |
I was sure that use 1.9.0, but it seems like I wasn't. Now I reinstall 1.9.0 from source and there isn't error with smbclient.open_file(r'\\mycompany.com\DFS\Report$\1.TXT', 'w').write('123456') # STATUS_ACCESS_DENIED
smbclient.open_file(r'\\fs-u40\DFS\Report$\1.TXT', 'w').write('123456') # STATUS_ACCESS_DENIED
smbclient.open_file(r'\\fs-p24\DFS\Report$\1.TXT', 'w').write('123456') # STATUS_ACCESS_DENIED
smbclient.open_file(r'\\fs-u40\Report$\1.TXT', 'w').write('123456') # pass
smbclient.open_file(r'\\fs-p24\Report$\1.TXT', 'w').write('123457') # pass All work If I execute next code in cmd: copy 1.txt \\fs-p24\DFS\Report$ |
As we see in I offer next solution: _io.py 318: try:
319: # if tree is dfs share, resolve it without waiting STATUS_PATH_NOT_COVERED
320: if self.raw.fd.tree_connect.is_dfs_share:
321: raise PathNotCovered()
322: res = func(requests[idx]) |
I still cannot replicate this problem even after setting up a test environment with Server 2012 R2 only. While potentially we could have a check in there to do a referral request for the full link this isn't what is meant to happen, or even what I see happen on Windows. Using Referral Process for Domain-based Namespaces as the workflow of what's meant to happen
In this case you are trying to access
If
Right now there is no referral cache that will match so will continue onto step 4.
For the first call the client knows about
On the first request there will be no cached referrals so will once again connect to the smbprotocol/src/smbclient/_pool.py Line 289 in 73d0d00
It uses this root DFS server to know what to translate
This is the problem here, the client is connecting to The crux of this problem is figuring out why this is happening as I don't wish to blindly add a fix for something I do not understand. Even when testing this particular scenario I see Windows acting the same way as dfsutil cache domain flush
dfsutil cache referral flush
dfsutil cache provider flush
Set-Content \\smb.test\dfs\test\test.txt text Clearing the domain cache will result in the client doing a DFS referral request for Accessing Now the client knows the DFS root server for It is connected to the tree and will try and access the file directly on the root DFS server but it returns Because of the Through this info it now knows the final path to connect to is The only difference between what I'm at a loss as to what to try, I'll see if I can try and change the code to do the initial request in a similar way to see if it fixes your problem but until then I don't really have anything else to try or recommend. The only other thing you could do is create 2 separate network captures for doing the smbclient way that fails and the Windows way that works (including the |
The changes in #190 change the behaviour to mark an open operation on a DFS share like Windows does. It would be great if you could test it out and see if it helps in your situation in any way. |
It works perfect now! smbclient.open_file(r'\\mycompany.com\DFS\Report$\1.TXT', 'w').write('123456') # pass
smbclient.open_file(r'\\fs-u40\DFS\Report$\1.TXT', 'w').write('123456') # pass
smbclient.open_file(r'\\fs-p24\DFS\Report$\1.TXT', 'w').write('123456') # pass
smbclient.open_file(r'\\fs-u40\Report$\1.TXT', 'w').write('123456') # pass
smbclient.open_file(r'\\fs-p24\Report$\1.TXT', 'w').write('123457') # pass
smbclient.open_file(r'\\node4\DFS\Report$\1.TXT', 'w').write('123456') # pass Thank you a lot! |
Awesome, still no idea why I'm not seeing the problem but I'm at least glad it's now working for you. I'll try and fix up the rename operation stuff in that PR as the current logic isn't liking what I've changed but at least I know what the problem is here. |
Small remark about #190 - I was fail when try to install it through |
You are better off using I've also just pushed one extra change around the rename operations. It would be good to see if the rename work you were originally trying to do works or does not with the changes there. |
I'cant remember what's the problem with rename operations. smbclient.rename(r'\\mycompany.com\DFS\Report$\1.TXT', r'\\mycompany.com\DFS\Report$\2.TXT') It works excelent in 1.9.0 and 1.10.0 both |
raname with Traceback (most recent call last):
File "C:/APPS/ttt.py", line 9, in <module>
smbclient.rename(r'\\mycompany.com\DFS\Report$\1.TXT', r'\\mycompany.com\DFS\Report$\2.TXT')
File "c:\apps\smbprotocol\src\smbclient\_os.py", line 485, in rename
_rename_information(src, dst, replace_if_exists=False, **kwargs)
File "c:\apps\smbprotocol\src\smbclient\_os.py", line 1135, in _rename_information
set_info(transaction, file_rename)
File "c:\apps\smbprotocol\src\smbclient\_io.py", line 258, in __exit__
self.commit()
File "c:\apps\smbprotocol\src\smbclient\_io.py", line 339, in commit
raise failures[0]
smbprotocol.exceptions.SMBOSError: [Error 2] [NtStatus 0xc000003a] No such file or directory: '\\mycompany.com\DFS\Report$\1.TXT' |
#191 modified it yet again after testing things out a bit more. It will continue to use |
Thanks, now it works fine at least in my environement! |
No description provided.
The text was updated successfully, but these errors were encountered: