Skip to content

Commit 3d3ea8e

Browse files
shirishpargaonkarsmfrench
authored andcommitted
cifs: Add mount options for backup intent (try torvalds#6)
Add mount options backupuid and backugid. It allows an authenticated user to access files with the intent to back them up including their ACLs, who may not have access permission but has "Backup files and directories user right" on them (by virtue of being part of the built-in group Backup Operators. When mount options backupuid is specified, cifs client restricts the use of backup intents to the user whose effective user id is specified along with the mount option. When mount options backupgid is specified, cifs client restricts the use of backup intents to the users whose effective user id belongs to the group id specified along with the mount option. If an authenticated user is not part of the built-in group Backup Operators at the server, access to such files is denied, even if allowed by the client. Signed-off-by: Shirish Pargaonkar <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 8bc4392 commit 3d3ea8e

File tree

9 files changed

+95
-16
lines changed

9 files changed

+95
-16
lines changed

fs/cifs/cifs_fs_sb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#define CIFS_MOUNT_STRICT_IO 0x40000 /* strict cache mode */
4444
#define CIFS_MOUNT_RWPIDFORWARD 0x80000 /* use pid forwarding for rw */
4545
#define CIFS_MOUNT_POSIXACL 0x100000 /* mirror of MS_POSIXACL in mnt_cifs_flags */
46+
#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
47+
#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
4648

4749
struct cifs_sb_info {
4850
struct rb_root tlink_tree;
@@ -55,6 +57,8 @@ struct cifs_sb_info {
5557
atomic_t active;
5658
uid_t mnt_uid;
5759
gid_t mnt_gid;
60+
uid_t mnt_backupuid;
61+
gid_t mnt_backupgid;
5862
mode_t mnt_file_mode;
5963
mode_t mnt_dir_mode;
6064
unsigned int mnt_cifs_flags;

fs/cifs/cifsacl.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
945945
{
946946
struct cifs_ntsd *pntsd = NULL;
947947
int oplock = 0;
948-
int xid, rc;
948+
int xid, rc, create_options = 0;
949949
__u16 fid;
950950
struct cifs_tcon *tcon;
951951
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
@@ -956,9 +956,12 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
956956
tcon = tlink_tcon(tlink);
957957
xid = GetXid();
958958

959-
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
960-
&fid, &oplock, NULL, cifs_sb->local_nls,
961-
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
959+
if (backup_cred(cifs_sb))
960+
create_options |= CREATE_OPEN_BACKUP_INTENT;
961+
962+
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
963+
create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
964+
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
962965
if (!rc) {
963966
rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
964967
CIFSSMBClose(xid, tcon, fid);
@@ -995,7 +998,7 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
995998
struct cifs_ntsd *pnntsd, u32 acllen)
996999
{
9971000
int oplock = 0;
998-
int xid, rc;
1001+
int xid, rc, create_options = 0;
9991002
__u16 fid;
10001003
struct cifs_tcon *tcon;
10011004
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
@@ -1006,7 +1009,10 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
10061009
tcon = tlink_tcon(tlink);
10071010
xid = GetXid();
10081011

1009-
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
1012+
if (backup_cred(cifs_sb))
1013+
create_options |= CREATE_OPEN_BACKUP_INTENT;
1014+
1015+
rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, create_options,
10101016
&fid, &oplock, NULL, cifs_sb->local_nls,
10111017
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
10121018
if (rc) {

fs/cifs/cifsglob.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ struct smb_vol {
167167
uid_t cred_uid;
168168
uid_t linux_uid;
169169
gid_t linux_gid;
170+
uid_t backupuid;
171+
gid_t backupgid;
170172
mode_t file_mode;
171173
mode_t dir_mode;
172174
unsigned secFlg;
@@ -179,6 +181,8 @@ struct smb_vol {
179181
bool noperm:1;
180182
bool no_psx_acl:1; /* set if posix acl support should be disabled */
181183
bool cifs_acl:1;
184+
bool backupuid_specified; /* mount option backupuid is specified */
185+
bool backupgid_specified; /* mount option backupgid is specified */
182186
bool no_xattr:1; /* set if xattr (EA) support should be disabled*/
183187
bool server_ino:1; /* use inode numbers from server ie UniqueId */
184188
bool direct_io:1;
@@ -219,7 +223,8 @@ struct smb_vol {
219223
CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
220224
CIFS_MOUNT_NOPOSIXBRL | CIFS_MOUNT_NOSSYNC | \
221225
CIFS_MOUNT_FSCACHE | CIFS_MOUNT_MF_SYMLINKS | \
222-
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO)
226+
CIFS_MOUNT_MULTIUSER | CIFS_MOUNT_STRICT_IO | \
227+
CIFS_MOUNT_CIFS_BACKUPUID | CIFS_MOUNT_CIFS_BACKUPGID)
223228

224229
#define CIFS_MS_MASK (MS_RDONLY | MS_MANDLOCK | MS_NOEXEC | MS_NOSUID | \
225230
MS_NODEV | MS_SYNCHRONOUS)

fs/cifs/cifsproto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ extern int SendReceiveBlockingLock(const unsigned int xid,
9090
extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
9191
extern bool is_valid_oplock_break(struct smb_hdr *smb,
9292
struct TCP_Server_Info *);
93+
extern bool backup_cred(struct cifs_sb_info *);
9394
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
9495
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
9596
unsigned int bytes_written);

fs/cifs/connect.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
831831
{
832832
char *value, *data, *end;
833833
char *mountdata_copy = NULL, *options;
834+
int err;
834835
unsigned int temp_len, i, j;
835836
char separator[2];
836837
short int override_uid = -1;
@@ -887,6 +888,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
887888
cFYI(1, "Null separator not allowed");
888889
}
889890
}
891+
vol->backupuid_specified = false; /* no backup intent for a user */
892+
vol->backupgid_specified = false; /* no backup intent for a group */
890893

891894
while ((data = strsep(&options, separator)) != NULL) {
892895
if (!*data)
@@ -1446,6 +1449,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
14461449
vol->mfsymlinks = true;
14471450
} else if (strnicmp(data, "multiuser", 8) == 0) {
14481451
vol->multiuser = true;
1452+
} else if (!strnicmp(data, "backupuid", 9) && value && *value) {
1453+
err = kstrtouint(value, 0, &vol->backupuid);
1454+
if (err < 0) {
1455+
cERROR(1, "%s: Invalid backupuid value",
1456+
__func__);
1457+
goto cifs_parse_mount_err;
1458+
}
1459+
vol->backupuid_specified = true;
1460+
} else if (!strnicmp(data, "backupgid", 9) && value && *value) {
1461+
err = kstrtouint(value, 0, &vol->backupgid);
1462+
if (err < 0) {
1463+
cERROR(1, "%s: Invalid backupgid value",
1464+
__func__);
1465+
goto cifs_parse_mount_err;
1466+
}
1467+
vol->backupgid_specified = true;
14491468
} else
14501469
printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
14511470
data);
@@ -2737,6 +2756,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
27372756

27382757
cifs_sb->mnt_uid = pvolume_info->linux_uid;
27392758
cifs_sb->mnt_gid = pvolume_info->linux_gid;
2759+
if (pvolume_info->backupuid_specified)
2760+
cifs_sb->mnt_backupuid = pvolume_info->backupuid;
2761+
if (pvolume_info->backupgid_specified)
2762+
cifs_sb->mnt_backupgid = pvolume_info->backupgid;
27402763
cifs_sb->mnt_file_mode = pvolume_info->file_mode;
27412764
cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
27422765
cFYI(1, "file mode: 0x%x dir mode: 0x%x",
@@ -2767,6 +2790,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
27672790
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_RWPIDFORWARD;
27682791
if (pvolume_info->cifs_acl)
27692792
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2793+
if (pvolume_info->backupuid_specified)
2794+
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPUID;
2795+
if (pvolume_info->backupgid_specified)
2796+
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_BACKUPGID;
27702797
if (pvolume_info->override_uid)
27712798
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
27722799
if (pvolume_info->override_gid)

fs/cifs/dir.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
244244
if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
245245
create_options |= CREATE_OPTION_READONLY;
246246

247+
if (backup_cred(cifs_sb))
248+
create_options |= CREATE_OPEN_BACKUP_INTENT;
249+
247250
if (tcon->ses->capabilities & CAP_NT_SMBS)
248251
rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
249252
desiredAccess, create_options,
@@ -357,6 +360,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
357360
{
358361
int rc = -EPERM;
359362
int xid;
363+
int create_options = CREATE_NOT_DIR | CREATE_OPTION_SPECIAL;
360364
struct cifs_sb_info *cifs_sb;
361365
struct tcon_link *tlink;
362366
struct cifs_tcon *pTcon;
@@ -431,9 +435,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
431435
return rc;
432436
}
433437

434-
/* FIXME: would WRITE_OWNER | WRITE_DAC be better? */
438+
if (backup_cred(cifs_sb))
439+
create_options |= CREATE_OPEN_BACKUP_INTENT;
440+
435441
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_CREATE,
436-
GENERIC_WRITE, CREATE_NOT_DIR | CREATE_OPTION_SPECIAL,
442+
GENERIC_WRITE, create_options,
437443
&fileHandle, &oplock, buf, cifs_sb->local_nls,
438444
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
439445
if (rc)

fs/cifs/file.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
174174
int rc;
175175
int desiredAccess;
176176
int disposition;
177+
int create_options = CREATE_NOT_DIR;
177178
FILE_ALL_INFO *buf;
178179

179180
desiredAccess = cifs_convert_flags(f_flags);
@@ -210,9 +211,12 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
210211
if (!buf)
211212
return -ENOMEM;
212213

214+
if (backup_cred(cifs_sb))
215+
create_options |= CREATE_OPEN_BACKUP_INTENT;
216+
213217
if (tcon->ses->capabilities & CAP_NT_SMBS)
214218
rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
215-
desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
219+
desiredAccess, create_options, pnetfid, poplock, buf,
216220
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
217221
& CIFS_MOUNT_MAP_SPECIAL_CHR);
218222
else
@@ -465,6 +469,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
465469
char *full_path = NULL;
466470
int desiredAccess;
467471
int disposition = FILE_OPEN;
472+
int create_options = CREATE_NOT_DIR;
468473
__u16 netfid;
469474

470475
xid = GetXid();
@@ -524,14 +529,17 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
524529

525530
desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
526531

532+
if (backup_cred(cifs_sb))
533+
create_options |= CREATE_OPEN_BACKUP_INTENT;
534+
527535
/* Can not refresh inode by passing in file_info buf to be returned
528536
by SMBOpen and then calling get_inode_info with returned buf
529537
since file might have write behind data that needs to be flushed
530538
and server version of file size can be stale. If we knew for sure
531539
that inode was not dirty locally we could do this */
532540

533541
rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
534-
CREATE_NOT_DIR, &netfid, &oplock, NULL,
542+
create_options, &netfid, &oplock, NULL,
535543
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
536544
CIFS_MOUNT_MAP_SPECIAL_CHR);
537545
if (rc) {

fs/cifs/link.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,20 @@ CIFSFormatMFSymlink(u8 *buf, unsigned int buf_len, const char *link_str)
183183
static int
184184
CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
185185
const char *fromName, const char *toName,
186-
const struct nls_table *nls_codepage, int remap)
186+
struct cifs_sb_info *cifs_sb)
187187
{
188188
int rc;
189189
int oplock = 0;
190+
int remap;
191+
int create_options = CREATE_NOT_DIR;
190192
__u16 netfid = 0;
191193
u8 *buf;
192194
unsigned int bytes_written = 0;
193195
struct cifs_io_parms io_parms;
196+
struct nls_table *nls_codepage;
197+
198+
nls_codepage = cifs_sb->local_nls;
199+
remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
194200

195201
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
196202
if (!buf)
@@ -202,8 +208,11 @@ CIFSCreateMFSymLink(const int xid, struct cifs_tcon *tcon,
202208
return rc;
203209
}
204210

211+
if (backup_cred(cifs_sb))
212+
create_options |= CREATE_OPEN_BACKUP_INTENT;
213+
205214
rc = CIFSSMBOpen(xid, tcon, fromName, FILE_CREATE, GENERIC_WRITE,
206-
CREATE_NOT_DIR, &netfid, &oplock, NULL,
215+
create_options, &netfid, &oplock, NULL,
207216
nls_codepage, remap);
208217
if (rc != 0) {
209218
kfree(buf);
@@ -559,9 +568,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
559568
/* BB what if DFS and this volume is on different share? BB */
560569
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
561570
rc = CIFSCreateMFSymLink(xid, pTcon, full_path, symname,
562-
cifs_sb->local_nls,
563-
cifs_sb->mnt_cifs_flags &
564-
CIFS_MOUNT_MAP_SPECIAL_CHR);
571+
cifs_sb);
565572
else if (pTcon->unix_ext)
566573
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
567574
cifs_sb->local_nls);

fs/cifs/misc.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,18 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
675675
cinode->clientCanCacheRead = false;
676676
}
677677
}
678+
679+
bool
680+
backup_cred(struct cifs_sb_info *cifs_sb)
681+
{
682+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) {
683+
if (cifs_sb->mnt_backupuid == current_fsuid())
684+
return true;
685+
}
686+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) {
687+
if (in_group_p(cifs_sb->mnt_backupgid))
688+
return true;
689+
}
690+
691+
return false;
692+
}

0 commit comments

Comments
 (0)