aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/auth.c92
-rw-r--r--fs/nfsd/nfs4recover.c68
-rw-r--r--fs/nfsd/nfsfh.c11
3 files changed, 102 insertions, 69 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 808fc03a6fbd..836ffa1047d9 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -27,55 +27,67 @@ 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 cred *act_as = current->cred ; 30 struct group_info *rqgi;
31 struct svc_cred cred = rqstp->rq_cred; 31 struct group_info *gi;
32 struct cred *new;
32 int i; 33 int i;
33 int flags = nfsexp_flags(rqstp, exp); 34 int flags = nfsexp_flags(rqstp, exp);
34 int ret; 35 int ret;
35 36
37 new = prepare_creds();
38 if (!new)
39 return -ENOMEM;
40
41 new->fsuid = rqstp->rq_cred.cr_uid;
42 new->fsgid = rqstp->rq_cred.cr_gid;
43
44 rqgi = rqstp->rq_cred.cr_group_info;
45
36 if (flags & NFSEXP_ALLSQUASH) { 46 if (flags & NFSEXP_ALLSQUASH) {
37 cred.cr_uid = exp->ex_anon_uid; 47 new->fsuid = exp->ex_anon_uid;
38 cred.cr_gid = exp->ex_anon_gid; 48 new->fsgid = exp->ex_anon_gid;
39 cred.cr_group_info = groups_alloc(0); 49 gi = groups_alloc(0);
40 } else if (flags & NFSEXP_ROOTSQUASH) { 50 } else if (flags & NFSEXP_ROOTSQUASH) {
41 struct group_info *gi; 51 if (!new->fsuid)
42 if (!cred.cr_uid) 52 new->fsuid = exp->ex_anon_uid;
43 cred.cr_uid = exp->ex_anon_uid; 53 if (!new->fsgid)
44 if (!cred.cr_gid) 54 new->fsgid = exp->ex_anon_gid;
45 cred.cr_gid = exp->ex_anon_gid;
46 gi = groups_alloc(cred.cr_group_info->ngroups);
47 if (gi)
48 for (i = 0; i < cred.cr_group_info->ngroups; i++) {
49 if (!GROUP_AT(cred.cr_group_info, i))
50 GROUP_AT(gi, i) = exp->ex_anon_gid;
51 else
52 GROUP_AT(gi, i) = GROUP_AT(cred.cr_group_info, i);
53 }
54 cred.cr_group_info = gi;
55 } else
56 get_group_info(cred.cr_group_info);
57
58 if (cred.cr_uid != (uid_t) -1)
59 act_as->fsuid = cred.cr_uid;
60 else
61 act_as->fsuid = exp->ex_anon_uid;
62 if (cred.cr_gid != (gid_t) -1)
63 act_as->fsgid = cred.cr_gid;
64 else
65 act_as->fsgid = exp->ex_anon_gid;
66 55
67 if (!cred.cr_group_info) 56 gi = groups_alloc(rqgi->ngroups);
68 return -ENOMEM; 57 if (!gi)
69 ret = set_groups(act_as, cred.cr_group_info); 58 goto oom;
70 put_group_info(cred.cr_group_info); 59
71 if ((cred.cr_uid)) { 60 for (i = 0; i < rqgi->ngroups; i++) {
72 act_as->cap_effective = 61 if (!GROUP_AT(rqgi, i))
73 cap_drop_nfsd_set(act_as->cap_effective); 62 GROUP_AT(gi, i) = exp->ex_anon_gid;
63 else
64 GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
65 }
74 } else { 66 } else {
75 act_as->cap_effective = 67 gi = get_group_info(rqgi);
76 cap_raise_nfsd_set(act_as->cap_effective,
77 act_as->cap_permitted);
78 } 68 }
69
70 if (new->fsuid == (uid_t) -1)
71 new->fsuid = exp->ex_anon_uid;
72 if (new->fsgid == (gid_t) -1)
73 new->fsgid = exp->ex_anon_gid;
74
75 ret = set_groups(new, gi);
76 put_group_info(gi);
77 if (!ret)
78 goto error;
79
80 if (new->uid)
81 new->cap_effective = cap_drop_nfsd_set(new->cap_effective);
82 else
83 new->cap_effective = cap_raise_nfsd_set(new->cap_effective,
84 new->cap_permitted);
85 return commit_creds(new);
86
87oom:
88 ret = -ENOMEM;
89error:
90 abort_creds(new);
79 return ret; 91 return ret;
80} 92}
81 93
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 632a50b4b371..9371ea12d7fa 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->cred->fsuid; 60 struct cred *new;
61 *savegid = current->cred->fsgid; 61
62 current->cred->fsuid = 0; 62 new = prepare_creds();
63 current->cred->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->cred->fsuid = saveuid; 76 revert_creds(original);
70 current->cred->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,20 +218,21 @@ 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 236
229 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY, 237 filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
230 current_cred()); 238 current_cred());
@@ -250,7 +258,7 @@ out:
250 dput(child->dentry); 258 dput(child->dentry);
251 kfree(child); 259 kfree(child);
252 } 260 }
253 nfs4_reset_user(uid, gid); 261 nfs4_reset_creds(original_cred);
254 return status; 262 return status;
255} 263}
256 264
@@ -312,8 +320,7 @@ out:
312void 320void
313nfsd4_remove_clid_dir(struct nfs4_client *clp) 321nfsd4_remove_clid_dir(struct nfs4_client *clp)
314{ 322{
315 uid_t uid; 323 const struct cred *original_cred;
316 gid_t gid;
317 int status; 324 int status;
318 325
319 if (!rec_dir_init || !clp->cl_firststate) 326 if (!rec_dir_init || !clp->cl_firststate)
@@ -323,9 +330,13 @@ nfsd4_remove_clid_dir(struct nfs4_client *clp)
323 if (status) 330 if (status)
324 goto out; 331 goto out;
325 clp->cl_firststate = 0; 332 clp->cl_firststate = 0;
326 nfs4_save_user(&uid, &gid); 333
334 status = nfs4_save_creds(&original_cred);
335 if (status < 0)
336 goto out;
337
327 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); 338 status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
328 nfs4_reset_user(uid, gid); 339 nfs4_reset_creds(original_cred);
329 if (status == 0) 340 if (status == 0)
330 nfsd4_sync_rec_dir(); 341 nfsd4_sync_rec_dir();
331 mnt_drop_write(rec_dir.mnt); 342 mnt_drop_write(rec_dir.mnt);
@@ -402,16 +413,21 @@ nfsd4_recdir_load(void) {
402void 413void
403nfsd4_init_recdir(char *rec_dirname) 414nfsd4_init_recdir(char *rec_dirname)
404{ 415{
405 uid_t uid = 0; 416 const struct cred *original_cred;
406 gid_t gid = 0; 417 int status;
407 int status;
408 418
409 printk("NFSD: Using %s as the NFSv4 state recovery directory\n", 419 printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
410 rec_dirname); 420 rec_dirname);
411 421
412 BUG_ON(rec_dir_init); 422 BUG_ON(rec_dir_init);
413 423
414 nfs4_save_user(&uid, &gid); 424 status = nfs4_save_creds(&original_cred);
425 if (status < 0) {
426 printk("NFSD: Unable to change credentials to find recovery"
427 " directory: error %d\n",
428 status);
429 return;
430 }
415 431
416 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 432 status = kern_path(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
417 &rec_dir); 433 &rec_dir);
@@ -421,7 +437,7 @@ nfsd4_init_recdir(char *rec_dirname)
421 437
422 if (!status) 438 if (!status)
423 rec_dir_init = 1; 439 rec_dir_init = 1;
424 nfs4_reset_user(uid, gid); 440 nfs4_reset_creds(original_cred);
425} 441}
426 442
427void 443void
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index e67cfaea0865..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->cred->cap_effective = 189 struct cred *new = prepare_creds();
190 cap_raise_nfsd_set(current->cred->cap_effective, 190 if (!new)
191 current->cred->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)