[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: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Steve French 2008-12-05 19:14:12 +00:00
parent 61e7480158
commit 8be0ed44c2
2 changed files with 56 additions and 6 deletions

View file

@ -2,7 +2,9 @@ Version 1.56
------------
Add "forcemandatorylock" mount option to allow user to use mandatory
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
------------

View file

@ -1,7 +1,7 @@
/*
* 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)
*
* 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 = {
.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 */
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 inode *inode;
long rc;
char *full_path;
inode = iget_locked(sb, ino);
if (!inode)
@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
return inode;
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)
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
rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
NULL);
rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
xid, NULL);
if (rc && cifs_sb->tcon->ipc) {
cFYI(1, ("ipc connection - fake read inode"));
inode->i_mode |= S_IFDIR;
@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
inode->i_uid = cifs_sb->mnt_uid;
inode->i_gid = cifs_sb->mnt_gid;
} else if (rc) {
kfree(full_path);
_FreeXid(xid);
iget_failed(inode);
return ERR_PTR(rc);
@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
unlock_new_inode(inode);
kfree(full_path);
/* can not call macro FreeXid here since in a void func
* TODO: This is no longer true
*/