Commit 8be0ed44 authored by Steve French's avatar Steve French

[CIFS] Can not mount with prefixpath if root directory of share is inaccessible

Windows allows you to deny access to the top of a share, but permit access to
a directory lower in the path.  With the prefixpath feature of cifs
(ie mounting \\server\share\directory\subdirectory\etc.) this should have
worked if the user specified a prefixpath which put the root of the mount
at a directory to which he had access, but we still were doing a lookup
on the root of the share (null path) when we should have been doing it on
the prefixpath subdirectory.

This fixes Samba bug # 5925
Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 61e74801
...@@ -2,7 +2,9 @@ Version 1.56 ...@@ -2,7 +2,9 @@ Version 1.56
------------ ------------
Add "forcemandatorylock" mount option to allow user to use mandatory Add "forcemandatorylock" mount option to allow user to use mandatory
rather than posix (advisory) byte range locks, even though server would rather than posix (advisory) byte range locks, even though server would
support posix byte range locks. support posix byte range locks. Fix query of root inode when prefixpath
specified and user does not have access to query information about the
top of the share.
Version 1.55 Version 1.55
------------ ------------
......
/* /*
* fs/cifs/inode.c * fs/cifs/inode.c
* *
* Copyright (C) International Business Machines Corp., 2002,2007 * Copyright (C) International Business Machines Corp., 2002,2008
* Author(s): Steve French (sfrench@us.ibm.com) * Author(s): Steve French (sfrench@us.ibm.com)
* *
* This library is free software; you can redistribute it and/or modify * This library is free software; you can redistribute it and/or modify
...@@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = { ...@@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = {
.lookup = cifs_lookup, .lookup = cifs_lookup,
}; };
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
{
int pplen = cifs_sb->prepathlen;
int dfsplen;
char *full_path = NULL;
/* if no prefix path, simply set path to the root of share to "" */
if (pplen == 0) {
full_path = kmalloc(1, GFP_KERNEL);
if (full_path)
full_path[0] = 0;
return full_path;
}
if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
else
dfsplen = 0;
full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
if (full_path == NULL)
return full_path;
if (dfsplen) {
strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
/* switch slash direction in prepath depending on whether
* windows or posix style path names
*/
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
int i;
for (i = 0; i < dfsplen; i++) {
if (full_path[i] == '\\')
full_path[i] = '/';
}
}
}
strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
full_path[dfsplen + pplen] = 0; /* add trailing null */
return full_path;
}
/* gets root inode */ /* gets root inode */
struct inode *cifs_iget(struct super_block *sb, unsigned long ino) struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
{ {
...@@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) ...@@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct inode *inode; struct inode *inode;
long rc; long rc;
char *full_path;
inode = iget_locked(sb, ino); inode = iget_locked(sb, ino);
if (!inode) if (!inode)
...@@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) ...@@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
return inode; return inode;
cifs_sb = CIFS_SB(inode->i_sb); cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid(); full_path = build_path_to_root(cifs_sb);
if (full_path == NULL)
return ERR_PTR(-ENOMEM);
xid = GetXid();
if (cifs_sb->tcon->unix_ext) if (cifs_sb->tcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
xid);
else else
rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid, rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
NULL); xid, NULL);
if (rc && cifs_sb->tcon->ipc) { if (rc && cifs_sb->tcon->ipc) {
cFYI(1, ("ipc connection - fake read inode")); cFYI(1, ("ipc connection - fake read inode"));
inode->i_mode |= S_IFDIR; inode->i_mode |= S_IFDIR;
...@@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) ...@@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
inode->i_uid = cifs_sb->mnt_uid; inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid; inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) { } else if (rc) {
kfree(full_path);
_FreeXid(xid); _FreeXid(xid);
iget_failed(inode); iget_failed(inode);
return ERR_PTR(rc); return ERR_PTR(rc);
...@@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) ...@@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
unlock_new_inode(inode); unlock_new_inode(inode);
kfree(full_path);
/* can not call macro FreeXid here since in a void func /* can not call macro FreeXid here since in a void func
* TODO: This is no longer true * TODO: This is no longer true
*/ */
......
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