Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: cifs: fix parsing of hostname in dfs referrals cifs: display fsc in /proc/mounts cifs: enable fscache iff fsc mount option is used explicitly cifs: allow fsc mount option only if CONFIG_CIFS_FSCACHE is set cifs: Handle extended attribute name cifs_acl to generate cifs acl blob (try #4) cifs: Misc. cleanup in cifsacl handling [try #4] cifs: trivial comment fix for cifs_invalidate_mapping [CIFS] fs/cifs/Kconfig: CIFS depends on CRYPTO_HMAC cifs: don't take extra tlink reference in initiate_cifs_search cifs: Percolate error up to the caller during get/set acls [try #4] cifs: fix another memleak, in cifs_root_iget cifs: fix potential use-after-free in cifs_oplock_break_put
This commit is contained in:
Коммит
8520eeaa12
|
@ -4,6 +4,7 @@ config CIFS
|
|||
select NLS
|
||||
select CRYPTO
|
||||
select CRYPTO_MD5
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_ARC4
|
||||
help
|
||||
This is the client VFS module for the Common Internet File System
|
||||
|
@ -143,6 +144,13 @@ config CIFS_FSCACHE
|
|||
to be cached locally on disk through the general filesystem cache
|
||||
manager. If unsure, say N.
|
||||
|
||||
config CIFS_ACL
|
||||
bool "Provide CIFS ACL support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && CIFS_XATTR
|
||||
help
|
||||
Allows to fetch CIFS/NTFS ACL from the server. The DACL blob
|
||||
is handed over to the application/caller.
|
||||
|
||||
config CIFS_EXPERIMENTAL
|
||||
bool "CIFS Experimental Features (EXPERIMENTAL)"
|
||||
depends on CIFS && EXPERIMENTAL
|
||||
|
|
|
@ -560,7 +560,7 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
|||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return NULL;
|
||||
return ERR_CAST(tlink);
|
||||
|
||||
xid = GetXid();
|
||||
rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
|
||||
|
@ -568,7 +568,9 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
|||
|
||||
cifs_put_tlink(tlink);
|
||||
|
||||
cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
|
||||
cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
|
@ -583,7 +585,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
|||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return NULL;
|
||||
return ERR_CAST(tlink);
|
||||
|
||||
tcon = tlink_tcon(tlink);
|
||||
xid = GetXid();
|
||||
|
@ -591,23 +593,22 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
|||
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
|
||||
&fid, &oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
if (rc) {
|
||||
cERROR(1, "Unable to open file to get ACL");
|
||||
goto out;
|
||||
if (!rc) {
|
||||
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
|
||||
CIFSSMBClose(xid, tcon, fid);
|
||||
}
|
||||
|
||||
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
|
||||
cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
|
||||
|
||||
CIFSSMBClose(xid, tcon, fid);
|
||||
out:
|
||||
cifs_put_tlink(tlink);
|
||||
FreeXid(xid);
|
||||
|
||||
cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
/* Retrieve an ACL from the server */
|
||||
static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
||||
struct inode *inode, const char *path,
|
||||
u32 *pacllen)
|
||||
{
|
||||
|
@ -695,7 +696,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|||
}
|
||||
|
||||
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
|
||||
void
|
||||
int
|
||||
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
struct inode *inode, const char *path, const __u16 *pfid)
|
||||
{
|
||||
|
@ -711,17 +712,21 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
|||
pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
|
||||
|
||||
/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
|
||||
if (pntsd)
|
||||
if (IS_ERR(pntsd)) {
|
||||
rc = PTR_ERR(pntsd);
|
||||
cERROR(1, "%s: error %d getting sec desc", __func__, rc);
|
||||
} else {
|
||||
rc = parse_sec_desc(pntsd, acllen, fattr);
|
||||
if (rc)
|
||||
cFYI(1, "parse sec desc failed rc = %d", rc);
|
||||
kfree(pntsd);
|
||||
if (rc)
|
||||
cERROR(1, "parse sec desc failed rc = %d", rc);
|
||||
}
|
||||
|
||||
kfree(pntsd);
|
||||
return;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Convert mode bits to an ACL so we can update the ACL on the server */
|
||||
int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
|
||||
int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
|
||||
{
|
||||
int rc = 0;
|
||||
__u32 secdesclen = 0;
|
||||
|
@ -736,7 +741,10 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
|
|||
/* Add three ACEs for owner, group, everyone getting rid of
|
||||
other ACEs as chmod disables ACEs and set the security descriptor */
|
||||
|
||||
if (pntsd) {
|
||||
if (IS_ERR(pntsd)) {
|
||||
rc = PTR_ERR(pntsd);
|
||||
cERROR(1, "%s: error %d getting sec desc", __func__, rc);
|
||||
} else {
|
||||
/* allocate memory for the smb header,
|
||||
set security descriptor request security descriptor
|
||||
parameters, and secuirty descriptor itself */
|
||||
|
|
|
@ -458,6 +458,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
|
|||
seq_printf(s, ",acl");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
|
||||
seq_printf(s, ",mfsymlinks");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE)
|
||||
seq_printf(s, ",fsc");
|
||||
|
||||
seq_printf(s, ",rsize=%d", cifs_sb->rsize);
|
||||
seq_printf(s, ",wsize=%d", cifs_sb->wsize);
|
||||
|
|
|
@ -130,10 +130,12 @@ extern int cifs_get_file_info_unix(struct file *filp);
|
|||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
const unsigned char *search_path,
|
||||
struct super_block *sb, int xid);
|
||||
extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr, struct inode *inode,
|
||||
const char *path, const __u16 *pfid);
|
||||
extern int mode_to_acl(struct inode *inode, const char *path, __u64);
|
||||
extern int mode_to_cifs_acl(struct inode *inode, const char *path, __u64);
|
||||
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
|
||||
const char *, u32 *);
|
||||
|
||||
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
|
||||
const char *);
|
||||
|
|
|
@ -1352,6 +1352,11 @@ cifs_parse_mount_options(char *options, const char *devname,
|
|||
"supported. Instead set "
|
||||
"/proc/fs/cifs/LookupCacheEnabled to 0\n");
|
||||
} else if (strnicmp(data, "fsc", 3) == 0) {
|
||||
#ifndef CONFIG_CIFS_FSCACHE
|
||||
cERROR(1, "FS-Cache support needs CONFIG_CIFS_FSCACHE"
|
||||
"kernel config option set");
|
||||
return 1;
|
||||
#endif
|
||||
vol->fsc = true;
|
||||
} else if (strnicmp(data, "mfsymlinks", 10) == 0) {
|
||||
vol->mfsymlinks = true;
|
||||
|
|
|
@ -66,7 +66,7 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
|||
/* Search for server name delimiter */
|
||||
sep = memchr(hostname, '\\', len);
|
||||
if (sep)
|
||||
len = sep - unc;
|
||||
len = sep - hostname;
|
||||
else
|
||||
cFYI(1, "%s: probably server name is whole unc: %s",
|
||||
__func__, unc);
|
||||
|
|
|
@ -2271,8 +2271,10 @@ void cifs_oplock_break_get(struct cifsFileInfo *cfile)
|
|||
|
||||
void cifs_oplock_break_put(struct cifsFileInfo *cfile)
|
||||
{
|
||||
struct super_block *sb = cfile->dentry->d_sb;
|
||||
|
||||
cifsFileInfo_put(cfile);
|
||||
cifs_sb_deactive(cfile->dentry->d_sb);
|
||||
cifs_sb_deactive(sb);
|
||||
}
|
||||
|
||||
const struct address_space_operations cifs_addr_ops = {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* fs/cifs/fscache.c - CIFS filesystem cache interface
|
||||
*
|
||||
* Copyright (c) 2010 Novell, Inc.
|
||||
* Author(s): Suresh Jayaraman (sjayaraman@suse.de>
|
||||
* Author(s): Suresh Jayaraman <sjayaraman@suse.de>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published
|
||||
|
@ -67,10 +67,12 @@ static void cifs_fscache_enable_inode_cookie(struct inode *inode)
|
|||
if (cifsi->fscache)
|
||||
return;
|
||||
|
||||
cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_FSCACHE) {
|
||||
cifsi->fscache = fscache_acquire_cookie(tcon->fscache,
|
||||
&cifs_fscache_inode_object_def, cifsi);
|
||||
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
|
||||
cFYI(1, "CIFS: got FH cookie (0x%p/0x%p)", tcon->fscache,
|
||||
cifsi->fscache);
|
||||
}
|
||||
}
|
||||
|
||||
void cifs_fscache_release_inode_cookie(struct inode *inode)
|
||||
|
@ -101,10 +103,8 @@ void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp)
|
|||
{
|
||||
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
|
||||
cifs_fscache_disable_inode_cookie(inode);
|
||||
else {
|
||||
else
|
||||
cifs_fscache_enable_inode_cookie(inode);
|
||||
cFYI(1, "CIFS: fscache inode cookie set");
|
||||
}
|
||||
}
|
||||
|
||||
void cifs_fscache_reset_inode_cookie(struct inode *inode)
|
||||
|
|
|
@ -689,8 +689,13 @@ int cifs_get_inode_info(struct inode **pinode,
|
|||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
/* fill in 0777 bits from ACL */
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
cFYI(1, "Getting mode bits from ACL");
|
||||
cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid);
|
||||
rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path,
|
||||
pfid);
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Getting ACL failed with error: %d",
|
||||
__func__, rc);
|
||||
goto cgii_exit;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -881,8 +886,10 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino)
|
|||
rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
|
||||
xid, NULL);
|
||||
|
||||
if (!inode)
|
||||
return ERR_PTR(rc);
|
||||
if (!inode) {
|
||||
inode = ERR_PTR(rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_FSCACHE
|
||||
/* populate tcon->resource_id */
|
||||
|
@ -898,13 +905,11 @@ struct inode *cifs_root_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);
|
||||
inode = ERR_PTR(rc);
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
kfree(full_path);
|
||||
/* can not call macro FreeXid here since in a void func
|
||||
* TODO: This is no longer true
|
||||
|
@ -1670,7 +1675,9 @@ cifs_inode_needs_reval(struct inode *inode)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* check invalid_mapping flag and zap the cache if it's set */
|
||||
/*
|
||||
* Zap the cache. Called when invalid_mapping flag is set.
|
||||
*/
|
||||
static void
|
||||
cifs_invalidate_mapping(struct inode *inode)
|
||||
{
|
||||
|
@ -2115,9 +2122,14 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
|||
if (attrs->ia_valid & ATTR_MODE) {
|
||||
rc = 0;
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||
rc = mode_to_acl(inode, full_path, mode);
|
||||
else
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
rc = mode_to_cifs_acl(inode, full_path, mode);
|
||||
if (rc) {
|
||||
cFYI(1, "%s: Setting ACL failed with error: %d",
|
||||
__func__, rc);
|
||||
goto cifs_setattr_exit;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
if (((mode & S_IWUGO) == 0) &&
|
||||
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
||||
|
|
|
@ -226,26 +226,29 @@ static int initiate_cifs_search(const int xid, struct file *file)
|
|||
char *full_path = NULL;
|
||||
struct cifsFileInfo *cifsFile;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
struct tcon_link *tlink;
|
||||
struct tcon_link *tlink = NULL;
|
||||
struct cifsTconInfo *pTcon;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
pTcon = tlink_tcon(tlink);
|
||||
|
||||
if (file->private_data == NULL)
|
||||
file->private_data =
|
||||
kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
if (file->private_data == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto error_exit;
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
|
||||
cifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
|
||||
if (cifsFile == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto error_exit;
|
||||
}
|
||||
file->private_data = cifsFile;
|
||||
cifsFile->tlink = cifs_get_tlink(tlink);
|
||||
pTcon = tlink_tcon(tlink);
|
||||
} else {
|
||||
cifsFile = file->private_data;
|
||||
pTcon = tlink_tcon(cifsFile->tlink);
|
||||
}
|
||||
|
||||
cifsFile = file->private_data;
|
||||
cifsFile->invalidHandle = true;
|
||||
cifsFile->srch_inf.endOfSearch = false;
|
||||
cifsFile->tlink = cifs_get_tlink(tlink);
|
||||
|
||||
full_path = build_path_from_dentry(file->f_path.dentry);
|
||||
if (full_path == NULL) {
|
||||
|
|
|
@ -30,10 +30,11 @@
|
|||
|
||||
#define MAX_EA_VALUE_SIZE 65535
|
||||
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
|
||||
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
|
||||
#define CIFS_XATTR_USER_PREFIX "user."
|
||||
#define CIFS_XATTR_SYSTEM_PREFIX "system."
|
||||
#define CIFS_XATTR_OS2_PREFIX "os2."
|
||||
#define CIFS_XATTR_SECURITY_PREFIX ".security"
|
||||
#define CIFS_XATTR_SECURITY_PREFIX "security."
|
||||
#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
|
||||
#define XATTR_TRUSTED_PREFIX_LEN 8
|
||||
#define XATTR_SECURITY_PREFIX_LEN 9
|
||||
|
@ -277,29 +278,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
|||
cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
|
||||
__u16 fid;
|
||||
int oplock = 0;
|
||||
struct cifs_ntsd *pacl = NULL;
|
||||
__u32 buflen = 0;
|
||||
if (experimEnabled)
|
||||
rc = CIFSSMBOpen(xid, pTcon, full_path,
|
||||
FILE_OPEN, GENERIC_READ, 0, &fid,
|
||||
&oplock, NULL, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
/* else rc is EOPNOTSUPP from above */
|
||||
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl,
|
||||
&buflen);
|
||||
CIFSSMBClose(xid, pTcon, fid);
|
||||
}
|
||||
}
|
||||
#endif /* EXPERIMENTAL */
|
||||
#else
|
||||
cFYI(1, "query POSIX ACL not supported yet");
|
||||
cFYI(1, "Query POSIX ACL not supported yet");
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
|
||||
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
|
||||
|
@ -311,8 +291,33 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
|
|||
cifs_sb->mnt_cifs_flags &
|
||||
CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
#else
|
||||
cFYI(1, "query POSIX default ACL not supported yet");
|
||||
#endif
|
||||
cFYI(1, "Query POSIX default ACL not supported yet");
|
||||
#endif /* CONFIG_CIFS_POSIX */
|
||||
} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
|
||||
strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
u32 acllen;
|
||||
struct cifs_ntsd *pacl;
|
||||
|
||||
pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
|
||||
full_path, &acllen);
|
||||
if (IS_ERR(pacl)) {
|
||||
rc = PTR_ERR(pacl);
|
||||
cERROR(1, "%s: error %zd getting sec desc",
|
||||
__func__, rc);
|
||||
} else {
|
||||
if (ea_value) {
|
||||
if (acllen > buf_size)
|
||||
acllen = -ERANGE;
|
||||
else
|
||||
memcpy(ea_value, pacl, acllen);
|
||||
}
|
||||
rc = acllen;
|
||||
kfree(pacl);
|
||||
}
|
||||
#else
|
||||
cFYI(1, "Query CIFS ACL not supported yet");
|
||||
#endif /* CONFIG_CIFS_ACL */
|
||||
} else if (strncmp(ea_name,
|
||||
CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
|
||||
cFYI(1, "Trusted xattr namespace not supported yet");
|
||||
|
|
Загрузка…
Ссылка в новой задаче