If a file is stored directly on a DFS enabled share, renaming fails with NT_STATUS_OBJECT_PATH_NOT_FOUND.
The usecase may sound unusual, but a customer is using NetApp ONTAP 9, which by default advertises DFS capabilities for all shares, and he cannot disable it for policy reasons.
I can also reproduce the issue with smbd and Windows Server 2012 R2 (haven't checked with other versions).
IMHO it is caused by:
- Not setting SMB2_HDR_FLAG_DFS when calling smb2cli_req_send() from smb2cli_set_info_send()
- cli_resolve_path() returning a full dfs path for the destination, which is then passed to cli_rename() to be used in SMB2_FILE_RENAME_INFO
After some patching and testing, I came to this conclusion:
Setting SMB2_HDR_FLAG_DFS solves the issue for smbd, but not for Windows Server and not for NetApp.
It seems that the file name in SMB2_FILE_RENAME_INFO must always be a non-dfs path and the header flag is ignored:
- A windows client uses a non-dfs path, but sets the header flag
- Linux kernel also uses a non-dfs path and doesn't set the header flag
This means, path handling for cli_rename() needs to be changed.
IMHO there are two possibilities:
- Extend cli_resolve_path() to be able to also return a non-dfs path
- Strip server/share from fname_dst in cli_rename(), e.g. with parse_dfs_path() from smbd
Created attachment 15564 [details]
Tree Connect Response
DFS capability is advertised. NetApp doesn't set DFS share flags (which is also not required and out of scope for this report).
Created attachment 15565 [details]
SetInfo Request with SMB2_FILE_RENAME_INFO
DFS flag is not set. Filename in SMB2_FILE_RENAME_INFO is a full dfs path.
Created attachment 15566 [details]
Rename failed with STATUS_OBJECT_PATH_NOT_FOUND
Can you please also upload a trace showing the traffic between a Windows client and a Windows server, so we peek how exactly Windows does it? Thanks.
Created attachment 15567 [details]
pcap of failed rename to NetApp
Created attachment 15568 [details]
pcap of successful rename from windows 10 client to windows server
Created attachment 15569 [details]
git-am prototype fix for master.
Works for me. Haven't checked with smb1 though.
The commit message for smb1/smb2 seems to be interchanged.
By the way: Found a function cli_ntrename() which is not called anywhere. Is it still required or just there for compability with older applications?
Thanks - this is a prototype patch so I'll fix that up and add a test (at least SMB2-only:-) before proposing this for an actual fix.
Thanks for confirming it fixes the issue against NetApp (I tested it locally against Samba but don't have access to a NetApp).
Yes, cli_ntrename() isn't used anywhere - it just maps onto cli_ntrename_internal() which is used by the hardlink code. I'll still add a fix for it into the patchset, it's easy enough to do. Thanks for testing !
I now have another issue: if the destination already exists I get STATUS_OBJECT_PATH_SYNTAX_BAD (in version 4.5.16, haven't checked with master yet)
Created attachment 15570 [details]
updated git-am fix for master.
In 4.5.x cli_smb2_rename() doesn't use the 'replace' paramter - it's missing from the cli_rename() call.
In master it does, you add the '-f' parameter to force overwrite (cli_rename() takes an extra 'replace' parameter, set if you add -f to the command line in smbclient).
Ignore comment #11. My local build- and test-environment was broken.