Commit a2809d0e authored by Eugene Korenevsky's avatar Eugene Korenevsky Committed by Steve French

cifs: quirk for STATUS_OBJECT_NAME_INVALID returned for non-ASCII dfs refs

Windows SMB server responds with STATUS_OBJECT_NAME_INVALID code to
SMB2 QUERY_INFO request for "\<server>\<dfsname>\<linkpath>" DFS reference,
where <dfsname> contains non-ASCII unicode symbols.

Check such DFS reference and emulate -EREMOTE if it is actual.

BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=215440Signed-off-by: default avatarEugene Korenevsky <ekorenevsky@astralinux.ru>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 7eacba3b
...@@ -647,6 +647,11 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, ...@@ -647,6 +647,11 @@ static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
int match_target_ip(struct TCP_Server_Info *server, int match_target_ip(struct TCP_Server_Info *server,
const char *share, size_t share_len, const char *share, size_t share_len,
bool *result); bool *result);
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *dfs_link_path);
#endif #endif
static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options) static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
......
...@@ -3374,6 +3374,11 @@ static int is_path_remote(struct mount_ctx *mnt_ctx) ...@@ -3374,6 +3374,11 @@ static int is_path_remote(struct mount_ctx *mnt_ctx)
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
full_path); full_path);
#ifdef CONFIG_CIFS_DFS_UPCALL
if (rc == -ENOENT && is_tcon_dfs(tcon))
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon, cifs_sb,
full_path);
#endif
if (rc != 0 && rc != -EREMOTE) { if (rc != 0 && rc != -EREMOTE) {
kfree(full_path); kfree(full_path);
return rc; return rc;
......
...@@ -952,6 +952,12 @@ cifs_get_inode_info(struct inode **inode, ...@@ -952,6 +952,12 @@ cifs_get_inode_info(struct inode **inode,
rc = server->ops->query_path_info(xid, tcon, cifs_sb, rc = server->ops->query_path_info(xid, tcon, cifs_sb,
full_path, tmp_data, full_path, tmp_data,
&adjust_tz, &is_reparse_point); &adjust_tz, &is_reparse_point);
#ifdef CONFIG_CIFS_DFS_UPCALL
if (rc == -ENOENT && is_tcon_dfs(tcon))
rc = cifs_dfs_query_info_nonascii_quirk(xid, tcon,
cifs_sb,
full_path);
#endif
data = tmp_data; data = tmp_data;
} }
......
...@@ -1302,4 +1302,53 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix) ...@@ -1302,4 +1302,53 @@ int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
return 0; return 0;
} }
/** cifs_dfs_query_info_nonascii_quirk
* Handle weird Windows SMB server behaviour. It responds with
* STATUS_OBJECT_NAME_INVALID code to SMB2 QUERY_INFO request
* for "\<server>\<dfsname>\<linkpath>" DFS reference,
* where <dfsname> contains non-ASCII unicode symbols.
*
* Check such DFS reference and emulate -ENOENT if it is actual.
*/
int cifs_dfs_query_info_nonascii_quirk(const unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *linkpath)
{
char *treename, *dfspath, sep;
int treenamelen, linkpathlen, rc;
treename = tcon->treeName;
/* MS-DFSC: All paths in REQ_GET_DFS_REFERRAL and RESP_GET_DFS_REFERRAL
* messages MUST be encoded with exactly one leading backslash, not two
* leading backslashes.
*/
sep = CIFS_DIR_SEP(cifs_sb);
if (treename[0] == sep && treename[1] == sep)
treename++;
linkpathlen = strlen(linkpath);
treenamelen = strnlen(treename, MAX_TREE_SIZE + 1);
dfspath = kzalloc(treenamelen + linkpathlen + 1, GFP_KERNEL);
if (!dfspath)
return -ENOMEM;
if (treenamelen)
memcpy(dfspath, treename, treenamelen);
memcpy(dfspath + treenamelen, linkpath, linkpathlen);
rc = dfs_cache_find(xid, tcon->ses, cifs_sb->local_nls,
cifs_remap(cifs_sb), dfspath, NULL, NULL);
if (rc == 0) {
cifs_dbg(FYI, "DFS ref '%s' is found, emulate -EREMOTE\n",
dfspath);
rc = -EREMOTE;
} else if (rc == -EEXIST) {
cifs_dbg(FYI, "DFS ref '%s' is not found, emulate -ENOENT\n",
dfspath);
rc = -ENOENT;
} else {
cifs_dbg(FYI, "%s: dfs_cache_find returned %d\n", __func__, rc);
}
kfree(dfspath);
return rc;
}
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment