diff options
author | Steve French <sfrench@us.ibm.com> | 2008-12-05 14:14:12 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-12-25 21:29:11 -0500 |
commit | 8be0ed44c2fa4afcf2c6d2fb3102c926e9f989df (patch) | |
tree | d0d003c8c9f12b865f0bf8f2015134d7b7031ee5 /fs/cifs/inode.c | |
parent | 61e748015866e48aff91284e3d300c6e3035a87a (diff) |
[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>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 58 |
1 files changed, 53 insertions, 5 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ff8c68de4a92..b8821b0e73de 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/inode.c | 2 | * fs/cifs/inode.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2007 | 4 | * Copyright (C) International Business Machines Corp., 2002,2008 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * 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 | .lookup = cifs_lookup, | 621 | .lookup = cifs_lookup, |
622 | }; | 622 | }; |
623 | 623 | ||
624 | static char *build_path_to_root(struct cifs_sb_info *cifs_sb) | ||
625 | { | ||
626 | int pplen = cifs_sb->prepathlen; | ||
627 | int dfsplen; | ||
628 | char *full_path = NULL; | ||
629 | |||
630 | /* if no prefix path, simply set path to the root of share to "" */ | ||
631 | if (pplen == 0) { | ||
632 | full_path = kmalloc(1, GFP_KERNEL); | ||
633 | if (full_path) | ||
634 | full_path[0] = 0; | ||
635 | return full_path; | ||
636 | } | ||
637 | |||
638 | if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) | ||
639 | dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); | ||
640 | else | ||
641 | dfsplen = 0; | ||
642 | |||
643 | full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL); | ||
644 | if (full_path == NULL) | ||
645 | return full_path; | ||
646 | |||
647 | if (dfsplen) { | ||
648 | strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); | ||
649 | /* switch slash direction in prepath depending on whether | ||
650 | * windows or posix style path names | ||
651 | */ | ||
652 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | ||
653 | int i; | ||
654 | for (i = 0; i < dfsplen; i++) { | ||
655 | if (full_path[i] == '\\') | ||
656 | full_path[i] = '/'; | ||
657 | } | ||
658 | } | ||
659 | } | ||
660 | strncpy(full_path + dfsplen, cifs_sb->prepath, pplen); | ||
661 | full_path[dfsplen + pplen] = 0; /* add trailing null */ | ||
662 | return full_path; | ||
663 | } | ||
664 | |||
624 | /* gets root inode */ | 665 | /* gets root inode */ |
625 | struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | 666 | struct inode *cifs_iget(struct super_block *sb, unsigned long ino) |
626 | { | 667 | { |
@@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
628 | struct cifs_sb_info *cifs_sb; | 669 | struct cifs_sb_info *cifs_sb; |
629 | struct inode *inode; | 670 | struct inode *inode; |
630 | long rc; | 671 | long rc; |
672 | char *full_path; | ||
631 | 673 | ||
632 | inode = iget_locked(sb, ino); | 674 | inode = iget_locked(sb, ino); |
633 | if (!inode) | 675 | if (!inode) |
@@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
636 | return inode; | 678 | return inode; |
637 | 679 | ||
638 | cifs_sb = CIFS_SB(inode->i_sb); | 680 | cifs_sb = CIFS_SB(inode->i_sb); |
639 | xid = GetXid(); | 681 | full_path = build_path_to_root(cifs_sb); |
682 | if (full_path == NULL) | ||
683 | return ERR_PTR(-ENOMEM); | ||
640 | 684 | ||
685 | xid = GetXid(); | ||
641 | if (cifs_sb->tcon->unix_ext) | 686 | if (cifs_sb->tcon->unix_ext) |
642 | rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); | 687 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, |
688 | xid); | ||
643 | else | 689 | else |
644 | rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid, | 690 | rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, |
645 | NULL); | 691 | xid, NULL); |
646 | if (rc && cifs_sb->tcon->ipc) { | 692 | if (rc && cifs_sb->tcon->ipc) { |
647 | cFYI(1, ("ipc connection - fake read inode")); | 693 | cFYI(1, ("ipc connection - fake read inode")); |
648 | inode->i_mode |= S_IFDIR; | 694 | inode->i_mode |= S_IFDIR; |
@@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
652 | inode->i_uid = cifs_sb->mnt_uid; | 698 | inode->i_uid = cifs_sb->mnt_uid; |
653 | inode->i_gid = cifs_sb->mnt_gid; | 699 | inode->i_gid = cifs_sb->mnt_gid; |
654 | } else if (rc) { | 700 | } else if (rc) { |
701 | kfree(full_path); | ||
655 | _FreeXid(xid); | 702 | _FreeXid(xid); |
656 | iget_failed(inode); | 703 | iget_failed(inode); |
657 | return ERR_PTR(rc); | 704 | return ERR_PTR(rc); |
@@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
659 | 706 | ||
660 | unlock_new_inode(inode); | 707 | unlock_new_inode(inode); |
661 | 708 | ||
709 | kfree(full_path); | ||
662 | /* can not call macro FreeXid here since in a void func | 710 | /* can not call macro FreeXid here since in a void func |
663 | * TODO: This is no longer true | 711 | * TODO: This is no longer true |
664 | */ | 712 | */ |