Skip to content

Commit 3970acf

Browse files
Boris ProtopopovSteve French
authored andcommitted
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 <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 0bf1baf commit 3970acf

File tree

8 files changed

+100
-48
lines changed

8 files changed

+100
-48
lines changed

fs/cifs/cifsacl.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
11951195
}
11961196

11971197
struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1198-
const struct cifs_fid *cifsfid, u32 *pacllen)
1198+
const struct cifs_fid *cifsfid, u32 *pacllen,
1199+
u32 __maybe_unused unused)
11991200
{
12001201
struct cifs_ntsd *pntsd = NULL;
12011202
unsigned int xid;
@@ -1263,7 +1264,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
12631264
/* Retrieve an ACL from the server */
12641265
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
12651266
struct inode *inode, const char *path,
1266-
u32 *pacllen)
1267+
u32 *pacllen, u32 info)
12671268
{
12681269
struct cifs_ntsd *pntsd = NULL;
12691270
struct cifsFileInfo *open_file = NULL;
@@ -1273,7 +1274,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
12731274
if (!open_file)
12741275
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
12751276

1276-
pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
1277+
pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
12771278
cifsFileInfo_put(open_file);
12781279
return pntsd;
12791280
}
@@ -1338,6 +1339,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
13381339
int rc = 0;
13391340
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
13401341
struct smb_version_operations *ops;
1342+
const u32 info = 0;
13411343

13421344
cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
13431345

@@ -1347,9 +1349,9 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
13471349
ops = tlink_tcon(tlink)->ses->server->ops;
13481350

13491351
if (pfid && (ops->get_acl_by_fid))
1350-
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
1352+
pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info);
13511353
else if (ops->get_acl)
1352-
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
1354+
pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info);
13531355
else {
13541356
cifs_put_tlink(tlink);
13551357
return -EOPNOTSUPP;
@@ -1388,6 +1390,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
13881390
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
13891391
struct smb_version_operations *ops;
13901392
bool mode_from_sid, id_from_sid;
1393+
const u32 info = 0;
13911394

13921395
if (IS_ERR(tlink))
13931396
return PTR_ERR(tlink);
@@ -1403,7 +1406,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
14031406
return -EOPNOTSUPP;
14041407
}
14051408

1406-
pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
1409+
pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info);
14071410
if (IS_ERR(pntsd)) {
14081411
rc = PTR_ERR(pntsd);
14091412
cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);

fs/cifs/cifsglob.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,9 +456,9 @@ struct smb_version_operations {
456456
const char *, const void *, const __u16,
457457
const struct nls_table *, struct cifs_sb_info *);
458458
struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
459-
const char *, u32 *);
459+
const char *, u32 *, u32);
460460
struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
461-
const struct cifs_fid *, u32 *);
461+
const struct cifs_fid *, u32 *, u32);
462462
int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
463463
int);
464464
/* writepages retry size */

fs/cifs/cifspdu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@
240240
#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */
241241
/* synchronize with the completion */
242242
/* of an input/output request */
243+
#define SYSTEM_SECURITY 0x01000000 /* The system access control list */
244+
/* can be read and changed */
243245
#define GENERIC_ALL 0x10000000
244246
#define GENERIC_EXECUTE 0x20000000
245247
#define GENERIC_WRITE 0x40000000

fs/cifs/cifsproto.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,9 +218,9 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
218218
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
219219
kuid_t uid, kgid_t gid);
220220
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
221-
const char *, u32 *);
221+
const char *, u32 *, u32);
222222
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
223-
const struct cifs_fid *, u32 *);
223+
const struct cifs_fid *, u32 *, u32);
224224
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
225225
const char *, int);
226226
extern unsigned int setup_authusers_ACE(struct cifs_ace *pace);

fs/cifs/smb2ops.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,7 +3214,7 @@ smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
32143214

32153215
static struct cifs_ntsd *
32163216
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
3217-
const struct cifs_fid *cifsfid, u32 *pacllen)
3217+
const struct cifs_fid *cifsfid, u32 *pacllen, u32 info)
32183218
{
32193219
struct cifs_ntsd *pntsd = NULL;
32203220
unsigned int xid;
@@ -3228,7 +3228,8 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
32283228
cifs_dbg(FYI, "trying to get acl\n");
32293229

32303230
rc = SMB2_query_acl(xid, tlink_tcon(tlink), cifsfid->persistent_fid,
3231-
cifsfid->volatile_fid, (void **)&pntsd, pacllen);
3231+
cifsfid->volatile_fid, (void **)&pntsd, pacllen,
3232+
info);
32323233
free_xid(xid);
32333234

32343235
cifs_put_tlink(tlink);
@@ -3242,7 +3243,7 @@ get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
32423243

