]>
Commit | Line | Data |
---|---|---|
7f651772 | 1 | Changes since 2.6.22-rc1-CITI_NFS4_ALL-1 |
2 | - update to 2.6.22-rc5 | |
3 | - allow id-squashing options to vary per pseudoflavor | |
4 | - enforce requirement that flags other than ro/rw and | |
5 | id-squashing flags not vary per pseudoflavor | |
6 | - meelap: vary maximum delegation limit by RAM size | |
7 | - meelap: don't grant delegations on files that saw conflicts | |
8 | - silence a compiler warning in ACL code | |
9 | - bhalevy: fix enc_stateid_sz for nfsd callbacks | |
10 | - fix mishandling of acl errors that could cause an oops | |
11 | - make all export finding function return -errno's on err | |
12 | - show flavor info in /proc/net/rpc/nfsd.export/content | |
13 | - miscellaneous cleanup | |
14 | ||
15 | --- | |
16 | ||
17 | b/fs/Kconfig | 1 | |
18 | b/fs/lockd/svc.c | 31 ++- | |
19 | b/fs/locks.c | 23 +- | |
20 | b/fs/nfs/file.c | 4 | |
21 | b/fs/nfsd/auth.c | 18 +- | |
22 | b/fs/nfsd/export.c | 284 ++++++++++++++++++++++++++------ | |
23 | b/fs/nfsd/lockd.c | 1 | |
24 | b/fs/nfsd/nfs4acl.c | 12 + | |
25 | b/fs/nfsd/nfs4callback.c | 2 | |
26 | b/fs/nfsd/nfs4idmap.c | 13 + | |
27 | b/fs/nfsd/nfs4proc.c | 34 +++ | |
28 | b/fs/nfsd/nfs4state.c | 28 ++- | |
29 | b/fs/nfsd/nfs4xdr.c | 99 +++++++++++ | |
30 | b/fs/nfsd/nfsctl.c | 1 | |
31 | b/fs/nfsd/nfsfh.c | 32 ++- | |
32 | b/fs/nfsd/nfsproc.c | 3 | |
33 | b/fs/nfsd/nfssvc.c | 10 + | |
34 | b/fs/nfsd/vfs.c | 110 ++++++------ | |
35 | b/fs/open.c | 16 + | |
36 | b/include/linux/fs.h | 2 | |
37 | b/include/linux/lockd/bind.h | 9 + | |
38 | b/include/linux/nfsd/export.h | 41 ++++ | |
39 | b/include/linux/nfsd/nfsd.h | 9 - | |
40 | b/include/linux/nfsd/state.h | 3 | |
41 | b/include/linux/nfsd/xdr4.h | 7 | |
42 | b/include/linux/sunrpc/gss_api.h | 1 | |
43 | b/include/linux/sunrpc/svc.h | 2 | |
44 | b/include/linux/sunrpc/svcauth.h | 1 | |
45 | b/include/linux/sunrpc/svcauth_gss.h | 2 | |
46 | b/net/sunrpc/auth_gss/gss_krb5_mech.c | 1 | |
47 | b/net/sunrpc/auth_gss/gss_mech_switch.c | 15 + | |
48 | b/net/sunrpc/auth_gss/gss_spkm3_mech.c | 1 | |
49 | b/net/sunrpc/auth_gss/svcauth_gss.c | 32 +++ | |
50 | b/net/sunrpc/svcauth_unix.c | 7 | |
51 | include/linux/nfsd/interface.h | 13 - | |
52 | 36 files changed, 693 insertions(+), 177 deletions(-) | |
53 | ||
54 | diff --git a/fs/Kconfig b/fs/Kconfig | |
55 | index 0fa0c11..76cf825 100644 | |
56 | --- a/fs/Kconfig | |
57 | +++ b/fs/Kconfig | |
58 | @@ -1675,6 +1675,7 @@ config NFSD_V3_ACL | |
59 | config NFSD_V4 | |
60 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | |
61 | depends on NFSD_V3 && EXPERIMENTAL | |
62 | + select RPCSEC_GSS_KRB5 | |
63 | help | |
64 | If you would like to include the NFSv4 server as well as the NFSv2 | |
65 | and NFSv3 servers, say Y here. This feature is experimental, and | |
66 | diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c | |
67 | index 126b1bf..6378572 100644 | |
68 | --- a/fs/lockd/svc.c | |
69 | +++ b/fs/lockd/svc.c | |
70 | @@ -75,18 +75,35 @@ static const int nlm_port_min = 0, nlm_port_max = 65535; | |
71 | ||
72 | static struct ctl_table_header * nlm_sysctl_table; | |
73 | ||
74 | -static unsigned long set_grace_period(void) | |
75 | +static time_t get_lockd_grace_period(void) | |
76 | { | |
77 | - unsigned long grace_period; | |
78 | - | |
79 | /* Note: nlm_timeout should always be nonzero */ | |
80 | if (nlm_grace_period) | |
81 | - grace_period = ((nlm_grace_period + nlm_timeout - 1) | |
82 | - / nlm_timeout) * nlm_timeout * HZ; | |
83 | + return ((nlm_grace_period + nlm_timeout - 1) | |
84 | + / nlm_timeout) * nlm_timeout; | |
85 | else | |
86 | - grace_period = nlm_timeout * 5 * HZ; | |
87 | + return nlm_timeout * 5; | |
88 | +} | |
89 | + | |
90 | +time_t get_nfs_grace_period(void) | |
91 | +{ | |
92 | + time_t lockdgrace = get_lockd_grace_period(); | |
93 | + time_t nfsdgrace = 0; | |
94 | + | |
95 | + if (nlmsvc_ops) | |
96 | + nfsdgrace = nlmsvc_ops->get_grace_period(); | |
97 | + | |
98 | + return max(lockdgrace, nfsdgrace); | |
99 | +} | |
100 | +EXPORT_SYMBOL(get_nfs_grace_period); | |
101 | + | |
102 | +static unsigned long set_grace_period(void) | |
103 | +{ | |
104 | + time_t grace_period; | |
105 | + | |
106 | + grace_period = get_nfs_grace_period(); | |
107 | nlmsvc_grace_period = 1; | |
108 | - return grace_period + jiffies; | |
109 | + return grace_period * HZ + jiffies; | |
110 | } | |
111 | ||
112 | static inline void clear_grace_period(void) | |
113 | diff --git a/fs/locks.c b/fs/locks.c | |
114 | index 431a8b8..bcc37b9 100644 | |
115 | --- a/fs/locks.c | |
116 | +++ b/fs/locks.c | |
117 | @@ -661,7 +661,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w | |
118 | return result; | |
119 | } | |
120 | ||
121 | -int | |
122 | +void | |
123 | posix_test_lock(struct file *filp, struct file_lock *fl) | |
124 | { | |
125 | struct file_lock *cfl; | |
126 | @@ -670,17 +670,15 @@ posix_test_lock(struct file *filp, struct file_lock *fl) | |
127 | for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { | |
128 | if (!IS_POSIX(cfl)) | |
129 | continue; | |
130 | - if (posix_locks_conflict(cfl, fl)) | |
131 | + if (posix_locks_conflict(fl, cfl)) | |
132 | break; | |
133 | } | |
134 | - if (cfl) { | |
135 | + if (cfl) | |
136 | __locks_copy_lock(fl, cfl); | |
137 | - unlock_kernel(); | |
138 | - return 1; | |
139 | - } else | |
140 | + else | |
141 | fl->fl_type = F_UNLCK; | |
142 | unlock_kernel(); | |
143 | - return 0; | |
144 | + return; | |
145 | } | |
146 | ||
147 | EXPORT_SYMBOL(posix_test_lock); | |
148 | @@ -823,7 +821,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |
149 | lock_kernel(); | |
150 | if (request->fl_type != F_UNLCK) { | |
151 | for_each_lock(inode, before) { | |
152 | - struct file_lock *fl = *before; | |
153 | + fl = *before; | |
154 | if (!IS_POSIX(fl)) | |
155 | continue; | |
156 | if (!posix_locks_conflict(request, fl)) | |
157 | @@ -1169,9 +1167,9 @@ static void time_out_leases(struct inode *inode) | |
158 | * @inode: the inode of the file to return | |
159 | * @mode: the open mode (read or write) | |
160 | * | |
161 | - * break_lease (inlined for speed) has checked there already | |
162 | - * is a lease on this file. Leases are broken on a call to open() | |
163 | - * or truncate(). This function can sleep unless you | |
164 | + * break_lease (inlined for speed) has checked there already is at least | |
165 | + * some kind of lock (maybe a lease) on this file. Leases are broken on | |
166 | + * a call to open() or truncate(). This function can sleep unless you | |
167 | * specified %O_NONBLOCK to your open(). | |
168 | */ | |
169 | int __break_lease(struct inode *inode, unsigned int mode) | |
170 | @@ -1597,8 +1595,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) | |
171 | /** | |
172 | * vfs_test_lock - test file byte range lock | |
173 | * @filp: The file to test lock for | |
174 | - * @fl: The lock to test | |
175 | - * @conf: Place to return a copy of the conflicting lock, if found | |
176 | + * @fl: The lock to test; also used to hold result | |
177 | * | |
178 | * Returns -ERRNO on failure. Indicates presence of conflicting lock by | |
179 | * setting conf->fl_type to something other than F_UNLCK. | |
180 | diff --git a/fs/nfs/file.c b/fs/nfs/file.c | |
181 | index 9eb8eb4..5b24e88 100644 | |
182 | --- a/fs/nfs/file.c | |
183 | +++ b/fs/nfs/file.c | |
184 | @@ -397,7 +397,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | |
185 | ||
186 | lock_kernel(); | |
187 | /* Try local locking first */ | |
188 | - if (posix_test_lock(filp, fl)) { | |
189 | + posix_test_lock(filp, fl); | |
190 | + if (fl->fl_type != F_UNLCK) { | |
191 | + /* found a conflict */ | |
192 | goto out; | |
193 | } | |
194 | ||
195 | diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c | |
196 | index 6e92b0f..cf61dc8 100644 | |
197 | --- a/fs/nfsd/auth.c | |
198 | +++ b/fs/nfsd/auth.c | |
199 | @@ -12,17 +12,31 @@ | |
200 | ||
201 | #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) | |
202 | ||
203 | +static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | |
204 | +{ | |
205 | + struct exp_flavor_info *f; | |
206 | + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | |
207 | + | |
208 | + for (f = exp->ex_flavors; f < end; f++) { | |
209 | + if (f->pseudoflavor == rqstp->rq_flavor) | |
210 | + return f->flags; | |
211 | + } | |
212 | + return exp->ex_flags; | |
213 | + | |
214 | +} | |
215 | + | |
216 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |
217 | { | |
218 | struct svc_cred cred = rqstp->rq_cred; | |
219 | int i; | |
220 | + int flags = nfsexp_flags(rqstp, exp); | |
221 | int ret; | |
222 | ||
223 | - if (exp->ex_flags & NFSEXP_ALLSQUASH) { | |
224 | + if (flags & NFSEXP_ALLSQUASH) { | |
225 | cred.cr_uid = exp->ex_anon_uid; | |
226 | cred.cr_gid = exp->ex_anon_gid; | |
227 | cred.cr_group_info = groups_alloc(0); | |
228 | - } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { | |
229 | + } else if (flags & NFSEXP_ROOTSQUASH) { | |
230 | struct group_info *gi; | |
231 | if (!cred.cr_uid) | |
232 | cred.cr_uid = exp->ex_anon_uid; | |
233 | diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c | |
234 | index 79bd03b..d9ed7f1 100644 | |
235 | --- a/fs/nfsd/export.c | |
236 | +++ b/fs/nfsd/export.c | |
237 | @@ -32,6 +32,8 @@ | |
238 | #include <linux/nfsd/nfsfh.h> | |
239 | #include <linux/nfsd/syscall.h> | |
240 | #include <linux/lockd/bind.h> | |
241 | +#include <linux/sunrpc/msg_prot.h> | |
242 | +#include <linux/sunrpc/gss_api.h> | |
243 | ||
244 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | |
245 | ||
246 | @@ -451,8 +453,46 @@ out_free_all: | |
247 | return err; | |
248 | } | |
249 | ||
250 | +static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | |
251 | +{ | |
252 | + int listsize, err; | |
253 | + struct exp_flavor_info *f; | |
254 | + | |
255 | + err = get_int(mesg, &listsize); | |
256 | + if (err) | |
257 | + return err; | |
258 | + if (listsize < 0 || listsize > MAX_SECINFO_LIST) | |
259 | + return -EINVAL; | |
260 | + | |
261 | + for (f=exp->ex_flavors; f < exp->ex_flavors + listsize; f++) { | |
262 | + err = get_int(mesg, &f->pseudoflavor); | |
263 | + if (err) | |
264 | + return err; | |
265 | + /* | |
266 | + * Just a quick sanity check; we could also try to check | |
267 | + * whether this pseudoflavor is supported, but at worst | |
268 | + * an unsupported pseudoflavor on the export would just | |
269 | + * be a pseudoflavor that won't match the flavor of any | |
270 | + * authenticated request. The administrator will | |
271 | + * probably discover the problem when someone fails to | |
272 | + * authenticate. | |
273 | + */ | |
274 | + if (f->pseudoflavor < 0) | |
275 | + return -EINVAL; | |
276 | + err = get_int(mesg, &f->flags); | |
277 | + if (err) | |
278 | + return err; | |
279 | + /* Only some flags are allowed to differ between flavors: */ | |
280 | + if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags)) | |
281 | + return -EINVAL; | |
282 | + } | |
283 | + exp->ex_nflavors = listsize; | |
284 | + return 0; | |
285 | +} | |
286 | + | |
287 | #else /* CONFIG_NFSD_V4 */ | |
288 | static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } | |
289 | +static inline int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; } | |
290 | #endif | |
291 | ||
292 | static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |
293 | @@ -476,6 +516,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |
294 | ||
295 | exp.ex_uuid = NULL; | |
296 | ||
297 | + /* secinfo */ | |
298 | + exp.ex_nflavors = 0; | |
299 | + | |
300 | if (mesg[mlen-1] != '\n') | |
301 | return -EINVAL; | |
302 | mesg[mlen-1] = 0; | |
303 | @@ -553,7 +596,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |
304 | if (exp.ex_uuid == NULL) | |
305 | err = -ENOMEM; | |
306 | } | |
307 | - } else | |
308 | + } else if (strcmp(buf, "secinfo") == 0) | |
309 | + err = secinfo_parse(&mesg, buf, &exp); | |
310 | + else | |
311 | /* quietly ignore unknown words and anything | |
312 | * following. Newer user-space can try to set | |
313 | * new values, then see what the result was. | |
314 | @@ -593,6 +638,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |
315 | ||
316 | static void exp_flags(struct seq_file *m, int flag, int fsid, | |
317 | uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); | |
318 | +static void show_secinfo(struct seq_file *m, struct svc_export *exp); | |
319 | ||
320 | static int svc_export_show(struct seq_file *m, | |
321 | struct cache_detail *cd, | |
322 | @@ -622,6 +668,7 @@ static int svc_export_show(struct seq_file *m, | |
323 | seq_printf(m, "%02x", exp->ex_uuid[i]); | |
324 | } | |
325 | } | |
326 | + show_secinfo(m, exp); | |
327 | } | |
328 | seq_puts(m, ")\n"); | |
329 | return 0; | |
330 | @@ -654,6 +701,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |
331 | { | |
332 | struct svc_export *new = container_of(cnew, struct svc_export, h); | |
333 | struct svc_export *item = container_of(citem, struct svc_export, h); | |
334 | + int i; | |
335 | ||
336 | new->ex_flags = item->ex_flags; | |
337 | new->ex_anon_uid = item->ex_anon_uid; | |
338 | @@ -669,6 +717,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |
339 | item->ex_fslocs.locations_count = 0; | |
340 | new->ex_fslocs.migrated = item->ex_fslocs.migrated; | |
341 | item->ex_fslocs.migrated = 0; | |
342 | + new->ex_nflavors = item->ex_nflavors; | |
343 | + for (i = 0; i < MAX_SECINFO_LIST; i++){ | |
344 | + new->ex_flavors[i] = item->ex_flavors[i]; | |
345 | + } | |
346 | } | |
347 | ||
348 | static struct cache_head *svc_export_alloc(void) | |
349 | @@ -738,16 +790,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |
350 | int err; | |
351 | ||
352 | if (!clp) | |
353 | - return NULL; | |
354 | + return ERR_PTR(-ENOENT); | |
355 | ||
356 | key.ek_client = clp; | |
357 | key.ek_fsidtype = fsid_type; | |
358 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | |
359 | ||
360 | ek = svc_expkey_lookup(&key); | |
361 | - if (ek != NULL) | |
362 | - if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) | |
363 | - ek = ERR_PTR(err); | |
364 | + if (ek == NULL) | |
365 | + return ERR_PTR(-ENOMEM); | |
366 | + err = cache_check(&svc_expkey_cache, &ek->h, reqp); | |
367 | + if (err) | |
368 | + return ERR_PTR(err); | |
369 | return ek; | |
370 | } | |
371 | ||
372 | @@ -808,30 +862,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, | |
373 | struct cache_req *reqp) | |
374 | { | |
375 | struct svc_export *exp, key; | |
376 | + int err; | |
377 | ||
378 | if (!clp) | |
379 | - return NULL; | |
380 | + return ERR_PTR(-ENOENT); | |
381 | ||
382 | key.ex_client = clp; | |
383 | key.ex_mnt = mnt; | |
384 | key.ex_dentry = dentry; | |
385 | ||
386 | exp = svc_export_lookup(&key); | |
387 | - if (exp != NULL) { | |
388 | - int err; | |
389 | - | |
390 | - err = cache_check(&svc_export_cache, &exp->h, reqp); | |
391 | - switch (err) { | |
392 | - case 0: break; | |
393 | - case -EAGAIN: | |
394 | - case -ETIMEDOUT: | |
395 | - exp = ERR_PTR(err); | |
396 | - break; | |
397 | - default: | |
398 | - exp = NULL; | |
399 | - } | |
400 | - } | |
401 | - | |
402 | + if (exp == NULL) | |
403 | + return ERR_PTR(-ENOMEM); | |
404 | + err = cache_check(&svc_export_cache, &exp->h, reqp); | |
405 | + if (err) | |
406 | + return ERR_PTR(err); | |
407 | return exp; | |
408 | } | |
409 | ||
410 | @@ -847,7 +892,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, | |
411 | dget(dentry); | |
412 | exp = exp_get_by_name(clp, mnt, dentry, reqp); | |
413 | ||
414 | - while (exp == NULL && !IS_ROOT(dentry)) { | |
415 | + while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { | |
416 | struct dentry *parent; | |
417 | ||
418 | parent = dget_parent(dentry); | |
419 | @@ -900,7 +945,7 @@ static void exp_fsid_unhash(struct svc_export *exp) | |
420 | return; | |
421 | ||
422 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); | |
423 | - if (ek && !IS_ERR(ek)) { | |
424 | + if (!IS_ERR(ek)) { | |
425 | ek->h.expiry_time = get_seconds()-1; | |
426 | cache_put(&ek->h, &svc_expkey_cache); | |
427 | } | |
428 | @@ -938,7 +983,7 @@ static void exp_unhash(struct svc_export *exp) | |
429 | struct inode *inode = exp->ex_dentry->d_inode; | |
430 | ||
431 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); | |
432 | - if (ek && !IS_ERR(ek)) { | |
433 | + if (!IS_ERR(ek)) { | |
434 | ek->h.expiry_time = get_seconds()-1; | |
435 | cache_put(&ek->h, &svc_expkey_cache); | |
436 | } | |
437 | @@ -989,13 +1034,12 @@ exp_export(struct nfsctl_export *nxp) | |
438 | ||
439 | /* must make sure there won't be an ex_fsid clash */ | |
440 | if ((nxp->ex_flags & NFSEXP_FSID) && | |
441 | - (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && | |
442 | - !IS_ERR(fsid_key) && | |
443 | + (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && | |
444 | fsid_key->ek_mnt && | |
445 | (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) | |
446 | goto finish; | |
447 | ||
448 | - if (exp) { | |
449 | + if (!IS_ERR(exp)) { | |
450 | /* just a flags/id/fsid update */ | |
451 | ||
452 | exp_fsid_unhash(exp); | |
453 | @@ -1104,7 +1148,7 @@ exp_unexport(struct nfsctl_export *nxp) | |
454 | err = -EINVAL; | |
455 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); | |
456 | path_release(&nd); | |
457 | - if (!exp) | |
458 | + if (IS_ERR(exp)) | |
459 | goto out_domain; | |
460 | ||
461 | exp_do_unexport(exp); | |
462 | @@ -1149,10 +1193,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) | |
463 | err = PTR_ERR(exp); | |
464 | goto out; | |
465 | } | |
466 | - if (!exp) { | |
467 | - dprintk("nfsd: exp_rootfh export not found.\n"); | |
468 | - goto out; | |
469 | - } | |
470 | ||
471 | /* | |
472 | * fh must be initialized before calling fh_compose | |
473 | @@ -1176,17 +1216,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | |
474 | { | |
475 | struct svc_export *exp; | |
476 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | |
477 | - if (!ek || IS_ERR(ek)) | |
478 | + if (IS_ERR(ek)) | |
479 | return ERR_PTR(PTR_ERR(ek)); | |
480 | ||
481 | exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); | |
482 | cache_put(&ek->h, &svc_expkey_cache); | |
483 | ||
484 | - if (!exp || IS_ERR(exp)) | |
485 | + if (IS_ERR(exp)) | |
486 | return ERR_PTR(PTR_ERR(exp)); | |
487 | return exp; | |
488 | } | |
489 | ||
490 | +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | |
491 | +{ | |
492 | + struct exp_flavor_info *f; | |
493 | + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | |
494 | + | |
495 | + /* legacy gss-only clients are always OK: */ | |
496 | + if (exp->ex_client == rqstp->rq_gssclient) | |
497 | + return 0; | |
498 | + /* ip-address based client; check sec= export option: */ | |
499 | + for (f = exp->ex_flavors; f < end; f++) { | |
500 | + if (f->pseudoflavor == rqstp->rq_flavor) | |
501 | + return 0; | |
502 | + } | |
503 | + /* defaults in absence of sec= options: */ | |
504 | + if (exp->ex_nflavors == 0) { | |
505 | + if (rqstp->rq_flavor == RPC_AUTH_NULL || | |
506 | + rqstp->rq_flavor == RPC_AUTH_UNIX) | |
507 | + return 0; | |
508 | + } | |
509 | + return nfserr_wrongsec; | |
510 | +} | |
511 | + | |
512 | +/* | |
513 | + * Uses rq_client and rq_gssclient to find an export; uses rq_client (an | |
514 | + * auth_unix client) if it's available and has secinfo information; | |
515 | + * otherwise, will try to use rq_gssclient. | |
516 | + * | |
517 | + * Called from functions that handle requests; functions that do work on | |
518 | + * behalf of mountd are passed a single client name to use, and should | |
519 | + * use exp_get_by_name() or exp_find(). | |
520 | + */ | |
521 | +struct svc_export * | |
522 | +rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, | |
523 | + struct dentry *dentry) | |
524 | +{ | |
525 | + struct svc_export *gssexp, *exp = NULL; | |
526 | + | |
527 | + if (rqstp->rq_client == NULL) | |
528 | + goto gss; | |
529 | + | |
530 | + /* First try the auth_unix client: */ | |
531 | + exp = exp_get_by_name(rqstp->rq_client, mnt, dentry, | |
532 | + &rqstp->rq_chandle); | |
533 | + if (PTR_ERR(exp) == -ENOENT) | |
534 | + goto gss; | |
535 | + if (IS_ERR(exp)) | |
536 | + return exp; | |
537 | + /* If it has secinfo, assume there are no gss/... clients */ | |
538 | + if (exp->ex_nflavors > 0) | |
539 | + return exp; | |
540 | +gss: | |
541 | + /* Otherwise, try falling back on gss client */ | |
542 | + if (rqstp->rq_gssclient == NULL) | |
543 | + return exp; | |
544 | + gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry, | |
545 | + &rqstp->rq_chandle); | |
546 | + if (PTR_ERR(gssexp) == -ENOENT) | |
547 | + return exp; | |
548 | + if (exp) | |
549 | + exp_put(exp); | |
550 | + return gssexp; | |
551 | +} | |
552 | + | |
553 | +struct svc_export * | |
554 | +rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) | |
555 | +{ | |
556 | + struct svc_export *gssexp, *exp = NULL; | |
557 | + | |
558 | + if (rqstp->rq_client == NULL) | |
559 | + goto gss; | |
560 | + | |
561 | + /* First try the auth_unix client: */ | |
562 | + exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle); | |
563 | + if (PTR_ERR(exp) == -ENOENT) | |
564 | + goto gss; | |
565 | + if (IS_ERR(exp)) | |
566 | + return exp; | |
567 | + /* If it has secinfo, assume there are no gss/... clients */ | |
568 | + if (exp->ex_nflavors > 0) | |
569 | + return exp; | |
570 | +gss: | |
571 | + /* Otherwise, try falling back on gss client */ | |
572 | + if (rqstp->rq_gssclient == NULL) | |
573 | + return exp; | |
574 | + gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv, | |
575 | + &rqstp->rq_chandle); | |
576 | + if (PTR_ERR(gssexp) == -ENOENT) | |
577 | + return exp; | |
578 | + if (exp) | |
579 | + exp_put(exp); | |
580 | + return gssexp; | |
581 | +} | |
582 | + | |
583 | +struct svc_export * | |
584 | +rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt, | |
585 | + struct dentry *dentry) | |
586 | +{ | |
587 | + struct svc_export *exp; | |
588 | + | |
589 | + dget(dentry); | |
590 | + exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | |
591 | + | |
592 | + while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { | |
593 | + struct dentry *parent; | |
594 | + | |
595 | + parent = dget_parent(dentry); | |
596 | + dput(dentry); | |
597 | + dentry = parent; | |
598 | + exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | |
599 | + } | |
600 | + dput(dentry); | |
601 | + return exp; | |
602 | +} | |
603 | ||
604 | /* | |
605 | * Called when we need the filehandle for the root of the pseudofs, | |
606 | @@ -1194,8 +1347,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | |
607 | * export point with fsid==0 | |
608 | */ | |
609 | __be32 | |
610 | -exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |
611 | - struct cache_req *creq) | |
612 | +exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |
613 | { | |
614 | struct svc_export *exp; | |
615 | __be32 rv; | |
616 | @@ -1203,12 +1355,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |
617 | ||
618 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); | |
619 | ||
620 | - exp = exp_find(clp, FSID_NUM, fsidv, creq); | |
621 | + exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); | |
622 | + if (PTR_ERR(exp) == -ENOENT) | |
623 | + return nfserr_perm; | |
624 | if (IS_ERR(exp)) | |
625 | return nfserrno(PTR_ERR(exp)); | |
626 | - if (exp == NULL) | |
627 | - return nfserr_perm; | |
628 | rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); | |
629 | + if (rv) | |
630 | + goto out; | |
631 | + rv = check_nfsd_access(exp, rqstp); | |
632 | +out: | |
633 | exp_put(exp); | |
634 | return rv; | |
635 | } | |
636 | @@ -1296,28 +1452,62 @@ static struct flags { | |
637 | { 0, {"", ""}} | |
638 | }; | |
639 | ||
640 | -static void exp_flags(struct seq_file *m, int flag, int fsid, | |
641 | - uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) | |
642 | +static void show_expflags(struct seq_file *m, int flags, int mask) | |
643 | { | |
644 | - int first = 0; | |
645 | struct flags *flg; | |
646 | + int state, first = 0; | |
647 | ||
648 | for (flg = expflags; flg->flag; flg++) { | |
649 | - int state = (flg->flag & flag)?0:1; | |
650 | + if (flg->flag & ~mask) | |
651 | + continue; | |
652 | + state = (flg->flag & flags) ? 0 : 1; | |
653 | if (*flg->name[state]) | |
654 | seq_printf(m, "%s%s", first++?",":"", flg->name[state]); | |
655 | } | |
656 | +} | |
657 | + | |
658 | +static void show_secinfo_flags(struct seq_file *m, int flags) | |
659 | +{ | |
660 | + seq_printf(m, ","); | |
661 | + show_expflags(m, flags, NFSEXP_SECINFO_FLAGS); | |
662 | +} | |
663 | + | |
664 | +static void show_secinfo(struct seq_file *m, struct svc_export *exp) | |
665 | +{ | |
666 | + struct exp_flavor_info *f; | |
667 | + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | |
668 | + int lastflags = 0, first = 0; | |
669 | + | |
670 | + if (exp->ex_nflavors == 0) | |
671 | + return; | |
672 | + for (f = exp->ex_flavors; f < end; f++) { | |
673 | + if (first || f->flags != lastflags) { | |
674 | + if (!first) | |
675 | + show_secinfo_flags(m, lastflags); | |
676 | + seq_printf(m, ",sec=%d", f->pseudoflavor); | |
677 | + lastflags = f->flags; | |
678 | + } else { | |
679 | + seq_printf(m, ":%d", f->pseudoflavor); | |
680 | + } | |
681 | + } | |
682 | + show_secinfo_flags(m, lastflags); | |
683 | +} | |
684 | + | |
685 | +static void exp_flags(struct seq_file *m, int flag, int fsid, | |
686 | + uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) | |
687 | +{ | |
688 | + show_expflags(m, flag, NFSEXP_ALLFLAGS); | |
689 | if (flag & NFSEXP_FSID) | |
690 | - seq_printf(m, "%sfsid=%d", first++?",":"", fsid); | |
691 | + seq_printf(m, ",fsid=%d", fsid); | |
692 | if (anonu != (uid_t)-2 && anonu != (0x10000-2)) | |
693 | - seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); | |
694 | + seq_printf(m, ",sanonuid=%d", anonu); | |
695 | if (anong != (gid_t)-2 && anong != (0x10000-2)) | |
696 | - seq_printf(m, "%sanongid=%d", first++?",":"", anong); | |
697 | + seq_printf(m, ",sanongid=%d", anong); | |
698 | if (fsloc && fsloc->locations_count > 0) { | |
699 | char *loctype = (fsloc->migrated) ? "refer" : "replicas"; | |
700 | int i; | |
701 | ||
702 | - seq_printf(m, "%s%s=", first++?",":"", loctype); | |
703 | + seq_printf(m, ",%s=", loctype); | |
704 | seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); | |
705 | seq_putc(m, '@'); | |
706 | seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); | |
707 | diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c | |
708 | index 221acd1..9e4a568 100644 | |
709 | --- a/fs/nfsd/lockd.c | |
710 | +++ b/fs/nfsd/lockd.c | |
711 | @@ -65,6 +65,7 @@ nlm_fclose(struct file *filp) | |
712 | static struct nlmsvc_binding nfsd_nlm_ops = { | |
713 | .fopen = nlm_fopen, /* open file for locking */ | |
714 | .fclose = nlm_fclose, /* close file */ | |
715 | + .get_grace_period = get_nfs4_grace_period, | |
716 | }; | |
717 | ||
718 | void | |
719 | diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c | |
720 | index cc3b7ba..b6ed383 100644 | |
721 | --- a/fs/nfsd/nfs4acl.c | |
722 | +++ b/fs/nfsd/nfs4acl.c | |
723 | @@ -183,8 +183,13 @@ static void | |
724 | summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) | |
725 | { | |
726 | struct posix_acl_entry *pa, *pe; | |
727 | - pas->users = 0; | |
728 | - pas->groups = 0; | |
729 | + | |
730 | + /* | |
731 | + * Only pas.users and pas.groups need initialization; previous | |
732 | + * posix_acl_valid() calls ensure that the other fields will be | |
733 | + * initialized in the following loop. But, just to placate gcc: | |
734 | + */ | |
735 | + memset(pas, 0, sizeof(*pas)); | |
736 | pas->mask = 07; | |
737 | ||
738 | pe = acl->a_entries + acl->a_count; | |
739 | @@ -732,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, | |
740 | *pacl = posix_state_to_acl(&effective_acl_state, flags); | |
741 | if (IS_ERR(*pacl)) { | |
742 | ret = PTR_ERR(*pacl); | |
743 | + *pacl = NULL; | |
744 | goto out_dstate; | |
745 | } | |
746 | *dpacl = posix_state_to_acl(&default_acl_state, | |
747 | flags | NFS4_ACL_TYPE_DEFAULT); | |
748 | if (IS_ERR(*dpacl)) { | |
749 | ret = PTR_ERR(*dpacl); | |
750 | + *dpacl = NULL; | |
751 | posix_acl_release(*pacl); | |
752 | + *pacl = NULL; | |
753 | goto out_dstate; | |
754 | } | |
755 | sort_pacl(*pacl); | |
756 | diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c | |
757 | index 864090e..c9e0c30 100644 | |
758 | --- a/fs/nfsd/nfs4callback.c | |
759 | +++ b/fs/nfsd/nfs4callback.c | |
760 | @@ -75,7 +75,7 @@ enum nfs_cb_opnum4 { | |
761 | #define op_enc_sz 1 | |
762 | #define op_dec_sz 2 | |
763 | #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) | |
764 | -#define enc_stateid_sz 16 | |
765 | +#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2) | |
766 | #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ | |
767 | 1 + enc_stateid_sz + \ | |
768 | enc_nfs4_fh_sz) | |
769 | diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c | |
770 | index 45aa21c..2cf9a9a 100644 | |
771 | --- a/fs/nfsd/nfs4idmap.c | |
772 | +++ b/fs/nfsd/nfs4idmap.c | |
773 | @@ -587,6 +587,15 @@ idmap_lookup(struct svc_rqst *rqstp, | |
774 | return ret; | |
775 | } | |
776 | ||
777 | +static char * | |
778 | +rqst_authname(struct svc_rqst *rqstp) | |
779 | +{ | |
780 | + struct auth_domain *clp; | |
781 | + | |
782 | + clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; | |
783 | + return clp->name; | |
784 | +} | |
785 | + | |
786 | static int | |
787 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, | |
788 | uid_t *id) | |
789 | @@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |
790 | return -EINVAL; | |
791 | memcpy(key.name, name, namelen); | |
792 | key.name[namelen] = '\0'; | |
793 | - strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); | |
794 | + strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | |
795 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); | |
796 | if (ret == -ENOENT) | |
797 | ret = -ESRCH; /* nfserr_badname */ | |
798 | @@ -620,7 +629,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |
799 | }; | |
800 | int ret; | |
801 | ||
802 | - strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); | |
803 | + strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); | |
804 | ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); | |
805 | if (ret == -ENOENT) | |
806 | return sprintf(name, "%u", id); | |
807 | diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c | |
808 | index 8522729..9403095 100644 | |
809 | --- a/fs/nfsd/nfs4proc.c | |
810 | +++ b/fs/nfsd/nfs4proc.c | |
811 | @@ -47,6 +47,7 @@ | |
812 | #include <linux/nfsd/state.h> | |
813 | #include <linux/nfsd/xdr4.h> | |
814 | #include <linux/nfs4_acl.h> | |
815 | +#include <linux/sunrpc/gss_api.h> | |
816 | ||
817 | #define NFSDDBG_FACILITY NFSDDBG_PROC | |
818 | ||
819 | @@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |
820 | __be32 status; | |
821 | ||
822 | fh_put(&cstate->current_fh); | |
823 | - status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, | |
824 | - &rqstp->rq_chandle); | |
825 | + status = exp_pseudoroot(rqstp, &cstate->current_fh); | |
826 | return status; | |
827 | } | |
828 | ||
829 | @@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |
830 | __be32 ret; | |
831 | ||
832 | fh_init(&tmp_fh, NFS4_FHSIZE); | |
833 | - if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, | |
834 | - &rqstp->rq_chandle)) != 0) | |
835 | + ret = exp_pseudoroot(rqstp, &tmp_fh); | |
836 | + if (ret) | |
837 | return ret; | |
838 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { | |
839 | fh_put(&tmp_fh); | |
840 | @@ -611,6 +611,29 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |
841 | } | |
842 | ||
843 | static __be32 | |
844 | +nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_secinfo *secinfo) | |
845 | +{ | |
846 | + struct svc_fh resfh; | |
847 | + struct svc_export *exp; | |
848 | + struct dentry *dentry; | |
849 | + __be32 err; | |
850 | + | |
851 | + fh_init(&resfh, NFS4_FHSIZE); | |
852 | + err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, | |
853 | + secinfo->si_name, secinfo->si_namelen, | |
854 | + &exp, &dentry); | |
855 | + if (err) | |
856 | + return err; | |
857 | + if (dentry->d_inode == NULL) { | |
858 | + exp_put(exp); | |
859 | + err = nfserr_noent; | |
860 | + } else | |
861 | + secinfo->si_exp = exp; | |
862 | + dput(dentry); | |
863 | + return err; | |
864 | +} | |
865 | + | |
866 | +static __be32 | |
867 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |
868 | struct nfsd4_setattr *setattr) | |
869 | { | |
870 | @@ -1009,6 +1032,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { | |
871 | [OP_SAVEFH] = { | |
872 | .op_func = (nfsd4op_func)nfsd4_savefh, | |
873 | }, | |
874 | + [OP_SECINFO] = { | |
875 | + .op_func = (nfsd4op_func)nfsd4_secinfo, | |
876 | + }, | |
877 | [OP_SETATTR] = { | |
878 | .op_func = (nfsd4op_func)nfsd4_setattr, | |
879 | }, | |
880 | diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c | |
881 | index 3cc8ce4..47d48e8 100644 | |
882 | --- a/fs/nfsd/nfs4state.c | |
883 | +++ b/fs/nfsd/nfs4state.c | |
884 | @@ -51,6 +51,7 @@ | |
885 | #include <linux/namei.h> | |
886 | #include <linux/mutex.h> | |
887 | #include <linux/lockd/bind.h> | |
888 | +#include <linux/module.h> | |
889 | ||
890 | #define NFSDDBG_FACILITY NFSDDBG_PROC | |
891 | ||
892 | @@ -149,6 +150,7 @@ get_nfs4_file(struct nfs4_file *fi) | |
893 | } | |
894 | ||
895 | static int num_delegations; | |
896 | +unsigned int max_delegations = 0; | |
897 | ||
898 | /* | |
899 | * Open owner state (share locks) | |
900 | @@ -192,7 +194,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |
901 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | |
902 | ||
903 | dprintk("NFSD alloc_init_deleg\n"); | |
904 | - if (num_delegations > STATEID_HASH_SIZE * 4) | |
905 | + if (fp->fi_had_conflict) | |
906 | + return NULL; | |
907 | + if (num_delegations > max_delegations) | |
908 | return NULL; | |
909 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); | |
910 | if (dp == NULL) | |
911 | @@ -1000,6 +1004,7 @@ alloc_init_file(struct inode *ino) | |
912 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | |
913 | fp->fi_inode = igrab(ino); | |
914 | fp->fi_id = current_fileid++; | |
915 | + fp->fi_had_conflict = false; | |
916 | return fp; | |
917 | } | |
918 | return NULL; | |
919 | @@ -1326,6 +1331,7 @@ do_recall(void *__dp) | |
920 | { | |
921 | struct nfs4_delegation *dp = __dp; | |
922 | ||
923 | + dp->dl_file->fi_had_conflict = true; | |
924 | nfsd4_cb_recall(dp); | |
925 | return 0; | |
926 | } | |
927 | @@ -3191,6 +3197,23 @@ nfsd4_load_reboot_recovery_data(void) | |
928 | printk("NFSD: Failure reading reboot recovery data\n"); | |
929 | } | |
930 | ||
931 | +time_t | |
932 | +get_nfs4_grace_period(void) | |
933 | +{ | |
934 | + return max(user_lease_time, lease_time); | |
935 | +} | |
936 | + | |
937 | +static void | |
938 | +set_max_delegations() | |
939 | +{ | |
940 | + struct sysinfo sys; | |
941 | + | |
942 | + si_meminfo(&sys); | |
943 | + sys.totalram *= sys.mem_unit; | |
944 | + sys.totalram >>= (18 - PAGE_SHIFT); | |
945 | + max_delegations = (unsigned int) sys.totalram; | |
946 | +} | |
947 | + | |
948 | /* initialization to perform when the nfsd service is started: */ | |
949 | ||
950 | static void | |
951 | @@ -3199,12 +3222,13 @@ __nfs4_state_start(void) | |
952 | time_t grace_time; | |
953 | ||
954 | boot_time = get_seconds(); | |
955 | - grace_time = max(user_lease_time, lease_time); | |
956 | + grace_time = get_nfs_grace_period(); | |
957 | lease_time = user_lease_time; | |
958 | in_grace = 1; | |
959 | printk("NFSD: starting %ld-second grace period\n", grace_time); | |
960 | laundry_wq = create_singlethread_workqueue("nfsd4"); | |
961 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ); | |
962 | + set_max_delegations(); | |
963 | } | |
964 | ||
965 | int | |
966 | diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c | |
967 | index 15809df..be8c614 100644 | |
968 | --- a/fs/nfsd/nfs4xdr.c | |
969 | +++ b/fs/nfsd/nfs4xdr.c | |
970 | @@ -56,6 +56,8 @@ | |
971 | #include <linux/nfsd_idmap.h> | |
972 | #include <linux/nfs4.h> | |
973 | #include <linux/nfs4_acl.h> | |
974 | +#include <linux/sunrpc/gss_api.h> | |
975 | +#include <linux/sunrpc/svcauth_gss.h> | |
976 | ||
977 | #define NFSDDBG_FACILITY NFSDDBG_XDR | |
978 | ||
979 | @@ -819,6 +821,22 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) | |
980 | } | |
981 | ||
982 | static __be32 | |
983 | +nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, struct nfsd4_secinfo *secinfo) | |
984 | +{ | |
985 | + DECODE_HEAD; | |
986 | + | |
987 | + READ_BUF(4); | |
988 | + READ32(secinfo->si_namelen); | |
989 | + READ_BUF(secinfo->si_namelen); | |
990 | + SAVEMEM(secinfo->si_name, secinfo->si_namelen); | |
991 | + status = check_filename(secinfo->si_name, secinfo->si_namelen, | |
992 | + nfserr_noent); | |
993 | + if (status) | |
994 | + return status; | |
995 | + DECODE_TAIL; | |
996 | +} | |
997 | + | |
998 | +static __be32 | |
999 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) | |
1000 | { | |
1001 | DECODE_HEAD; | |
1002 | @@ -1131,6 +1149,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |
1003 | case OP_SAVEFH: | |
1004 | op->status = nfs_ok; | |
1005 | break; | |
1006 | + case OP_SECINFO: | |
1007 | + op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo); | |
1008 | + break; | |
1009 | case OP_SETATTR: | |
1010 | op->status = nfsd4_decode_setattr(argp, &op->u.setattr); | |
1011 | break; | |
1012 | @@ -1296,7 +1317,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * | |
1013 | char *path, *rootpath; | |
1014 | ||
1015 | fh_init(&tmp_fh, NFS4_FHSIZE); | |
1016 | - *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); | |
1017 | + *stat = exp_pseudoroot(rqstp, &tmp_fh); | |
1018 | if (*stat) | |
1019 | return NULL; | |
1020 | rootpath = tmp_fh.fh_export->ex_path; | |
1021 | @@ -1847,11 +1868,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |
1022 | if (d_mountpoint(dentry)) { | |
1023 | int err; | |
1024 | ||
1025 | + /* | |
1026 | + * Why the heck aren't we just using nfsd_lookup?? | |
1027 | + * Different "."/".." handling? Something else? | |
1028 | + * At least, add a comment here to explain.... | |
1029 | + */ | |
1030 | err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); | |
1031 | if (err) { | |
1032 | nfserr = nfserrno(err); | |
1033 | goto out_put; | |
1034 | } | |
1035 | + nfserr = check_nfsd_access(exp, cd->rd_rqstp); | |
1036 | + if (nfserr) | |
1037 | + goto out_put; | |
1038 | ||
1039 | } | |
1040 | nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, | |
1041 | @@ -2419,6 +2448,71 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |
1042 | } | |
1043 | } | |
1044 | ||
1045 | +static void | |
1046 | +nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_secinfo *secinfo) | |
1047 | +{ | |
1048 | + int i = 0; | |
1049 | + struct svc_export *exp = secinfo->si_exp; | |
1050 | + u32 nflavs; | |
1051 | + struct exp_flavor_info *flavs; | |
1052 | + struct exp_flavor_info def_flavs[2]; | |
1053 | + ENCODE_HEAD; | |
1054 | + | |
1055 | + if (nfserr) | |
1056 | + goto out; | |
1057 | + if (exp->ex_nflavors) { | |
1058 | + flavs = exp->ex_flavors; | |
1059 | + nflavs = exp->ex_nflavors; | |
1060 | + } else { /* Handling of some defaults in absence of real secinfo: */ | |
1061 | + flavs = def_flavs; | |
1062 | + if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { | |
1063 | + nflavs = 2; | |
1064 | + flavs[0].pseudoflavor = RPC_AUTH_UNIX; | |
1065 | + flavs[1].pseudoflavor = RPC_AUTH_NULL; | |
1066 | + } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { | |
1067 | + nflavs = 1; | |
1068 | + flavs[0].pseudoflavor | |
1069 | + = svcauth_gss_flavor(exp->ex_client); | |
1070 | + } else { | |
1071 | + nflavs = 1; | |
1072 | + flavs[0].pseudoflavor | |
1073 | + = exp->ex_client->flavour->flavour; | |
1074 | + } | |
1075 | + } | |
1076 | + | |
1077 | + RESERVE_SPACE(4); | |
1078 | + WRITE32(nflavs); | |
1079 | + ADJUST_ARGS(); | |
1080 | + for (i = 0; i < nflavs; i++) { | |
1081 | + u32 flav = flavs[i].pseudoflavor; | |
1082 | + struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); | |
1083 | + | |
1084 | + if (gm) { | |
1085 | + RESERVE_SPACE(4); | |
1086 | + WRITE32(RPC_AUTH_GSS); | |
1087 | + ADJUST_ARGS(); | |
1088 | + RESERVE_SPACE(4 + gm->gm_oid.len); | |
1089 | + WRITE32(gm->gm_oid.len); | |
1090 | + WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); | |
1091 | + ADJUST_ARGS(); | |
1092 | + RESERVE_SPACE(4); | |
1093 | + WRITE32(0); /* qop */ | |
1094 | + ADJUST_ARGS(); | |
1095 | + RESERVE_SPACE(4); | |
1096 | + WRITE32(gss_pseudoflavor_to_service(gm, flav)); | |
1097 | + ADJUST_ARGS(); | |
1098 | + gss_mech_put(gm); | |
1099 | + } else { | |
1100 | + RESERVE_SPACE(4); | |
1101 | + WRITE32(flav); | |
1102 | + ADJUST_ARGS(); | |
1103 | + } | |
1104 | + } | |
1105 | +out: | |
1106 | + if (exp) | |
1107 | + exp_put(exp); | |
1108 | +} | |
1109 | + | |
1110 | /* | |
1111 | * The SETATTR encode routine is special -- it always encodes a bitmap, | |
1112 | * regardless of the error status. | |
1113 | @@ -2559,6 +2653,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |
1114 | break; | |
1115 | case OP_SAVEFH: | |
1116 | break; | |
1117 | + case OP_SECINFO: | |
1118 | + nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo); | |
1119 | + break; | |
1120 | case OP_SETATTR: | |
1121 | nfsd4_encode_setattr(resp, op->status, &op->u.setattr); | |
1122 | break; | |
1123 | diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c | |
1124 | index 71c686d..4f10257 100644 | |
1125 | --- a/fs/nfsd/nfsctl.c | |
1126 | +++ b/fs/nfsd/nfsctl.c | |
1127 | @@ -35,7 +35,6 @@ | |
1128 | #include <linux/nfsd/cache.h> | |
1129 | #include <linux/nfsd/xdr.h> | |
1130 | #include <linux/nfsd/syscall.h> | |
1131 | -#include <linux/nfsd/interface.h> | |
1132 | ||
1133 | #include <asm/uaccess.h> | |
1134 | ||
1135 | diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c | |
1136 | index 6ca2d24..5198573 100644 | |
1137 | --- a/fs/nfsd/nfsfh.c | |
1138 | +++ b/fs/nfsd/nfsfh.c | |
1139 | @@ -19,6 +19,7 @@ | |
1140 | ||
1141 | #include <linux/sunrpc/clnt.h> | |
1142 | #include <linux/sunrpc/svc.h> | |
1143 | +#include <linux/sunrpc/svcauth_gss.h> | |
1144 | #include <linux/nfsd/nfsd.h> | |
1145 | ||
1146 | #define NFSDDBG_FACILITY NFSDDBG_FH | |
1147 | @@ -123,8 +124,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |
1148 | int data_left = fh->fh_size/4; | |
1149 | ||
1150 | error = nfserr_stale; | |
1151 | - if (rqstp->rq_client == NULL) | |
1152 | - goto out; | |
1153 | if (rqstp->rq_vers > 2) | |
1154 | error = nfserr_badhandle; | |
1155 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | |
1156 | @@ -148,7 +147,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |
1157 | fh->fh_fsid[1] = fh->fh_fsid[2]; | |
1158 | } | |
1159 | if ((data_left -= len)<0) goto out; | |
1160 | - exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle); | |
1161 | + exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap); | |
1162 | datap += len; | |
1163 | } else { | |
1164 | dev_t xdev; | |
1165 | @@ -159,19 +158,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |
1166 | xdev = old_decode_dev(fh->ofh_xdev); | |
1167 | xino = u32_to_ino_t(fh->ofh_xino); | |
1168 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | |
1169 | - exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, | |
1170 | - &rqstp->rq_chandle); | |
1171 | + exp = rqst_exp_find(rqstp, FSID_DEV, tfh); | |
1172 | } | |
1173 | ||
1174 | - if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN | |
1175 | - || PTR_ERR(exp) == -ETIMEDOUT)) { | |
1176 | - error = nfserrno(PTR_ERR(exp)); | |
1177 | + error = nfserr_stale; | |
1178 | + if (PTR_ERR(exp) == -ENOENT) | |
1179 | goto out; | |
1180 | - } | |
1181 | ||
1182 | - error = nfserr_stale; | |
1183 | - if (!exp || IS_ERR(exp)) | |
1184 | + if (IS_ERR(exp)) { | |
1185 | + error = nfserrno(PTR_ERR(exp)); | |
1186 | goto out; | |
1187 | + } | |
1188 | ||
1189 | /* Check if the request originated from a secure port. */ | |
1190 | error = nfserr_perm; | |
1191 | @@ -257,8 +254,19 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |
1192 | if (error) | |
1193 | goto out; | |
1194 | ||
1195 | + if (!(access & MAY_LOCK)) { | |
1196 | + /* | |
1197 | + * pseudoflavor restrictions are not enforced on NLM, | |
1198 | + * which clients virtually always use auth_sys for, | |
1199 | + * even while using RPCSEC_GSS for NFS. | |
1200 | + */ | |
1201 | + error = check_nfsd_access(exp, rqstp); | |
1202 | + if (error) | |
1203 | + goto out; | |
1204 | + } | |
1205 | + | |
1206 | /* Finally, check access permissions. */ | |
1207 | - error = nfsd_permission(exp, dentry, access); | |
1208 | + error = nfsd_permission(rqstp, exp, dentry, access); | |
1209 | ||
1210 | if (error) { | |
1211 | dprintk("fh_verify: %s/%s permission failure, " | |
1212 | diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c | |
1213 | index b2c7147..977a71f 100644 | |
1214 | --- a/fs/nfsd/nfsproc.c | |
1215 | +++ b/fs/nfsd/nfsproc.c | |
1216 | @@ -278,7 +278,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |
1217 | * echo thing > device-special-file-or-pipe | |
1218 | * by doing a CREATE with type==0 | |
1219 | */ | |
1220 | - nfserr = nfsd_permission(newfhp->fh_export, | |
1221 | + nfserr = nfsd_permission(rqstp, | |
1222 | + newfhp->fh_export, | |
1223 | newfhp->fh_dentry, | |
1224 | MAY_WRITE|MAY_LOCAL_ACCESS); | |
1225 | if (nfserr && nfserr != nfserr_rofs) | |
1226 | diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c | |
1227 | index ff55950..da33b25 100644 | |
1228 | --- a/fs/nfsd/nfssvc.c | |
1229 | +++ b/fs/nfsd/nfssvc.c | |
1230 | @@ -492,6 +492,15 @@ out: | |
1231 | module_put_and_exit(0); | |
1232 | } | |
1233 | ||
1234 | +static __be32 map_new_errors(u32 vers, __be32 nfserr) | |
1235 | +{ | |
1236 | + if (nfserr == nfserr_jukebox && vers == 2) | |
1237 | + return nfserr_dropit; | |
1238 | + if (nfserr == nfserr_wrongsec && vers < 4) | |
1239 | + return nfserr_acces; | |
1240 | + return nfserr; | |
1241 | +} | |
1242 | + | |
1243 | int | |
1244 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |
1245 | { | |
1246 | @@ -534,6 +543,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |
1247 | ||
1248 | /* Now call the procedure handler, and encode NFS status. */ | |
1249 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | |
1250 | + nfserr = map_new_errors(rqstp->rq_vers, nfserr); | |
1251 | if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) | |
1252 | nfserr = nfserr_dropit; | |
1253 | if (nfserr == nfserr_dropit) { | |
1254 | diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c | |
1255 | index 7e6aa24..8a3f520 100644 | |
1256 | --- a/fs/nfsd/vfs.c | |
1257 | +++ b/fs/nfsd/vfs.c | |
1258 | @@ -113,7 +113,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |
1259 | ||
1260 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); | |
1261 | ||
1262 | - exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); | |
1263 | + exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); | |
1264 | if (IS_ERR(exp2)) { | |
1265 | err = PTR_ERR(exp2); | |
1266 | dput(mounts); | |
1267 | @@ -135,21 +135,10 @@ out: | |
1268 | return err; | |
1269 | } | |
1270 | ||
1271 | -/* | |
1272 | - * Look up one component of a pathname. | |
1273 | - * N.B. After this call _both_ fhp and resfh need an fh_put | |
1274 | - * | |
1275 | - * If the lookup would cross a mountpoint, and the mounted filesystem | |
1276 | - * is exported to the client with NFSEXP_NOHIDE, then the lookup is | |
1277 | - * accepted as it stands and the mounted directory is | |
1278 | - * returned. Otherwise the covered directory is returned. | |
1279 | - * NOTE: this mountpoint crossing is not supported properly by all | |
1280 | - * clients and is explicitly disallowed for NFSv3 | |
1281 | - * NeilBrown <neilb@cse.unsw.edu.au> | |
1282 | - */ | |
1283 | __be32 | |
1284 | -nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1285 | - int len, struct svc_fh *resfh) | |
1286 | +nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
1287 | + const char *name, int len, | |
1288 | + struct svc_export **exp_ret, struct dentry **dentry_ret) | |
1289 | { | |
1290 | struct svc_export *exp; | |
1291 | struct dentry *dparent; | |
1292 | @@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1293 | exp = fhp->fh_export; | |
1294 | exp_get(exp); | |
1295 | ||
1296 | - err = nfserr_acces; | |
1297 | - | |
1298 | /* Lookup the name, but don't follow links */ | |
1299 | if (isdotent(name, len)) { | |
1300 | if (len==1) | |
1301 | @@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1302 | dput(dentry); | |
1303 | dentry = dp; | |
1304 | ||
1305 | - exp2 = exp_parent(exp->ex_client, mnt, dentry, | |
1306 | - &rqstp->rq_chandle); | |
1307 | - if (IS_ERR(exp2)) { | |
1308 | + exp2 = rqst_exp_parent(rqstp, mnt, dentry); | |
1309 | + if (PTR_ERR(exp2) == -ENOENT) { | |
1310 | + dput(dentry); | |
1311 | + dentry = dget(dparent); | |
1312 | + } else if (IS_ERR(exp2)) { | |
1313 | host_err = PTR_ERR(exp2); | |
1314 | dput(dentry); | |
1315 | mntput(mnt); | |
1316 | goto out_nfserr; | |
1317 | - } | |
1318 | - if (!exp2) { | |
1319 | - dput(dentry); | |
1320 | - dentry = dget(dparent); | |
1321 | } else { | |
1322 | exp_put(exp); | |
1323 | exp = exp2; | |
1324 | @@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1325 | } | |
1326 | } | |
1327 | } | |
1328 | + *dentry_ret = dentry; | |
1329 | + *exp_ret = exp; | |
1330 | + return 0; | |
1331 | + | |
1332 | +out_nfserr: | |
1333 | + exp_put(exp); | |
1334 | + return nfserrno(host_err); | |
1335 | +} | |
1336 | + | |
1337 | +/* | |
1338 | + * Look up one component of a pathname. | |
1339 | + * N.B. After this call _both_ fhp and resfh need an fh_put | |
1340 | + * | |
1341 | + * If the lookup would cross a mountpoint, and the mounted filesystem | |
1342 | + * is exported to the client with NFSEXP_NOHIDE, then the lookup is | |
1343 | + * accepted as it stands and the mounted directory is | |
1344 | + * returned. Otherwise the covered directory is returned. | |
1345 | + * NOTE: this mountpoint crossing is not supported properly by all | |
1346 | + * clients and is explicitly disallowed for NFSv3 | |
1347 | + * NeilBrown <neilb@cse.unsw.edu.au> | |
1348 | + */ | |
1349 | +__be32 | |
1350 | +nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1351 | + int len, struct svc_fh *resfh) | |
1352 | +{ | |
1353 | + struct svc_export *exp; | |
1354 | + struct dentry *dentry; | |
1355 | + __be32 err; | |
1356 | + | |
1357 | + err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); | |
1358 | + if (err) | |
1359 | + return err; | |
1360 | + err = check_nfsd_access(exp, rqstp); | |
1361 | + if (err) | |
1362 | + goto out; | |
1363 | /* | |
1364 | * Note: we compose the file handle now, but as the | |
1365 | * dentry may be negative, it may need to be updated. | |
1366 | @@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |
1367 | err = fh_compose(resfh, exp, dentry, fhp); | |
1368 | if (!err && !dentry->d_inode) | |
1369 | err = nfserr_noent; | |
1370 | - dput(dentry); | |
1371 | out: | |
1372 | + dput(dentry); | |
1373 | exp_put(exp); | |
1374 | return err; | |
1375 | - | |
1376 | -out_nfserr: | |
1377 | - err = nfserrno(host_err); | |
1378 | - goto out; | |
1379 | } | |
1380 | ||
1381 | + | |
1382 | /* | |
1383 | * Set various file attributes. | |
1384 | * N.B. After this call fhp needs an fh_put | |
1385 | @@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |
1386 | /* The size case is special. It changes the file as well as the attributes. */ | |
1387 | if (iap->ia_valid & ATTR_SIZE) { | |
1388 | if (iap->ia_size < inode->i_size) { | |
1389 | - err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); | |
1390 | + err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); | |
1391 | if (err) | |
1392 | goto out; | |
1393 | } | |
1394 | @@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
1395 | /* Get inode */ | |
1396 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); | |
1397 | if (error) | |
1398 | - goto out; | |
1399 | + return error; | |
1400 | ||
1401 | dentry = fhp->fh_dentry; | |
1402 | inode = dentry->d_inode; | |
1403 | @@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |
1404 | ||
1405 | host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); | |
1406 | if (host_error == -EINVAL) { | |
1407 | - error = nfserr_attrnotsupp; | |
1408 | - goto out; | |
1409 | + return nfserr_attrnotsupp; | |
1410 | } else if (host_error < 0) | |
1411 | goto out_nfserr; | |
1412 | ||
1413 | host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); | |
1414 | if (host_error < 0) | |
1415 | - goto out_nfserr; | |
1416 | + goto out_release; | |
1417 | ||
1418 | - if (S_ISDIR(inode->i_mode)) { | |
1419 | + if (S_ISDIR(inode->i_mode)) | |
1420 | host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); | |
1421 | - if (host_error < 0) | |
1422 | - goto out_nfserr; | |
1423 | - } | |
1424 | - | |
1425 | - error = nfs_ok; | |
1426 | ||
1427 | -out: | |
1428 | +out_release: | |
1429 | posix_acl_release(pacl); | |
1430 | posix_acl_release(dpacl); | |
1431 | - return (error); | |
1432 | out_nfserr: | |
1433 | if (host_error == -EOPNOTSUPP) | |
1434 | - error = nfserr_attrnotsupp; | |
1435 | + return nfserr_attrnotsupp; | |
1436 | else | |
1437 | - error = nfserrno(host_error); | |
1438 | - goto out; | |
1439 | + return nfserrno(host_error); | |
1440 | } | |
1441 | ||
1442 | static struct posix_acl * | |
1443 | @@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor | |
1444 | ||
1445 | sresult |= map->access; | |
1446 | ||
1447 | - err2 = nfsd_permission(export, dentry, map->how); | |
1448 | + err2 = nfsd_permission(rqstp, export, dentry, map->how); | |
1449 | switch (err2) { | |
1450 | case nfs_ok: | |
1451 | result |= map->access; | |
1452 | @@ -1018,7 +1027,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |
1453 | __be32 err; | |
1454 | ||
1455 | if (file) { | |
1456 | - err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | |
1457 | + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, | |
1458 | MAY_READ|MAY_OWNER_OVERRIDE); | |
1459 | if (err) | |
1460 | goto out; | |
1461 | @@ -1047,7 +1056,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |
1462 | __be32 err = 0; | |
1463 | ||
1464 | if (file) { | |
1465 | - err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | |
1466 | + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, | |
1467 | MAY_WRITE|MAY_OWNER_OVERRIDE); | |
1468 | if (err) | |
1469 | goto out; | |
1470 | @@ -1776,7 +1785,8 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) | |
1471 | * Check for a user's access permissions to this inode. | |
1472 | */ | |
1473 | __be32 | |
1474 | -nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | |
1475 | +nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |
1476 | + struct dentry *dentry, int acc) | |
1477 | { | |
1478 | struct inode *inode = dentry->d_inode; | |
1479 | int err; | |
1480 | @@ -1807,7 +1817,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | |
1481 | */ | |
1482 | if (!(acc & MAY_LOCAL_ACCESS)) | |
1483 | if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { | |
1484 | - if (EX_RDONLY(exp) || IS_RDONLY(inode)) | |
1485 | + if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode)) | |
1486 | return nfserr_rofs; | |
1487 | if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) | |
1488 | return nfserr_perm; | |
1489 | diff --git a/fs/open.c b/fs/open.c | |
1490 | index 0d515d1..c32aba0 100644 | |
1491 | --- a/fs/open.c | |
1492 | +++ b/fs/open.c | |
1493 | @@ -255,24 +255,26 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |
1494 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | |
1495 | goto dput_and_out; | |
1496 | ||
1497 | - /* | |
1498 | - * Make sure that there are no leases. | |
1499 | - */ | |
1500 | - error = break_lease(inode, FMODE_WRITE); | |
1501 | + error = get_write_access(inode); | |
1502 | if (error) | |
1503 | goto dput_and_out; | |
1504 | ||
1505 | - error = get_write_access(inode); | |
1506 | + /* | |
1507 | + * Make sure that there are no leases. get_write_access() protects | |
1508 | + * against the truncate racing with a lease-granting setlease(). | |
1509 | + */ | |
1510 | + error = break_lease(inode, FMODE_WRITE); | |
1511 | if (error) | |
1512 | - goto dput_and_out; | |
1513 | + goto put_write_and_out; | |
1514 | ||
1515 | error = locks_verify_truncate(inode, NULL, length); | |
1516 | if (!error) { | |
1517 | DQUOT_INIT(inode); | |
1518 | error = do_truncate(nd.dentry, length, 0, NULL); | |
1519 | } | |
1520 | - put_write_access(inode); | |
1521 | ||
1522 | +put_write_and_out: | |
1523 | + put_write_access(inode); | |
1524 | dput_and_out: | |
1525 | path_release(&nd); | |
1526 | out: | |
1527 | diff --git a/include/linux/fs.h b/include/linux/fs.h | |
1528 | index b3ae77c..9df3553 100644 | |
1529 | --- a/include/linux/fs.h | |
1530 | +++ b/include/linux/fs.h | |
1531 | @@ -855,7 +855,7 @@ extern void locks_init_lock(struct file_lock *); | |
1532 | extern void locks_copy_lock(struct file_lock *, struct file_lock *); | |
1533 | extern void locks_remove_posix(struct file *, fl_owner_t); | |
1534 | extern void locks_remove_flock(struct file *); | |
1535 | -extern int posix_test_lock(struct file *, struct file_lock *); | |
1536 | +extern void posix_test_lock(struct file *, struct file_lock *); | |
1537 | extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); | |
1538 | extern int posix_lock_file_wait(struct file *, struct file_lock *); | |
1539 | extern int posix_unblock_lock(struct file *, struct file_lock *); | |
1540 | diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h | |
1541 | index 246de1d..df008eb 100644 | |
1542 | --- a/include/linux/lockd/bind.h | |
1543 | +++ b/include/linux/lockd/bind.h | |
1544 | @@ -27,6 +27,7 @@ struct nlmsvc_binding { | |
1545 | struct nfs_fh *, | |
1546 | struct file **); | |
1547 | void (*fclose)(struct file *); | |
1548 | + time_t (*get_grace_period)(void); | |
1549 | }; | |
1550 | ||
1551 | extern struct nlmsvc_binding * nlmsvc_ops; | |
1552 | @@ -38,4 +39,12 @@ extern int nlmclnt_proc(struct inode *, int, struct file_lock *); | |
1553 | extern int lockd_up(int proto); | |
1554 | extern void lockd_down(void); | |
1555 | ||
1556 | +time_t get_nfs_grace_period(void); | |
1557 | + | |
1558 | +#ifdef CONFIG_NFSD_V4 | |
1559 | +time_t get_nfs4_grace_period(void); | |
1560 | +#else | |
1561 | +static inline void get_nfs4_grace_period(void) {return 0;} | |
1562 | +#endif | |
1563 | + | |
1564 | #endif /* LINUX_LOCKD_BIND_H */ | |
1565 | diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h | |
1566 | index 9f62d61..78feb7b 100644 | |
1567 | --- a/include/linux/nfsd/export.h | |
1568 | +++ b/include/linux/nfsd/export.h | |
1569 | @@ -42,6 +42,9 @@ | |
1570 | #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ | |
1571 | #define NFSEXP_ALLFLAGS 0xFE3F | |
1572 | ||
1573 | +/* The flags that may vary depending on security flavor: */ | |
1574 | +#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ | |
1575 | + | NFSEXP_ALLSQUASH) | |
1576 | ||
1577 | #ifdef __KERNEL__ | |
1578 | ||
1579 | @@ -64,6 +67,19 @@ struct nfsd4_fs_locations { | |
1580 | int migrated; | |
1581 | }; | |
1582 | ||
1583 | +/* | |
1584 | + * We keep an array of pseudoflavors with the export, in order from most | |
1585 | + * to least preferred. For the forseeable future, we don't expect more | |
1586 | + * than the eight pseudoflavors null, unix, krb5, krb5i, krb5p, skpm3, | |
1587 | + * spkm3i, and spkm3p (and using all 8 at once should be rare). | |
1588 | + */ | |
1589 | +#define MAX_SECINFO_LIST 8 | |
1590 | + | |
1591 | +struct exp_flavor_info { | |
1592 | + u32 pseudoflavor; | |
1593 | + u32 flags; | |
1594 | +}; | |
1595 | + | |
1596 | struct svc_export { | |
1597 | struct cache_head h; | |
1598 | struct auth_domain * ex_client; | |
1599 | @@ -76,6 +92,8 @@ struct svc_export { | |
1600 | int ex_fsid; | |
1601 | unsigned char * ex_uuid; /* 16 byte fsid */ | |
1602 | struct nfsd4_fs_locations ex_fslocs; | |
1603 | + int ex_nflavors; | |
1604 | + struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST]; | |
1605 | }; | |
1606 | ||
1607 | /* an "export key" (expkey) maps a filehandlefragement to an | |
1608 | @@ -95,10 +113,22 @@ struct svc_expkey { | |
1609 | ||
1610 | #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) | |
1611 | #define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC)) | |
1612 | -#define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY) | |
1613 | #define EX_NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE) | |
1614 | #define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES) | |
1615 | ||
1616 | +static inline int EX_RDONLY(struct svc_export *exp, struct svc_rqst *rqstp) | |
1617 | +{ | |
1618 | + struct exp_flavor_info *f; | |
1619 | + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | |
1620 | + | |
1621 | + for (f = exp->ex_flavors; f < end; f++) { | |
1622 | + if (f->pseudoflavor == rqstp->rq_flavor) | |
1623 | + return f->flags & NFSEXP_READONLY; | |
1624 | + } | |
1625 | + return exp->ex_flags & NFSEXP_READONLY; | |
1626 | +} | |
1627 | + | |
1628 | +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp); | |
1629 | ||
1630 | /* | |
1631 | * Function declarations | |
1632 | @@ -112,13 +142,19 @@ struct svc_export * exp_get_by_name(struct auth_domain *clp, | |
1633 | struct vfsmount *mnt, | |
1634 | struct dentry *dentry, | |
1635 | struct cache_req *reqp); | |
1636 | +struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, | |
1637 | + struct vfsmount *, | |
1638 | + struct dentry *); | |
1639 | struct svc_export * exp_parent(struct auth_domain *clp, | |
1640 | struct vfsmount *mnt, | |
1641 | struct dentry *dentry, | |
1642 | struct cache_req *reqp); | |
1643 | +struct svc_export * rqst_exp_parent(struct svc_rqst *, | |
1644 | + struct vfsmount *mnt, | |
1645 | + struct dentry *dentry); | |
1646 | int exp_rootfh(struct auth_domain *, | |
1647 | char *path, struct knfsd_fh *, int maxsize); | |
1648 | -__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq); | |
1649 | +__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); | |
1650 | __be32 nfserrno(int errno); | |
1651 | ||
1652 | extern struct cache_detail svc_export_cache; | |
1653 | @@ -135,6 +171,7 @@ static inline void exp_get(struct svc_export *exp) | |
1654 | extern struct svc_export * | |
1655 | exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | |
1656 | struct cache_req *reqp); | |
1657 | +struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *); | |
1658 | ||
1659 | #endif /* __KERNEL__ */ | |
1660 | ||
1661 | diff --git a/include/linux/nfsd/interface.h b/include/linux/nfsd/interface.h | |
1662 | deleted file mode 100644 | |
1663 | index af09797..0000000 | |
1664 | --- a/include/linux/nfsd/interface.h | |
1665 | +++ /dev/null | |
1666 | @@ -1,13 +0,0 @@ | |
1667 | -/* | |
1668 | - * include/linux/nfsd/interface.h | |
1669 | - * | |
1670 | - * defines interface between nfsd and other bits of | |
1671 | - * the kernel. Particularly filesystems (eventually). | |
1672 | - * | |
1673 | - * Copyright (C) 2000 Neil Brown <neilb@cse.unsw.edu.au> | |
1674 | - */ | |
1675 | - | |
1676 | -#ifndef LINUX_NFSD_INTERFACE_H | |
1677 | -#define LINUX_NFSD_INTERFACE_H | |
1678 | - | |
1679 | -#endif /* LINUX_NFSD_INTERFACE_H */ | |
1680 | diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h | |
1681 | index 72feac5..e452256 100644 | |
1682 | --- a/include/linux/nfsd/nfsd.h | |
1683 | +++ b/include/linux/nfsd/nfsd.h | |
1684 | @@ -22,7 +22,6 @@ | |
1685 | #include <linux/nfsd/export.h> | |
1686 | #include <linux/nfsd/auth.h> | |
1687 | #include <linux/nfsd/stats.h> | |
1688 | -#include <linux/nfsd/interface.h> | |
1689 | /* | |
1690 | * nfsd version | |
1691 | */ | |
1692 | @@ -72,6 +71,9 @@ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |
1693 | struct svc_export **expp); | |
1694 | __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, | |
1695 | const char *, int, struct svc_fh *); | |
1696 | +__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *, | |
1697 | + const char *, int, | |
1698 | + struct svc_export **, struct dentry **); | |
1699 | __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, | |
1700 | struct iattr *, int, time_t); | |
1701 | #ifdef CONFIG_NFSD_V4 | |
1702 | @@ -120,7 +122,8 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, | |
1703 | struct kstatfs *); | |
1704 | ||
1705 | int nfsd_notify_change(struct inode *, struct iattr *); | |
1706 | -__be32 nfsd_permission(struct svc_export *, struct dentry *, int); | |
1707 | +__be32 nfsd_permission(struct svc_rqst *, struct svc_export *, | |
1708 | + struct dentry *, int); | |
1709 | int nfsd_sync_dir(struct dentry *dp); | |
1710 | ||
1711 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | |
1712 | @@ -149,6 +152,7 @@ extern int nfsd_max_blksize; | |
1713 | * NFSv4 State | |
1714 | */ | |
1715 | #ifdef CONFIG_NFSD_V4 | |
1716 | +extern unsigned int max_delegations; | |
1717 | void nfs4_state_init(void); | |
1718 | int nfs4_state_start(void); | |
1719 | void nfs4_state_shutdown(void); | |
1720 | @@ -236,6 +240,7 @@ void nfsd_lockd_shutdown(void); | |
1721 | #define nfserr_badname __constant_htonl(NFSERR_BADNAME) | |
1722 | #define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN) | |
1723 | #define nfserr_locked __constant_htonl(NFSERR_LOCKED) | |
1724 | +#define nfserr_wrongsec __constant_htonl(NFSERR_WRONGSEC) | |
1725 | #define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME) | |
1726 | ||
1727 | /* error codes for internal use */ | |
1728 | diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h | |
1729 | index ab5c236..db348f7 100644 | |
1730 | --- a/include/linux/nfsd/state.h | |
1731 | +++ b/include/linux/nfsd/state.h | |
1732 | @@ -67,7 +67,7 @@ struct nfs4_cb_recall { | |
1733 | int cbr_trunc; | |
1734 | stateid_t cbr_stateid; | |
1735 | u32 cbr_fhlen; | |
1736 | - u32 cbr_fhval[NFS4_FHSIZE]; | |
1737 | + char cbr_fhval[NFS4_FHSIZE]; | |
1738 | struct nfs4_delegation *cbr_dp; | |
1739 | }; | |
1740 | ||
1741 | @@ -224,6 +224,7 @@ struct nfs4_file { | |
1742 | struct inode *fi_inode; | |
1743 | u32 fi_id; /* used with stateowner->so_id | |
1744 | * for stateid_hashtbl hash */ | |
1745 | + bool fi_had_conflict; | |
1746 | }; | |
1747 | ||
1748 | /* | |
1749 | diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h | |
1750 | index 09799bc..1b65326 100644 | |
1751 | --- a/include/linux/nfsd/xdr4.h | |
1752 | +++ b/include/linux/nfsd/xdr4.h | |
1753 | @@ -293,6 +293,12 @@ struct nfsd4_rename { | |
1754 | struct nfsd4_change_info rn_tinfo; /* response */ | |
1755 | }; | |
1756 | ||
1757 | +struct nfsd4_secinfo { | |
1758 | + u32 si_namelen; /* request */ | |
1759 | + char *si_name; /* request */ | |
1760 | + struct svc_export *si_exp; /* response */ | |
1761 | +}; | |
1762 | + | |
1763 | struct nfsd4_setattr { | |
1764 | stateid_t sa_stateid; /* request */ | |
1765 | u32 sa_bmval[2]; /* request */ | |
1766 | @@ -365,6 +371,7 @@ struct nfsd4_op { | |
1767 | struct nfsd4_remove remove; | |
1768 | struct nfsd4_rename rename; | |
1769 | clientid_t renew; | |
1770 | + struct nfsd4_secinfo secinfo; | |
1771 | struct nfsd4_setattr setattr; | |
1772 | struct nfsd4_setclientid setclientid; | |
1773 | struct nfsd4_setclientid_confirm setclientid_confirm; | |
1774 | diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h | |
1775 | index 5eca9e4..f76f705 100644 | |
1776 | --- a/include/linux/sunrpc/gss_api.h | |
1777 | +++ b/include/linux/sunrpc/gss_api.h | |
1778 | @@ -58,6 +58,7 @@ u32 gss_unwrap( | |
1779 | u32 gss_delete_sec_context( | |
1780 | struct gss_ctx **ctx_id); | |
1781 | ||
1782 | +u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service); | |
1783 | u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); | |
1784 | char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); | |
1785 | ||
1786 | diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h | |
1787 | index 4a7ae8a..211f8da 100644 | |
1788 | --- a/include/linux/sunrpc/svc.h | |
1789 | +++ b/include/linux/sunrpc/svc.h | |
1790 | @@ -212,6 +212,7 @@ struct svc_rqst { | |
1791 | struct svc_pool * rq_pool; /* thread pool */ | |
1792 | struct svc_procedure * rq_procinfo; /* procedure info */ | |
1793 | struct auth_ops * rq_authop; /* authentication flavour */ | |
1794 | + u32 rq_flavor; /* pseudoflavor */ | |
1795 | struct svc_cred rq_cred; /* auth info */ | |
1796 | struct sk_buff * rq_skbuff; /* fast recv inet buffer */ | |
1797 | struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */ | |
1798 | @@ -248,6 +249,7 @@ struct svc_rqst { | |
1799 | */ | |
1800 | /* Catering to nfsd */ | |
1801 | struct auth_domain * rq_client; /* RPC peer info */ | |
1802 | + struct auth_domain * rq_gssclient; /* "gss/"-style peer info */ | |
1803 | struct svc_cacherep * rq_cacherep; /* cache info */ | |
1804 | struct knfsd_fh * rq_reffh; /* Referrence filehandle, used to | |
1805 | * determine what device number | |
1806 | diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h | |
1807 | index de92619..22e1ef8 100644 | |
1808 | --- a/include/linux/sunrpc/svcauth.h | |
1809 | +++ b/include/linux/sunrpc/svcauth.h | |
1810 | @@ -127,6 +127,7 @@ extern struct auth_domain *auth_unix_lookup(struct in_addr addr); | |
1811 | extern int auth_unix_forget_old(struct auth_domain *dom); | |
1812 | extern void svcauth_unix_purge(void); | |
1813 | extern void svcauth_unix_info_release(void *); | |
1814 | +extern int svcauth_unix_set_client(struct svc_rqst *rqstp); | |
1815 | ||
1816 | static inline unsigned long hash_str(char *name, int bits) | |
1817 | { | |
1818 | diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h | |
1819 | index 5a5db16..442b061 100644 | |
1820 | --- a/include/linux/sunrpc/svcauth_gss.h | |
1821 | +++ b/include/linux/sunrpc/svcauth_gss.h | |
1822 | @@ -22,6 +22,8 @@ | |
1823 | int gss_svc_init(void); | |
1824 | void gss_svc_shutdown(void); | |
1825 | int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name); | |
1826 | +u32 svcauth_gss_flavor(struct auth_domain *dom); | |
1827 | + | |
1828 | ||
1829 | #endif /* __KERNEL__ */ | |
1830 | #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */ | |
1831 | diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c | |
1832 | index 7b19432..03e0b8b 100644 | |
1833 | --- a/net/sunrpc/auth_gss/gss_krb5_mech.c | |
1834 | +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |
1835 | @@ -231,6 +231,7 @@ static struct pf_desc gss_kerberos_pfs[] = { | |
1836 | static struct gss_api_mech gss_kerberos_mech = { | |
1837 | .gm_name = "krb5", | |
1838 | .gm_owner = THIS_MODULE, | |
1839 | + .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}, | |
1840 | .gm_ops = &gss_kerberos_ops, | |
1841 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | |
1842 | .gm_pfs = gss_kerberos_pfs, | |
1843 | diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c | |
1844 | index 2687251..5c4e983 100644 | |
1845 | --- a/net/sunrpc/auth_gss/gss_mech_switch.c | |
1846 | +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |
1847 | @@ -194,6 +194,21 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |
1848 | EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor); | |
1849 | ||
1850 | u32 | |
1851 | +gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | |
1852 | +{ | |
1853 | + int i; | |
1854 | + | |
1855 | + for (i = 0; i < gm->gm_pf_num; i++) { | |
1856 | + if (gm->gm_pfs[i].service == service) { | |
1857 | + return gm->gm_pfs[i].pseudoflavor; | |
1858 | + } | |
1859 | + } | |
1860 | + return RPC_AUTH_MAXFLAVOR; /* illegal value */ | |
1861 | +} | |
1862 | + | |
1863 | +EXPORT_SYMBOL(gss_svc_to_pseudoflavor); | |
1864 | + | |
1865 | +u32 | |
1866 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | |
1867 | { | |
1868 | int i; | |
1869 | diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
1870 | index 7e15aa6..9331119 100644 | |
1871 | --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
1872 | +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c | |
1873 | @@ -217,6 +217,7 @@ static struct pf_desc gss_spkm3_pfs[] = { | |
1874 | static struct gss_api_mech gss_spkm3_mech = { | |
1875 | .gm_name = "spkm3", | |
1876 | .gm_owner = THIS_MODULE, | |
1877 | + .gm_oid = {7, "\053\006\001\005\005\001\003"}, | |
1878 | .gm_ops = &gss_spkm3_ops, | |
1879 | .gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs), | |
1880 | .gm_pfs = gss_spkm3_pfs, | |
1881 | diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c | |
1882 | index 099a983..34d6763 100644 | |
1883 | --- a/net/sunrpc/auth_gss/svcauth_gss.c | |
1884 | +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |
1885 | @@ -743,6 +743,15 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc) | |
1886 | ||
1887 | static struct auth_ops svcauthops_gss; | |
1888 | ||
1889 | +u32 svcauth_gss_flavor(struct auth_domain *dom) | |
1890 | +{ | |
1891 | + struct gss_domain *gd = container_of(dom, struct gss_domain, h); | |
1892 | + | |
1893 | + return gd->pseudoflavor; | |
1894 | +} | |
1895 | + | |
1896 | +EXPORT_SYMBOL(svcauth_gss_flavor); | |
1897 | + | |
1898 | int | |
1899 | svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name) | |
1900 | { | |
1901 | @@ -913,10 +922,23 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) | |
1902 | struct gss_svc_data *svcdata = rqstp->rq_auth_data; | |
1903 | struct rsc *rsci = svcdata->rsci; | |
1904 | struct rpc_gss_wire_cred *gc = &svcdata->clcred; | |
1905 | + int stat; | |
1906 | ||
1907 | - rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc); | |
1908 | - if (rqstp->rq_client == NULL) | |
1909 | + /* | |
1910 | + * A gss export can be specified either by: | |
1911 | + * export *(sec=krb5,rw) | |
1912 | + * or by | |
1913 | + * export gss/krb5(rw) | |
1914 | + * The latter is deprecated; but for backwards compatibility reasons | |
1915 | + * the nfsd code will still fall back on trying it if the former | |
1916 | + * doesn't work; so we try to make both available to nfsd, below. | |
1917 | + */ | |
1918 | + rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc); | |
1919 | + if (rqstp->rq_gssclient == NULL) | |
1920 | return SVC_DENIED; | |
1921 | + stat = svcauth_unix_set_client(rqstp); | |
1922 | + if (stat == SVC_DROP) | |
1923 | + return stat; | |
1924 | return SVC_OK; | |
1925 | } | |
1926 | ||
1927 | @@ -1088,7 +1110,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |
1928 | svc_putnl(resv, GSS_SEQ_WIN); | |
1929 | if (svc_safe_putnetobj(resv, &rsip->out_token)) | |
1930 | goto drop; | |
1931 | - rqstp->rq_client = NULL; | |
1932 | } | |
1933 | goto complete; | |
1934 | case RPC_GSS_PROC_DESTROY: | |
1935 | @@ -1131,6 +1152,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |
1936 | } | |
1937 | svcdata->rsci = rsci; | |
1938 | cache_get(&rsci->h); | |
1939 | + rqstp->rq_flavor = gss_svc_to_pseudoflavor( | |
1940 | + rsci->mechctx->mech_type, gc->gc_svc); | |
1941 | ret = SVC_OK; | |
1942 | goto out; | |
1943 | } | |
1944 | @@ -1317,6 +1340,9 @@ out_err: | |
1945 | if (rqstp->rq_client) | |
1946 | auth_domain_put(rqstp->rq_client); | |
1947 | rqstp->rq_client = NULL; | |
1948 | + if (rqstp->rq_gssclient) | |
1949 | + auth_domain_put(rqstp->rq_gssclient); | |
1950 | + rqstp->rq_gssclient = NULL; | |
1951 | if (rqstp->rq_cred.cr_group_info) | |
1952 | put_group_info(rqstp->rq_cred.cr_group_info); | |
1953 | rqstp->rq_cred.cr_group_info = NULL; | |
1954 | diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c | |
1955 | index 07dcd20..4114794 100644 | |
1956 | --- a/net/sunrpc/svcauth_unix.c | |
1957 | +++ b/net/sunrpc/svcauth_unix.c | |
1958 | @@ -5,6 +5,7 @@ | |
1959 | #include <linux/sunrpc/xdr.h> | |
1960 | #include <linux/sunrpc/svcsock.h> | |
1961 | #include <linux/sunrpc/svcauth.h> | |
1962 | +#include <linux/sunrpc/gss_api.h> | |
1963 | #include <linux/err.h> | |
1964 | #include <linux/seq_file.h> | |
1965 | #include <linux/hash.h> | |
1966 | @@ -637,7 +638,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip, | |
1967 | } | |
1968 | } | |
1969 | ||
1970 | -static int | |
1971 | +int | |
1972 | svcauth_unix_set_client(struct svc_rqst *rqstp) | |
1973 | { | |
1974 | struct sockaddr_in *sin = svc_addr_in(rqstp); | |
1975 | @@ -672,6 +673,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) | |
1976 | return SVC_OK; | |
1977 | } | |
1978 | ||
1979 | +EXPORT_SYMBOL(svcauth_unix_set_client); | |
1980 | + | |
1981 | static int | |
1982 | svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |
1983 | { | |
1984 | @@ -707,6 +710,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) | |
1985 | svc_putnl(resv, RPC_AUTH_NULL); | |
1986 | svc_putnl(resv, 0); | |
1987 | ||
1988 | + rqstp->rq_flavor = RPC_AUTH_NULL; | |
1989 | return SVC_OK; | |
1990 | } | |
1991 | ||
1992 | @@ -784,6 +788,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |
1993 | svc_putnl(resv, RPC_AUTH_NULL); | |
1994 | svc_putnl(resv, 0); | |
1995 | ||
1996 | + rqstp->rq_flavor = RPC_AUTH_UNIX; | |
1997 | return SVC_OK; | |
1998 | ||
1999 | badcred: |