aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/auth.c95
-rw-r--r--fs/nfsd/nfs4recover.c72
-rw-r--r--fs/nfsd/nfsfh.c11
-rw-r--r--fs/nfsd/vfs.c9
4 files changed, 114 insertions, 73 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 294992e9bf69..0184fe9b514c 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,53 +27,70 @@ int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
27 27
28int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) 28int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
29{ 29{
30 struct svc_cred cred = rqstp->rq_cred; 30 struct group_info *rqgi;
31 struct group_info *gi;
32 struct cred *new;
31 int i; 33 int i;
32 int flags = nfsexp_flags(rqstp, exp); 34 int flags = nfsexp_flags(rqstp, exp);
33 int ret; 35 int ret;
34 36
37 /* discard any old override before preparing the new set */
38 revert_creds(get_cred(current->real_cred));
39 new = prepare_creds();
40 if (!new)
41 return -ENOMEM;
42
43 new->fsuid = rqstp->rq_cred.cr_uid;
44 new->fsgid = rqstp->rq_cred.cr_gid;
45
46 rqgi = rqstp->rq_cred.cr_group_info;
47
35 if (flags & NFSEXP_ALLSQUASH) { 48 if (flags & NFSEXP_ALLSQUASH) {
36 cred.cr_uid = exp->ex_anon_uid; 49 new->fsuid = exp->ex_anon_uid;
37 cred.cr_gid = exp->ex_anon_gid; 50 new->fsgid = exp->ex_anon_gid;
38 cred.cr_group_info = groups_alloc(0); 51 gi = groups_alloc(0);
39 } else if (flags & NFSEXP_ROOTSQUASH) { 52 } else if (flags & NFSEXP_ROOTSQUASH) {
40 struct group_info *gi; 53 if (!new->fsuid)
41 if (!cred.cr_uid) 54 new->fsuid = exp->ex_anon_uid;
42 cred.cr_uid = exp->ex_anon_uid; 55 if (!new->fsgid)
43 if (!cred.cr_gid) 56 new->fsgid = exp->ex_anon_gid;
44 cred.cr_gid = exp->ex_anon_gid;
45 gi = groups_alloc(cred.cr_group_info->ngroups);
46 if (gi)
47 for (i = 0; i < cred.cr_group_info->ngroups; i++) {
48 if (!GROUP_AT(cred.cr_group_info, i))
49 GROUP_AT(gi, i) = exp->ex_anon_gid;
50 else
51 GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
52 }
53 cred.cr_group_info = gi;
54 } else
55 get_group_info(cred.cr_group_info);
56
57 if (cred.cr_uid != (uid_t) -1)
58 current->fsuid = cred.cr_uid;
59 else
60 current->fsuid = exp->ex_anon_uid;
61 if (cred.cr_gid != (gid_t) -1)
62 current->fsgid = cred.cr_gid;
63 else
64 current->fsgid = exp->ex_anon_gid;
65 57
66 if (!cred.cr_group_info) 58 gi = groups_alloc(rqgi->ngroups);
67 return -ENOMEM; 59 if (!gi)
68 ret = set_current_groups(cred.cr_group_info); 60 goto oom;
69 put_group_info(cred.cr_group_info); 61
70 if ((cred.cr_uid)) { 62 for (i = 0; i < rqgi->ngroups; i++) {
71 current->cap_effective = 63 if (!GROUP_AT(rqgi, i))
72 cap_drop_nfsd_set(current->cap_effective); 64 GROUP_AT(gi, i) = exp->ex_anon_gid;
65 else
66 GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
67 }
73 } else { 68 } else {
74 current->cap_effective = 69 gi = get_group_info(rqgi);
75 cap_raise_nfsd_set(current->cap_effective,
76 current->cap_permitted);
77 } 70 }
71
72 if (new->fsuid == (uid_t) -1)
73 new->fsuid = exp->ex_anon_uid;
74 if (new->fsgid == (gid_t) -1)
75 new->fsgid = exp->ex_anon_gid;
76
77 ret = set_groups(new, gi);
78 put_group_info(gi);
79 if (!ret)
80 goto error;
81
82 if (new->uid)
83 new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
84 else
85 new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
86 new->cap_permitted);
87 put_cred(override_creds(new));
88 return 0;
89
90oom:
91 ret = -ENOMEM;
92error:
93 abort_creds(new);
78 return ret; 94 return ret;
79} 95}
96
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index b79ec930d9f1..0f9d6efaa62b 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -54,20 +54,26 @@
54static struct path rec_dir; 54static struct path rec_dir;
55static int rec_dir_init = 0; 55static int rec_dir_init = 0;
56 56
57static void 57static int
58nfs4_save_user(uid_t *saveuid, gid_t *savegid) 58nfs4_save_creds(const struct cred **original_creds)
59{ 59{
60 *saveuid = current->fsuid; 60 struct cred *new;
61 *savegid = current->fsgid; 61
62 current->fsuid = 0; 62 new = prepare_creds();
63 current->fsgid = 0; 63 if (!new)
64 return -ENOMEM;
65
66 new->fsuid = 0;
67 new->fsgid = 0;
68 *original_creds = override_creds(new);
69 put_cred(new);
70 return 0;
64} 71}
65 72
66static void 73static void
67nfs4_reset_user(uid_t saveuid, gid_t savegid) 74nfs4_reset_creds(const struct cred *original)
68{ 75{
69 current->fsuid = saveuid; 76 revert_creds(original);
70 current->fsgid = savegid;
71} 77}
72 78
73static void 79static void
@@ -129,10 +135,9 @@ nfsd4_sync_rec_dir(void)
129int 135int
130nfsd4_create_clid_dir(struct nfs4_client *clp) 136nfsd4_create_clid_dir(struct nfs4_client *clp)
131{ 137{
138 const struct cred *original_cred;
132 char *dname = clp->cl_recdir; 139 char *dname = clp->cl_recdir;
133 struct dentry *dentry; 140 struct dentry *dentry;
134 uid_t uid;
135 gid_t gid;
136 int status; 141 int status;
137 142
138 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); 143 dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
@@ -140,7 +145,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
140 if (!rec_dir_init || clp->cl_firststate) 145 if (!rec_dir_init || clp->cl_firststate)
141 return 0; 146 return 0;
142 147
143 nfs4_save_user(&uid, &gid); 148 status = nfs4_save_creds(&original_cred);
149 if (status < 0)
150 return status;
144 151
145 /* lock the parent */ 152 /* lock the parent */
146 mutex_lock(&rec_dir.dentry->d_inode->i_mutex); 153 mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
@@ -168,7 +175,7 @@ out_unlock:
168 clp->cl_firststate = 1; 175 clp->cl_firststate = 1;
169 nfsd4_sync_rec_dir(); 176 nfsd4_sync_rec_dir();
170 } 177 }
171 nfs4_reset_user(uid, gid); 178 nfs4_reset_creds(original_cred);
172 dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); 179 dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
173 return status; 180 return status;
174} 181}
@@ -211,26 +218,29 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
211static int 218static int
212nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) 219nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
213{ 220{
221 const struct cred *original_cred;
214 struct file *filp; 222 struct file *filp;
215 struct dentry_list_arg dla = { 223 struct dentry_list_arg dla = {
216 .parent = dir, 224 .parent = dir,
217 }; 225 };
218 struct list_head *dentries = &dla.dentries; 226 struct list_head *dentries = &dla.dentries;
219 struct dentry_list *child; 227 struct dentry_list *child;
220 uid_t uid;
221 gid_t gid;
222 int status; 228 int status;
223 229
224 if (!rec_dir_init) 230 if (!rec_dir_init)
225 return 0; 231 return 0;
226 232
227 nfs4_save_user(&uid, &gid); 233 status = nfs4_save_creds(&original_cred);
234 if (status < 0)
235 return status;
228 INIT_LIST_HEAD(dentries); 236 INIT_LIST_HEAD(dentries);
229 237
230 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); 238 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
239 current_cred());
231 status = PTR_ERR(filp); 240 status = PTR_ERR(filp);
232 if (IS_ERR(filp)) 241 if (IS_ERR(filp))
233 goto out; 242 goto out;
243 INIT_LIST_HEAD(dentries);
234 status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); 244 status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
235 fput(filp); 245 fput(filp);
236 while (!list_empty(dentries)) { 246 while (!list_empty(dentries)) {
@@ -249,7 +259,7 @@ out:
249 dput(child->dentry); 259 dput(child->dentry);
250 kfree(child); 260 kfree(child);
251 } 261 }
252 nfs4_reset_user(uid, gid); 262 nfs4_reset_creds(original_cred);
253 return status; 263 return status;
254} 264}
255 265
@@ -311,8 +321,7 @@ out:
311void 321void
312nfsd4_remove_clid_dir(struct nfs4_client *clp) 322nfsd4_remove_clid_dir(struct nfs4_client *clp)
313{ 323{
314 uid_t uid; 324 const struct cred *original_cred;
315 gid_t gid;
316 int status; 325 int status;
317 326
318 if (!rec_dir_init || !clp->cl_firststate) 327 if (!rec_dir_init || !clp->cl_firststate)
@@ -322,9 +331,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
322 if (status) 331 if (status)
323 goto out; 332 goto out;
324 clp->cl_firststate = 0; 333 clp->cl_firststate = 0;
325 nfs4_save_user(&uid, &gid); 334
335 status = nfs4_save_creds(&original_cred);
336 if (status < 0)
337 goto out;
338
326 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 339 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
327 nfs4_reset_user(uid, gid); 340 nfs4_reset_creds(original_cred);
328 if (status == 0) 341 if (status == 0)
329 nfsd4_sync_rec_dir(); 342 nfsd4_sync_rec_dir();
330 mnt_drop_write(rec_dir.mnt); 343 mnt_drop_write(rec_dir.mnt);
@@ -401,16 +414,21 @@ nfsd4_recdir_load(void) {
401void 414void
402nfsd4_init_recdir(char *rec_dirname) 415nfsd4_init_recdir(char *rec_dirname)
403{ 416{
404 uid_t uid = 0; 417 const struct cred *original_cred;
405 gid_t gid = 0; 418 int status;
406 int status;
407 419
408 printk("NFSD: Using %s as the NFSv4 state recovery directory\n", 420 printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
409 rec_dirname); 421 rec_dirname);
410 422
411 BUG_ON(rec_dir_init); 423 BUG_ON(rec_dir_init);
412 424
413 nfs4_save_user(&uid, &gid); 425 status = nfs4_save_creds(&original_cred);
426 if (status < 0) {
427 printk("NFSD: Unable to change credentials to find recovery"
428 " directory: error %d\n",
429 status);
430 return;
431 }
414 432
415 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 433 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
416 &rec_dir); 434 &rec_dir);
@@ -420,7 +438,7 @@ nfsd4_init_recdir(char *rec_dirname)
420 438
421 if (!status) 439 if (!status)
422 rec_dir_init = 1; 440 rec_dir_init = 1;
423 nfs4_reset_user(uid, gid); 441 nfs4_reset_creds(original_cred);
424} 442}
425 443
426void 444void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index cd25d91895a1..f0da7d9c3a92 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -186,9 +186,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
186 * access control settings being in effect, we cannot 186 * access control settings being in effect, we cannot
187 * fix that case easily. 187 * fix that case easily.
188 */ 188 */
189 current->cap_effective = 189 struct cred *new = prepare_creds();
190 cap_raise_nfsd_set(current->cap_effective, 190 if (!new)
191 current->cap_permitted); 191 return nfserrno(-ENOMEM);
192 new->cap_effective =
193 cap_raise_nfsd_set(new->cap_effective,
194 new->cap_permitted);
195 put_cred(override_creds(new));
196 put_cred(new);
192 } else { 197 } else {
193 error = nfsd_setuser_and_check_port(rqstp, exp); 198 error = nfsd_setuser_and_check_port(rqstp, exp);
194 if (error) 199 if (error)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 4433c8f00163..d1c5f787b365 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -671,6 +671,7 @@ __be32
671nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, 671nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
672 int access, struct file **filp) 672 int access, struct file **filp)
673{ 673{
674 const struct cred *cred = current_cred();
674 struct dentry *dentry; 675 struct dentry *dentry;
675 struct inode *inode; 676 struct inode *inode;
676 int flags = O_RDONLY|O_LARGEFILE; 677 int flags = O_RDONLY|O_LARGEFILE;
@@ -725,7 +726,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
725 DQUOT_INIT(inode); 726 DQUOT_INIT(inode);
726 } 727 }
727 *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), 728 *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
728 flags); 729 flags, cred);
729 if (IS_ERR(*filp)) 730 if (IS_ERR(*filp))
730 host_err = PTR_ERR(*filp); 731 host_err = PTR_ERR(*filp);
731out_nfserr: 732out_nfserr:
@@ -1169,7 +1170,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp,
1169 * send along the gid on create when it tries to implement 1170 * send along the gid on create when it tries to implement
1170 * setgid directories via NFS: 1171 * setgid directories via NFS:
1171 */ 1172 */
1172 if (current->fsuid != 0) 1173 if (current_fsuid() != 0)
1173 iap->ia_valid &= ~(ATTR_UID|ATTR_GID); 1174 iap->ia_valid &= ~(ATTR_UID|ATTR_GID);
1174 if (iap->ia_valid) 1175 if (iap->ia_valid)
1175 return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); 1176 return nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
@@ -2001,7 +2002,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
2001 IS_APPEND(inode)? " append" : "", 2002 IS_APPEND(inode)? " append" : "",
2002 __mnt_is_readonly(exp->ex_path.mnt)? " ro" : ""); 2003 __mnt_is_readonly(exp->ex_path.mnt)? " ro" : "");
2003 dprintk(" owner %d/%d user %d/%d\n", 2004 dprintk(" owner %d/%d user %d/%d\n",
2004 inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); 2005 inode->i_uid, inode->i_gid, current_fsuid(), current_fsgid());
2005#endif 2006#endif
2006 2007
2007 /* Normally we reject any write/sattr etc access on a read-only file 2008 /* Normally we reject any write/sattr etc access on a read-only file
@@ -2044,7 +2045,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
2044 * with NFSv3. 2045 * with NFSv3.
2045 */ 2046 */
2046 if ((acc & NFSD_MAY_OWNER_OVERRIDE) && 2047 if ((acc & NFSD_MAY_OWNER_OVERRIDE) &&
2047 inode->i_uid == current->fsuid) 2048 inode->i_uid == current_fsuid())
2048 return 0; 2049 return 0;
2049 2050
2050 /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ 2051 /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */