mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
SMB3: Add support for getting and setting SACLs
Add SYSTEM_SECURITY access flag and use with smb2 when opening files for getting/setting SACLs. Add "system.cifs_ntsd_full" extended attribute to allow user-space access to the functionality. Avoid multiple server calls when setting owner, DACL, and SACL. Signed-off-by: Boris Protopopov <pboris@amazon.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
0bf1bafb17
commit
3970acf7dd
@ -1195,7 +1195,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
|
||||
}
|
||||
|
||||
struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
||||
const struct cifs_fid *cifsfid, u32 *pacllen)
|
||||
const struct cifs_fid *cifsfid, u32 *pacllen,
|
||||
u32 __maybe_unused unused)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
unsigned int xid;
|
||||
@ -1263,7 +1264,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
/* Retrieve an ACL from the server */
|
||||
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
||||
struct inode *inode, const char *path,
|
||||
u32 *pacllen)
|
||||
u32 *pacllen, u32 info)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
@ -1273,7 +1274,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
|
||||
if (!open_file)
|
||||
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
|
||||
|
||||
pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
|
||||
pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
|
||||
cifsFileInfo_put(open_file);
|
||||
return pntsd;
|
||||
}
|
||||
@ -1338,6 +1339,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
int rc = 0;
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct smb_version_operations *ops;
|
||||
const u32 info = 0;
|
||||
|
||||
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
|
||||
|
||||
@ -1347,9 +1349,9 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
|
||||
ops = tlink_tcon(tlink)->ses->server->ops;
|
||||
|
||||
if (pfid && (ops->get_acl_by_fid))
|
||||
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
|
||||
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info);
|
||||
else if (ops->get_acl)
|
||||
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
|
||||
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info);
|
||||
else {
|
||||
cifs_put_tlink(tlink);
|
||||
return -EOPNOTSUPP;
|
||||
@ -1388,6 +1390,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct smb_version_operations *ops;
|
||||
bool mode_from_sid, id_from_sid;
|
||||
const u32 info = 0;
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
@ -1403,7 +1406,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
|
||||
pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info);
|
||||
if (IS_ERR(pntsd)) {
|
||||
rc = PTR_ERR(pntsd);
|
||||
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
|
||||
|
@ -456,9 +456,9 @@ struct smb_version_operations {
|
||||
const char *, const void *, const __u16,
|
||||
const struct nls_table *, struct cifs_sb_info *);
|
||||
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
|
||||
const char *, u32 *);
|
||||
const char *, u32 *, u32);
|
||||
struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
|
||||
const struct cifs_fid *, u32 *);
|
||||
const struct cifs_fid *, u32 *, u32);
|
||||
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
|
||||
int);
|
||||
/* writepages retry size */
|
||||
|
@ -240,6 +240,8 @@
|
||||
#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */
|
||||
/* synchronize with the completion */
|
||||
/* of an input/output request */
|
||||
#define SYSTEM_SECURITY 0x01000000 /* The system access control list */
|
||||
/* can be read and changed */
|
||||
#define GENERIC_ALL 0x10000000
|
||||
#define GENERIC_EXECUTE 0x20000000
|
||||
#define GENERIC_WRITE 0x40000000
|
||||
|
@ -218,9 +218,9 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
kuid_t uid, kgid_t gid);
|
||||
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
|
||||
const char *, u32 *);
|
||||
const char *, u32 *, u32);
|
||||
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
|
||||
const struct cifs_fid *, u32 *);
|
||||
const struct cifs_fid *, u32 *, u32);
|
||||
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
|
||||
const char *, int);
|
||||
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);
|
||||
|
@ -3214,7 +3214,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
||||
const struct cifs_fid *cifsfid, u32 *pacllen)
|
||||
const struct cifs_fid *cifsfid, u32 *pacllen, u32 info)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
unsigned int xid;
|
||||
@ -3228,7 +3228,8 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
||||
cifs_dbg(FYI, "trying to get acl\n");
|
||||
|
||||
rc = SMB2_query_acl(xid, tlink_tcon(tlink), cifsfid->persistent_fid,
|
||||
cifsfid->volatile_fid, (void **)&pntsd, pacllen);
|
||||
cifsfid->volatile_fid, (void **)&pntsd, pacllen,
|
||||
info);
|
||||
free_xid(xid);
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
@ -3242,7 +3243,7 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
||||
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
const char *path, u32 *pacllen)
|
||||
const char *path, u32 *pacllen, u32 info)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
@ -3280,12 +3281,16 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
if (info & SACL_SECINFO)
|
||||
oparms.desired_access |= SYSTEM_SECURITY;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
|
||||
NULL);
|
||||
kfree(utf16_path);
|
||||
if (!rc) {
|
||||
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
|
||||
fid.volatile_fid, (void **)&pntsd, pacllen);
|
||||
fid.volatile_fid, (void **)&pntsd, pacllen,
|
||||
info);
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
}
|
||||
|
||||
@ -3319,10 +3324,12 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
tcon = tlink_tcon(tlink);
|
||||
xid = get_xid();
|
||||
|
||||
if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
|
||||
access_flags = WRITE_OWNER;
|
||||
else
|
||||
access_flags = WRITE_DAC;
|
||||
if (aclflag & CIFS_ACL_OWNER || aclflag & CIFS_ACL_GROUP)
|
||||
access_flags |= WRITE_OWNER;
|
||||
if (aclflag & CIFS_ACL_SACL)
|
||||
access_flags |= SYSTEM_SECURITY;
|
||||
if (aclflag & CIFS_ACL_DACL)
|
||||
access_flags |= WRITE_DAC;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path) {
|
||||
@ -3356,8 +3363,8 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
||||
/* Retrieve an ACL from the server */
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl(struct cifs_sb_info *cifs_sb,
|
||||
struct inode *inode, const char *path,
|
||||
u32 *pacllen)
|
||||
struct inode *inode, const char *path,
|
||||
u32 *pacllen, u32 info)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
@ -3365,9 +3372,9 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
|
||||
if (inode)
|
||||
open_file = find_readable_file(CIFS_I(inode), true);
|
||||
if (!open_file)
|
||||
return get_smb2_acl_by_path(cifs_sb, path, pacllen);
|
||||
return get_smb2_acl_by_path(cifs_sb, path, pacllen, info);
|
||||
|
||||
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
|
||||
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
|
||||
cifsFileInfo_put(open_file);
|
||||
return pntsd;
|
||||
}
|
||||
|
@ -3479,10 +3479,9 @@ SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
|
||||
int
|
||||
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
void **data, u32 *plen)
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
void **data, u32 *plen, u32 additional_info)
|
||||
{
|
||||
__u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
|
||||
*plen = 0;
|
||||
|
||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
|
@ -200,8 +200,8 @@ extern int SMB2_query_info_init(struct cifs_tcon *tcon,
|
||||
size_t input_len, void *input);
|
||||
extern void SMB2_query_info_free(struct smb_rqst *rqst);
|
||||
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
void **data, unsigned int *plen);
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
void **data, unsigned int *plen, u32 info);
|
||||
extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
__le64 *uniqueid);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define MAX_EA_VALUE_SIZE CIFSMaxBufSize
|
||||
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */
|
||||
#define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */
|
||||
#define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */
|
||||
#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */
|
||||
#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */
|
||||
/*
|
||||
@ -43,12 +44,13 @@
|
||||
*/
|
||||
#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */
|
||||
#define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */
|
||||
#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */
|
||||
#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */
|
||||
#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */
|
||||
/* BB need to add server (Samba e.g) support for security and trusted prefix */
|
||||
|
||||
enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT,
|
||||
XATTR_CIFS_NTSD };
|
||||
XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };
|
||||
|
||||
static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
|
||||
struct inode *inode, char *full_path,
|
||||
@ -164,7 +166,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
break;
|
||||
|
||||
case XATTR_CIFS_ACL:
|
||||
case XATTR_CIFS_NTSD: {
|
||||
case XATTR_CIFS_NTSD:
|
||||
case XATTR_CIFS_NTSD_FULL: {
|
||||
struct cifs_ntsd *pacl;
|
||||
|
||||
if (!value)
|
||||
@ -174,23 +177,27 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
|
||||
rc = -ENOMEM;
|
||||
} else {
|
||||
memcpy(pacl, value, size);
|
||||
if (value &&
|
||||
pTcon->ses->server->ops->set_acl) {
|
||||
if (pTcon->ses->server->ops->set_acl) {
|
||||
int aclflags = 0;
|
||||
rc = 0;
|
||||
if (handler->flags == XATTR_CIFS_NTSD) {
|
||||
/* set owner and DACL */
|
||||
rc = pTcon->ses->server->ops->set_acl(
|
||||
pacl, size, inode,
|
||||
full_path,
|
||||
CIFS_ACL_OWNER);
|
||||
}
|
||||
if (rc == 0) {
|
||||
/* set DACL */
|
||||
rc = pTcon->ses->server->ops->set_acl(
|
||||
pacl, size, inode,
|
||||
full_path,
|
||||
CIFS_ACL_DACL);
|
||||
|
||||
switch (handler->flags) {
|
||||
case XATTR_CIFS_NTSD_FULL:
|
||||
aclflags = (CIFS_ACL_OWNER |
|
||||
CIFS_ACL_DACL |
|
||||
CIFS_ACL_SACL);
|
||||
break;
|
||||
case XATTR_CIFS_NTSD:
|
||||
aclflags = (CIFS_ACL_OWNER |
|
||||
CIFS_ACL_DACL);
|
||||
break;
|
||||
case XATTR_CIFS_ACL:
|
||||
default:
|
||||
aclflags = CIFS_ACL_DACL;
|
||||
}
|
||||
|
||||
rc = pTcon->ses->server->ops->set_acl(pacl,
|
||||
size, inode, full_path, aclflags);
|
||||
} else {
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
@ -327,16 +334,27 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
|
||||
break;
|
||||
|
||||
case XATTR_CIFS_ACL:
|
||||
case XATTR_CIFS_NTSD: {
|
||||
/* the whole ntsd is fetched regardless */
|
||||
u32 acllen;
|
||||
case XATTR_CIFS_NTSD:
|
||||
case XATTR_CIFS_NTSD_FULL: {
|
||||
/*
|
||||
* fetch owner, DACL, and SACL if asked for full descriptor,
|
||||
* fetch owner and DACL otherwise
|
||||
*/
|
||||
u32 acllen, additional_info = 0;
|
||||
struct cifs_ntsd *pacl;
|
||||
|
||||
if (pTcon->ses->server->ops->get_acl == NULL)
|
||||
goto out; /* rc already EOPNOTSUPP */
|
||||
|
||||
if (handler->flags == XATTR_CIFS_NTSD_FULL) {
|
||||
additional_info = OWNER_SECINFO | GROUP_SECINFO |
|
||||
DACL_SECINFO | SACL_SECINFO;
|
||||
} else {
|
||||
additional_info = OWNER_SECINFO | GROUP_SECINFO |
|
||||
DACL_SECINFO;
|
||||
}
|
||||
pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
|
||||
inode, full_path, &acllen);
|
||||
inode, full_path, &acllen, additional_info);
|
||||
if (IS_ERR(pacl)) {
|
||||
rc = PTR_ERR(pacl);
|
||||
cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
|
||||
@ -486,6 +504,27 @@ static const struct xattr_handler smb3_ntsd_xattr_handler = {
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = {
|
||||
.name = CIFS_XATTR_CIFS_NTSD_FULL,
|
||||
.flags = XATTR_CIFS_NTSD_FULL,
|
||||
.get = cifs_xattr_get,
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
/*
|
||||
* Although this is just an alias for the above, need to move away from
|
||||
* confusing users and using the 20 year old term 'cifs' when it is no
|
||||
* longer secure and was replaced by SMB2/SMB3 a long time ago, and
|
||||
* SMB3 and later are highly secure.
|
||||
*/
|
||||
static const struct xattr_handler smb3_ntsd_full_xattr_handler = {
|
||||
.name = SMB3_XATTR_CIFS_NTSD_FULL,
|
||||
.flags = XATTR_CIFS_NTSD_FULL,
|
||||
.get = cifs_xattr_get,
|
||||
.set = cifs_xattr_set,
|
||||
};
|
||||
|
||||
|
||||
static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
|
||||
.name = XATTR_NAME_POSIX_ACL_ACCESS,
|
||||
.flags = XATTR_ACL_ACCESS,
|
||||
@ -507,6 +546,8 @@ const struct xattr_handler *cifs_xattr_handlers[] = {
|
||||
&smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&cifs_cifs_ntsd_xattr_handler,
|
||||
&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&cifs_cifs_ntsd_full_xattr_handler,
|
||||
&smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */
|
||||
&cifs_posix_acl_access_xattr_handler,
|
||||
&cifs_posix_acl_default_xattr_handler,
|
||||
NULL
|
||||
|
Loading…
Reference in New Issue
Block a user