32433244
static struct cifs_ntsd *
32443245
get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
3245-
const char *path, u32 *pacllen)
3246+
const char *path, u32 *pacllen, u32 info)
32463247
{
32473248
struct cifs_ntsd *pntsd = NULL;
32483249
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
@@ -3280,12 +3281,16 @@ get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
32803281
oparms.fid = &fid;
32813282
oparms.reconnect = false;
32823283

3284+
if (info & SACL_SECINFO)
3285+
oparms.desired_access |= SYSTEM_SECURITY;
3286+
32833287
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
32843288
NULL);
32853289
kfree(utf16_path);
32863290
if (!rc) {
32873291
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
3288-
fid.volatile_fid, (void **)&pntsd, pacllen);
3292+
fid.volatile_fid, (void **)&pntsd, pacllen,
3293+
info);
32893294
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
32903295
}
32913296

@@ -3319,10 +3324,12 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
33193324
tcon = tlink_tcon(tlink);
33203325
xid = get_xid();
33213326

3322-
if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
3323-
access_flags = WRITE_OWNER;
3324-
else
3325-
access_flags = WRITE_DAC;
3327+
if (aclflag & CIFS_ACL_OWNER || aclflag & CIFS_ACL_GROUP)
3328+
access_flags |= WRITE_OWNER;
3329+
if (aclflag & CIFS_ACL_SACL)
3330+
access_flags |= SYSTEM_SECURITY;
3331+
if (aclflag & CIFS_ACL_DACL)
3332+
access_flags |= WRITE_DAC;
33263333

33273334
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
33283335
if (!utf16_path) {
@@ -3356,18 +3363,18 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
33563363
/* Retrieve an ACL from the server */
33573364
static struct cifs_ntsd *
33583365
get_smb2_acl(struct cifs_sb_info *cifs_sb,
3359-
struct inode *inode, const char *path,
3360-
u32 *pacllen)
3366+
struct inode *inode, const char *path,
3367+
u32 *pacllen, u32 info)
33613368
{
33623369
struct cifs_ntsd *pntsd = NULL;
33633370
struct cifsFileInfo *open_file = NULL;
33643371

33653372
if (inode)
33663373
open_file = find_readable_file(CIFS_I(inode), true);
33673374
if (!open_file)
3368-
return get_smb2_acl_by_path(cifs_sb, path, pacllen);
3375+
return get_smb2_acl_by_path(cifs_sb, path, pacllen, info);
33693376

3370-
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
3377+
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
33713378
cifsFileInfo_put(open_file);
33723379
return pntsd;
33733380
}

fs/cifs/smb2pdu.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,10 +3479,9 @@ SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
34793479

34803480
int
34813481
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
3482-
u64 persistent_fid, u64 volatile_fid,
3483-
void **data, u32 *plen)
3482+
u64 persistent_fid, u64 volatile_fid,
3483+
void **data, u32 *plen, u32 additional_info)
34843484
{
3485-
__u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
34863485
*plen = 0;
34873486

34883487
return query_info(xid, tcon, persistent_fid, volatile_fid,

fs/cifs/smb2proto.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,8 @@ extern int SMB2_query_info_init(struct cifs_tcon *tcon,
200200
size_t input_len, void *input);
201201
extern void SMB2_query_info_free(struct smb_rqst *rqst);
202202
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
203-
u64 persistent_file_id, u64 volatile_file_id,
204-
void **data, unsigned int *plen);
203+
u64 persistent_file_id, u64 volatile_file_id,
204+
void **data, unsigned int *plen, u32 info);
205205
extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
206206
u64 persistent_fid, u64 volatile_fid,
207207
__le64 *uniqueid);

fs/cifs/xattr.c

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#define MAX_EA_VALUE_SIZE CIFSMaxBufSize
3535
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */
3636
#define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */
37+
#define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */
3738
#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */
3839
#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */
3940
/*
@@ -43,12 +44,13 @@
4344
*/
4445
#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */
4546
#define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */
47+
#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */
4648
#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */
4749
#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */
4850
/* BB need to add server (Samba e.g) support for security and trusted prefix */
4951

5052
enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT,
51-
XATTR_CIFS_NTSD };
53+
XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };
5254

5355
static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
5456
struct inode *inode, char *full_path,
@@ -164,7 +166,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
164166
break;
165167

