Closed mrmaxi closed 2 years ago
Merging #171 (0015f39) into master (ad98d67) will decrease coverage by
3.34%
. The diff coverage is33.33%
.
@@ Coverage Diff @@
## master #171 +/- ##
==========================================
- Coverage 99.09% 95.74% -3.35%
==========================================
Files 23 23
Lines 5063 5077 +14
==========================================
- Hits 5017 4861 -156
- Misses 46 216 +170
Flag | Coverage Δ | |
---|---|---|
macOS | 67.10% <8.33%> (-1.12%) |
:arrow_down: |
py3.10 | 95.74% <33.33%> (-3.33%) |
:arrow_down: |
py3.6 | 95.74% <33.33%> (-3.33%) |
:arrow_down: |
py3.7 | 95.74% <33.33%> (-3.33%) |
:arrow_down: |
py3.8 | 95.73% <33.33%> (-3.34%) |
:arrow_down: |
py3.9 | 95.73% <33.33%> (-3.36%) |
:arrow_down: |
ubuntu | 93.13% <20.83%> (-3.65%) |
:arrow_down: |
windows | 95.65% <33.33%> (-3.36%) |
:arrow_down: |
x64 | 95.74% <33.33%> (-3.35%) |
:arrow_down: |
x86 | 95.65% <33.33%> (-3.36%) |
:arrow_down: |
Flags with carried forward coverage won't be shown. Click here to find out more.
Impacted Files | Coverage Δ | |
---|---|---|
smbclient/_pool.py | 82.29% <33.33%> (-13.61%) |
:arrow_down: |
smbclient/shutil.py | 41.66% <0.00%> (-53.44%) |
:arrow_down: |
smbclient/path.py | 44.18% <0.00%> (-46.52%) |
:arrow_down: |
smbclient/_os.py | 96.74% <0.00%> (-1.74%) |
:arrow_down: |
smbclient/_io.py | 97.74% <0.00%> (-1.30%) |
:arrow_down: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact)
,ø = not affected
,? = missing data
Powered by Codecov. Last update ad98d67...0015f39. Read the comment docs.
Nice picking up on your original problem, I'll have to play around with it to see if I can replicate it as it's certainly not something I would expect. I think we might need a different approach in the PR as keeping the referrals around resulted in a memory bloat reporting in https://github.com/jborean93/smbprotocol/issues/136. Maybe we should keep the existing cache and the expiry checks but have another simple list that contains paths known to be DFS paths as part of the check. That way it still knows to do the DFS referral request even on an expiry but the referral responses aren't stored indefinitely.
Maybe we should keep the existing cache and the expiry checks but have another simple list that contains paths known to be DFS paths as part of the check. That way it still knows to do the DFS referral request even on an expiry but the referral responses aren't stored indefinitely.
I thought about this, but in this case we need to duplicate lookup_referral code for find if requested path is part of dfs. And I don't found simple solution.
I've taken some time to look at this further and while this might alleviate the problem temporarily for you the issue still remains where the first request is going to error with STATUS_ACCESS_DENIED
causing smbclient to raise the exception. Without the server actually responding with the expected errors to start the DFS process anything on top is going to be a hack really. At a guess your domain controller actually has a share or path that the code is legitimately trying to open, or failing that maybe the DFS share permissions themselves cause it to only work if opening with read access or when being requested to the proper DFS server.
It is due to this problem I see the proper solution is ensuing you've resolved the proper DFS servers for your domain rather than rely on the rudimentary check that smbclient
tries to do for you without knowing what your domain controller is called.
As mentioned in https://github.com/jborean93/smbprotocol/issues/85#issuecomment-810841141 and further down that thread, in these cases you should be setting the following at the start of your script to ensure the domain referrals are looked up properly.
import smbclient
smbclient.ClientConfig(domain_controller='dc.hostname.realm')
You can add username
and/or password
if you can't rely on implicit Kerberos authentication but otherwise what this code does is:
domain_controller
specifiedWhen an actual request is seen to connect to one of these now known domain names it knows that this is for a DFS path and can do the lookup pre-emptively avoiding this problem altogether. The reason why you don't see this problem when running it natively on Windows is that it already knows the domain controller to contact and the domain information. On Linux, and in this pure Python implementation it does not have that luxury so it relies on what the caller has provided or error codes returned back. In this case it gets back a STATUS_ACCESS_DENIED
so assumed the path is legitimate but you don't have access to it. Why it returns STATUS_ACCESS_DENIED
rather than one of the expected error codes to start the lookup I don't have the slightest idea why and I cannot seem to replicate it myself. If this was working then this wouldn't be an issue because the DFS fallback code would run and check the cache or resend the DFS request as needed.
I apologise for getting back to you so late on the PR but unfortunately this is a workaround that keeps around expired caches causing a leak over time for something that can be solved by setting smbclient.ClientConfig(domain_controller='...')
and letting smbclient know for sure what is a DFS request or not initially.
fix #170 - STATUS_ACCESS_DENIED when write by dfs path before read
Remember that path if DFS if it discovered once, and than when referral was expired only refresh it. Use persistent _referral_cache as dict, so when referral is expired just refresh it (instead of removing).