166168
case XATTR_CIFS_ACL:
167-
case XATTR_CIFS_NTSD: {
169+
case XATTR_CIFS_NTSD:
170+
case XATTR_CIFS_NTSD_FULL: {
168171
struct cifs_ntsd *pacl;
169172

170173
if (!value)
@@ -174,23 +177,27 @@ static int cifs_xattr_set(const struct xattr_handler *handler,
174177
rc = -ENOMEM;
175178
} else {
176179
memcpy(pacl, value, size);
177-
if (value &&
178-
pTcon->ses->server->ops->set_acl) {
180+
if (pTcon->ses->server->ops->set_acl) {
181+
int aclflags = 0;
179182
rc = 0;
180-
if (handler->flags == XATTR_CIFS_NTSD) {
181-
/* set owner and DACL */
182-
rc = pTcon->ses->server->ops->set_acl(
183-
pacl, size, inode,
184-
full_path,
185-
CIFS_ACL_OWNER);
186-
}
187-
if (rc == 0) {
188-
/* set DACL */
189-
rc = pTcon->ses->server->ops->set_acl(
190-
pacl, size, inode,
191-
full_path,
192-
CIFS_ACL_DACL);
183+
184+
switch (handler->flags) {
185+
case XATTR_CIFS_NTSD_FULL:
186+
aclflags = (CIFS_ACL_OWNER |
187+
CIFS_ACL_DACL |
188+
CIFS_ACL_SACL);
189+
break;
190+
case XATTR_CIFS_NTSD:
191+
aclflags = (CIFS_ACL_OWNER |
192+
CIFS_ACL_DACL);
193+
break;
194+
case XATTR_CIFS_ACL:
195+
default:
196+
aclflags = CIFS_ACL_DACL;
193197
}
198+
199+
rc = pTcon->ses->server->ops->set_acl(pacl,
200+
size, inode, full_path, aclflags);
194201
} else {
195202
rc = -EOPNOTSUPP;
196203
}
@@ -327,16 +334,27 @@ static int cifs_xattr_get(const struct xattr_handler *handler,
327334
break;
328335

329336
case XATTR_CIFS_ACL:
330-
case XATTR_CIFS_NTSD: {
331-
/* the whole ntsd is fetched regardless */
332-
u32 acllen;
337+
case XATTR_CIFS_NTSD:
338+
case XATTR_CIFS_NTSD_FULL: {
339+
/*
340+
* fetch owner, DACL, and SACL if asked for full descriptor,
341+
* fetch owner and DACL otherwise
342+
*/
343+
u32 acllen, additional_info = 0;
333344
struct cifs_ntsd *pacl;
334345

335346
if (pTcon->ses->server->ops->get_acl == NULL)
336347
goto out; /* rc already EOPNOTSUPP */
337348

349+
if (handler->flags == XATTR_CIFS_NTSD_FULL) {
350+
additional_info = OWNER_SECINFO | GROUP_SECINFO |
351+
DACL_SECINFO | SACL_SECINFO;
352+
} else {
353+
additional_info = OWNER_SECINFO | GROUP_SECINFO |
354+
DACL_SECINFO;
355+
}
338356
pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
339-
inode, full_path, &acllen);
357+
inode, full_path, &acllen, additional_info);
340358
if (IS_ERR(pacl)) {
341359
rc = PTR_ERR(pacl);
342360
cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
@@ -486,6 +504,27 @@ static const struct xattr_handler smb3_ntsd_xattr_handler = {
486504
.set = cifs_xattr_set,
487505
};
488506

507+
static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = {
508+
.name = CIFS_XATTR_CIFS_NTSD_FULL,
509+
.flags = XATTR_CIFS_NTSD_FULL,
510+
.get = cifs_xattr_get,
511+
.set = cifs_xattr_set,
512+
};
513+
514+
/*
515+
* Although this is just an alias for the above, need to move away from
516+
* confusing users and using the 20 year old term 'cifs' when it is no
517+
* longer secure and was replaced by SMB2/SMB3 a long time ago, and
518+
* SMB3 and later are highly secure.
519+
*/
520+
static const struct xattr_handler smb3_ntsd_full_xattr_handler = {
521+
.name = SMB3_XATTR_CIFS_NTSD_FULL,
522+
.flags = XATTR_CIFS_NTSD_FULL,
523+
.get = cifs_xattr_get,
524+
.set = cifs_xattr_set,
525+
};
526+
527+
489528
static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
490529
.name = XATTR_NAME_POSIX_ACL_ACCESS,
491530
.flags = XATTR_ACL_ACCESS,
@@ -507,6 +546,8 @@ const struct xattr_handler *cifs_xattr_handlers[] = {
507546
&smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
508547
&cifs_cifs_ntsd_xattr_handler,
509548
&smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
549+
&cifs_cifs_ntsd_full_xattr_handler,
550+
&smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */
510551
&cifs_posix_acl_access_xattr_handler,
511552
&cifs_posix_acl_default_xattr_handler,
512553
NULL

0 commit comments

Comments
 (0)