diff options
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 349 |
1 files changed, 226 insertions, 123 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 4e4ccc5b6fea..baf4096d52d4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -54,9 +54,10 @@ | |||
54 | #include <linux/sunrpc/gss_api.h> | 54 | #include <linux/sunrpc/gss_api.h> |
55 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
56 | 56 | ||
57 | static struct rpc_authops authgss_ops; | 57 | static const struct rpc_authops authgss_ops; |
58 | 58 | ||
59 | static struct rpc_credops gss_credops; | 59 | static const struct rpc_credops gss_credops; |
60 | static const struct rpc_credops gss_nullops; | ||
60 | 61 | ||
61 | #ifdef RPC_DEBUG | 62 | #ifdef RPC_DEBUG |
62 | # define RPCDBG_FACILITY RPCDBG_AUTH | 63 | # define RPCDBG_FACILITY RPCDBG_AUTH |
@@ -64,7 +65,6 @@ static struct rpc_credops gss_credops; | |||
64 | 65 | ||
65 | #define NFS_NGROUPS 16 | 66 | #define NFS_NGROUPS 16 |
66 | 67 | ||
67 | #define GSS_CRED_EXPIRE (60 * HZ) /* XXX: reasonable? */ | ||
68 | #define GSS_CRED_SLACK 1024 /* XXX: unused */ | 68 | #define GSS_CRED_SLACK 1024 /* XXX: unused */ |
69 | /* length of a krb5 verifier (48), plus data added before arguments when | 69 | /* length of a krb5 verifier (48), plus data added before arguments when |
70 | * using integrity (two 4-byte integers): */ | 70 | * using integrity (two 4-byte integers): */ |
@@ -79,19 +79,16 @@ static struct rpc_credops gss_credops; | |||
79 | /* dump the buffer in `emacs-hexl' style */ | 79 | /* dump the buffer in `emacs-hexl' style */ |
80 | #define isprint(c) ((c > 0x1f) && (c < 0x7f)) | 80 | #define isprint(c) ((c > 0x1f) && (c < 0x7f)) |
81 | 81 | ||
82 | static DEFINE_RWLOCK(gss_ctx_lock); | ||
83 | |||
84 | struct gss_auth { | 82 | struct gss_auth { |
83 | struct kref kref; | ||
85 | struct rpc_auth rpc_auth; | 84 | struct rpc_auth rpc_auth; |
86 | struct gss_api_mech *mech; | 85 | struct gss_api_mech *mech; |
87 | enum rpc_gss_svc service; | 86 | enum rpc_gss_svc service; |
88 | struct list_head upcalls; | ||
89 | struct rpc_clnt *client; | 87 | struct rpc_clnt *client; |
90 | struct dentry *dentry; | 88 | struct dentry *dentry; |
91 | spinlock_t lock; | ||
92 | }; | 89 | }; |
93 | 90 | ||
94 | static void gss_destroy_ctx(struct gss_cl_ctx *); | 91 | static void gss_free_ctx(struct gss_cl_ctx *); |
95 | static struct rpc_pipe_ops gss_upcall_ops; | 92 | static struct rpc_pipe_ops gss_upcall_ops; |
96 | 93 | ||
97 | static inline struct gss_cl_ctx * | 94 | static inline struct gss_cl_ctx * |
@@ -105,20 +102,24 @@ static inline void | |||
105 | gss_put_ctx(struct gss_cl_ctx *ctx) | 102 | gss_put_ctx(struct gss_cl_ctx *ctx) |
106 | { | 103 | { |
107 | if (atomic_dec_and_test(&ctx->count)) | 104 | if (atomic_dec_and_test(&ctx->count)) |
108 | gss_destroy_ctx(ctx); | 105 | gss_free_ctx(ctx); |
109 | } | 106 | } |
110 | 107 | ||
108 | /* gss_cred_set_ctx: | ||
109 | * called by gss_upcall_callback and gss_create_upcall in order | ||
110 | * to set the gss context. The actual exchange of an old context | ||
111 | * and a new one is protected by the inode->i_lock. | ||
112 | */ | ||
111 | static void | 113 | static void |
112 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) | 114 | gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx) |
113 | { | 115 | { |
114 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 116 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
115 | struct gss_cl_ctx *old; | 117 | struct gss_cl_ctx *old; |
116 | write_lock(&gss_ctx_lock); | 118 | |
117 | old = gss_cred->gc_ctx; | 119 | old = gss_cred->gc_ctx; |
118 | gss_cred->gc_ctx = ctx; | 120 | rcu_assign_pointer(gss_cred->gc_ctx, ctx); |
119 | cred->cr_flags |= RPCAUTH_CRED_UPTODATE; | 121 | set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
120 | cred->cr_flags &= ~RPCAUTH_CRED_NEW; | 122 | clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags); |
121 | write_unlock(&gss_ctx_lock); | ||
122 | if (old) | 123 | if (old) |
123 | gss_put_ctx(old); | 124 | gss_put_ctx(old); |
124 | } | 125 | } |
@@ -129,10 +130,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred) | |||
129 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 130 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
130 | int res = 0; | 131 | int res = 0; |
131 | 132 | ||
132 | read_lock(&gss_ctx_lock); | 133 | rcu_read_lock(); |
133 | if ((cred->cr_flags & RPCAUTH_CRED_UPTODATE) && gss_cred->gc_ctx) | 134 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx) |
134 | res = 1; | 135 | res = 1; |
135 | read_unlock(&gss_ctx_lock); | 136 | rcu_read_unlock(); |
136 | return res; | 137 | return res; |
137 | } | 138 | } |
138 | 139 | ||
@@ -171,10 +172,10 @@ gss_cred_get_ctx(struct rpc_cred *cred) | |||
171 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 172 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
172 | struct gss_cl_ctx *ctx = NULL; | 173 | struct gss_cl_ctx *ctx = NULL; |
173 | 174 | ||
174 | read_lock(&gss_ctx_lock); | 175 | rcu_read_lock(); |
175 | if (gss_cred->gc_ctx) | 176 | if (gss_cred->gc_ctx) |
176 | ctx = gss_get_ctx(gss_cred->gc_ctx); | 177 | ctx = gss_get_ctx(gss_cred->gc_ctx); |
177 | read_unlock(&gss_ctx_lock); | 178 | rcu_read_unlock(); |
178 | return ctx; | 179 | return ctx; |
179 | } | 180 | } |
180 | 181 | ||
@@ -269,10 +270,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) | |||
269 | } | 270 | } |
270 | 271 | ||
271 | static struct gss_upcall_msg * | 272 | static struct gss_upcall_msg * |
272 | __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) | 273 | __gss_find_upcall(struct rpc_inode *rpci, uid_t uid) |
273 | { | 274 | { |
274 | struct gss_upcall_msg *pos; | 275 | struct gss_upcall_msg *pos; |
275 | list_for_each_entry(pos, &gss_auth->upcalls, list) { | 276 | list_for_each_entry(pos, &rpci->in_downcall, list) { |
276 | if (pos->uid != uid) | 277 | if (pos->uid != uid) |
277 | continue; | 278 | continue; |
278 | atomic_inc(&pos->count); | 279 | atomic_inc(&pos->count); |
@@ -290,24 +291,24 @@ __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid) | |||
290 | static inline struct gss_upcall_msg * | 291 | static inline struct gss_upcall_msg * |
291 | gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) | 292 | gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg) |
292 | { | 293 | { |
294 | struct inode *inode = gss_auth->dentry->d_inode; | ||
295 | struct rpc_inode *rpci = RPC_I(inode); | ||
293 | struct gss_upcall_msg *old; | 296 | struct gss_upcall_msg *old; |
294 | 297 | ||
295 | spin_lock(&gss_auth->lock); | 298 | spin_lock(&inode->i_lock); |
296 | old = __gss_find_upcall(gss_auth, gss_msg->uid); | 299 | old = __gss_find_upcall(rpci, gss_msg->uid); |
297 | if (old == NULL) { | 300 | if (old == NULL) { |
298 | atomic_inc(&gss_msg->count); | 301 | atomic_inc(&gss_msg->count); |
299 | list_add(&gss_msg->list, &gss_auth->upcalls); | 302 | list_add(&gss_msg->list, &rpci->in_downcall); |
300 | } else | 303 | } else |
301 | gss_msg = old; | 304 | gss_msg = old; |
302 | spin_unlock(&gss_auth->lock); | 305 | spin_unlock(&inode->i_lock); |
303 | return gss_msg; | 306 | return gss_msg; |
304 | } | 307 | } |
305 | 308 | ||
306 | static void | 309 | static void |
307 | __gss_unhash_msg(struct gss_upcall_msg *gss_msg) | 310 | __gss_unhash_msg(struct gss_upcall_msg *gss_msg) |
308 | { | 311 | { |
309 | if (list_empty(&gss_msg->list)) | ||
310 | return; | ||
311 | list_del_init(&gss_msg->list); | 312 | list_del_init(&gss_msg->list); |
312 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | 313 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); |
313 | wake_up_all(&gss_msg->waitqueue); | 314 | wake_up_all(&gss_msg->waitqueue); |
@@ -318,10 +319,14 @@ static void | |||
318 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) | 319 | gss_unhash_msg(struct gss_upcall_msg *gss_msg) |
319 | { | 320 | { |
320 | struct gss_auth *gss_auth = gss_msg->auth; | 321 | struct gss_auth *gss_auth = gss_msg->auth; |
322 | struct inode *inode = gss_auth->dentry->d_inode; | ||
321 | 323 | ||
322 | spin_lock(&gss_auth->lock); | 324 | if (list_empty(&gss_msg->list)) |
323 | __gss_unhash_msg(gss_msg); | 325 | return; |
324 | spin_unlock(&gss_auth->lock); | 326 | spin_lock(&inode->i_lock); |
327 | if (!list_empty(&gss_msg->list)) | ||
328 | __gss_unhash_msg(gss_msg); | ||
329 | spin_unlock(&inode->i_lock); | ||
325 | } | 330 | } |
326 | 331 | ||
327 | static void | 332 | static void |
@@ -330,16 +335,16 @@ gss_upcall_callback(struct rpc_task *task) | |||
330 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, | 335 | struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, |
331 | struct gss_cred, gc_base); | 336 | struct gss_cred, gc_base); |
332 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; | 337 | struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall; |
338 | struct inode *inode = gss_msg->auth->dentry->d_inode; | ||
333 | 339 | ||
334 | BUG_ON(gss_msg == NULL); | 340 | spin_lock(&inode->i_lock); |
335 | if (gss_msg->ctx) | 341 | if (gss_msg->ctx) |
336 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); | 342 | gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx)); |
337 | else | 343 | else |
338 | task->tk_status = gss_msg->msg.errno; | 344 | task->tk_status = gss_msg->msg.errno; |
339 | spin_lock(&gss_msg->auth->lock); | ||
340 | gss_cred->gc_upcall = NULL; | 345 | gss_cred->gc_upcall = NULL; |
341 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); | 346 | rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno); |
342 | spin_unlock(&gss_msg->auth->lock); | 347 | spin_unlock(&inode->i_lock); |
343 | gss_release_msg(gss_msg); | 348 | gss_release_msg(gss_msg); |
344 | } | 349 | } |
345 | 350 | ||
@@ -386,11 +391,12 @@ static inline int | |||
386 | gss_refresh_upcall(struct rpc_task *task) | 391 | gss_refresh_upcall(struct rpc_task *task) |
387 | { | 392 | { |
388 | struct rpc_cred *cred = task->tk_msg.rpc_cred; | 393 | struct rpc_cred *cred = task->tk_msg.rpc_cred; |
389 | struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth, | 394 | struct gss_auth *gss_auth = container_of(cred->cr_auth, |
390 | struct gss_auth, rpc_auth); | 395 | struct gss_auth, rpc_auth); |
391 | struct gss_cred *gss_cred = container_of(cred, | 396 | struct gss_cred *gss_cred = container_of(cred, |
392 | struct gss_cred, gc_base); | 397 | struct gss_cred, gc_base); |
393 | struct gss_upcall_msg *gss_msg; | 398 | struct gss_upcall_msg *gss_msg; |
399 | struct inode *inode = gss_auth->dentry->d_inode; | ||
394 | int err = 0; | 400 | int err = 0; |
395 | 401 | ||
396 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, | 402 | dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid, |
@@ -400,7 +406,7 @@ gss_refresh_upcall(struct rpc_task *task) | |||
400 | err = PTR_ERR(gss_msg); | 406 | err = PTR_ERR(gss_msg); |
401 | goto out; | 407 | goto out; |
402 | } | 408 | } |
403 | spin_lock(&gss_auth->lock); | 409 | spin_lock(&inode->i_lock); |
404 | if (gss_cred->gc_upcall != NULL) | 410 | if (gss_cred->gc_upcall != NULL) |
405 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); | 411 | rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); |
406 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { | 412 | else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { |
@@ -411,7 +417,7 @@ gss_refresh_upcall(struct rpc_task *task) | |||
411 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); | 417 | rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); |
412 | } else | 418 | } else |
413 | err = gss_msg->msg.errno; | 419 | err = gss_msg->msg.errno; |
414 | spin_unlock(&gss_auth->lock); | 420 | spin_unlock(&inode->i_lock); |
415 | gss_release_msg(gss_msg); | 421 | gss_release_msg(gss_msg); |
416 | out: | 422 | out: |
417 | dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", | 423 | dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n", |
@@ -422,6 +428,7 @@ out: | |||
422 | static inline int | 428 | static inline int |
423 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 429 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
424 | { | 430 | { |
431 | struct inode *inode = gss_auth->dentry->d_inode; | ||
425 | struct rpc_cred *cred = &gss_cred->gc_base; | 432 | struct rpc_cred *cred = &gss_cred->gc_base; |
426 | struct gss_upcall_msg *gss_msg; | 433 | struct gss_upcall_msg *gss_msg; |
427 | DEFINE_WAIT(wait); | 434 | DEFINE_WAIT(wait); |
@@ -435,12 +442,11 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
435 | } | 442 | } |
436 | for (;;) { | 443 | for (;;) { |
437 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); | 444 | prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); |
438 | spin_lock(&gss_auth->lock); | 445 | spin_lock(&inode->i_lock); |
439 | if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { | 446 | if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { |
440 | spin_unlock(&gss_auth->lock); | ||
441 | break; | 447 | break; |
442 | } | 448 | } |
443 | spin_unlock(&gss_auth->lock); | 449 | spin_unlock(&inode->i_lock); |
444 | if (signalled()) { | 450 | if (signalled()) { |
445 | err = -ERESTARTSYS; | 451 | err = -ERESTARTSYS; |
446 | goto out_intr; | 452 | goto out_intr; |
@@ -451,6 +457,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | |||
451 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); | 457 | gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); |
452 | else | 458 | else |
453 | err = gss_msg->msg.errno; | 459 | err = gss_msg->msg.errno; |
460 | spin_unlock(&inode->i_lock); | ||
454 | out_intr: | 461 | out_intr: |
455 | finish_wait(&gss_msg->waitqueue, &wait); | 462 | finish_wait(&gss_msg->waitqueue, &wait); |
456 | gss_release_msg(gss_msg); | 463 | gss_release_msg(gss_msg); |
@@ -489,12 +496,11 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
489 | const void *p, *end; | 496 | const void *p, *end; |
490 | void *buf; | 497 | void *buf; |
491 | struct rpc_clnt *clnt; | 498 | struct rpc_clnt *clnt; |
492 | struct gss_auth *gss_auth; | ||
493 | struct rpc_cred *cred; | ||
494 | struct gss_upcall_msg *gss_msg; | 499 | struct gss_upcall_msg *gss_msg; |
500 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
495 | struct gss_cl_ctx *ctx; | 501 | struct gss_cl_ctx *ctx; |
496 | uid_t uid; | 502 | uid_t uid; |
497 | int err = -EFBIG; | 503 | ssize_t err = -EFBIG; |
498 | 504 | ||
499 | if (mlen > MSG_BUF_MAXSIZE) | 505 | if (mlen > MSG_BUF_MAXSIZE) |
500 | goto out; | 506 | goto out; |
@@ -503,7 +509,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
503 | if (!buf) | 509 | if (!buf) |
504 | goto out; | 510 | goto out; |
505 | 511 | ||
506 | clnt = RPC_I(filp->f_path.dentry->d_inode)->private; | 512 | clnt = RPC_I(inode)->private; |
507 | err = -EFAULT; | 513 | err = -EFAULT; |
508 | if (copy_from_user(buf, src, mlen)) | 514 | if (copy_from_user(buf, src, mlen)) |
509 | goto err; | 515 | goto err; |
@@ -519,43 +525,38 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) | |||
519 | ctx = gss_alloc_context(); | 525 | ctx = gss_alloc_context(); |
520 | if (ctx == NULL) | 526 | if (ctx == NULL) |
521 | goto err; | 527 | goto err; |
522 | err = 0; | 528 | |
523 | gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth); | 529 | err = -ENOENT; |
524 | p = gss_fill_context(p, end, ctx, gss_auth->mech); | 530 | /* Find a matching upcall */ |
531 | spin_lock(&inode->i_lock); | ||
532 | gss_msg = __gss_find_upcall(RPC_I(inode), uid); | ||
533 | if (gss_msg == NULL) { | ||
534 | spin_unlock(&inode->i_lock); | ||
535 | goto err_put_ctx; | ||
536 | } | ||
537 | list_del_init(&gss_msg->list); | ||
538 | spin_unlock(&inode->i_lock); | ||
539 | |||
540 | p = gss_fill_context(p, end, ctx, gss_msg->auth->mech); | ||
525 | if (IS_ERR(p)) { | 541 | if (IS_ERR(p)) { |
526 | err = PTR_ERR(p); | 542 | err = PTR_ERR(p); |
527 | if (err != -EACCES) | 543 | gss_msg->msg.errno = (err == -EACCES) ? -EACCES : -EAGAIN; |
528 | goto err_put_ctx; | 544 | goto err_release_msg; |
529 | } | ||
530 | spin_lock(&gss_auth->lock); | ||
531 | gss_msg = __gss_find_upcall(gss_auth, uid); | ||
532 | if (gss_msg) { | ||
533 | if (err == 0 && gss_msg->ctx == NULL) | ||
534 | gss_msg->ctx = gss_get_ctx(ctx); | ||
535 | gss_msg->msg.errno = err; | ||
536 | __gss_unhash_msg(gss_msg); | ||
537 | spin_unlock(&gss_auth->lock); | ||
538 | gss_release_msg(gss_msg); | ||
539 | } else { | ||
540 | struct auth_cred acred = { .uid = uid }; | ||
541 | spin_unlock(&gss_auth->lock); | ||
542 | cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); | ||
543 | if (IS_ERR(cred)) { | ||
544 | err = PTR_ERR(cred); | ||
545 | goto err_put_ctx; | ||
546 | } | ||
547 | gss_cred_set_ctx(cred, gss_get_ctx(ctx)); | ||
548 | } | 545 | } |
549 | gss_put_ctx(ctx); | 546 | gss_msg->ctx = gss_get_ctx(ctx); |
550 | kfree(buf); | 547 | err = mlen; |
551 | dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); | 548 | |
552 | return mlen; | 549 | err_release_msg: |
550 | spin_lock(&inode->i_lock); | ||
551 | __gss_unhash_msg(gss_msg); | ||
552 | spin_unlock(&inode->i_lock); | ||
553 | gss_release_msg(gss_msg); | ||
553 | err_put_ctx: | 554 | err_put_ctx: |
554 | gss_put_ctx(ctx); | 555 | gss_put_ctx(ctx); |
555 | err: | 556 | err: |
556 | kfree(buf); | 557 | kfree(buf); |
557 | out: | 558 | out: |
558 | dprintk("RPC: gss_pipe_downcall returning %d\n", err); | 559 | dprintk("RPC: gss_pipe_downcall returning %Zd\n", err); |
559 | return err; | 560 | return err; |
560 | } | 561 | } |
561 | 562 | ||
@@ -563,27 +564,21 @@ static void | |||
563 | gss_pipe_release(struct inode *inode) | 564 | gss_pipe_release(struct inode *inode) |
564 | { | 565 | { |
565 | struct rpc_inode *rpci = RPC_I(inode); | 566 | struct rpc_inode *rpci = RPC_I(inode); |
566 | struct rpc_clnt *clnt; | 567 | struct gss_upcall_msg *gss_msg; |
567 | struct rpc_auth *auth; | ||
568 | struct gss_auth *gss_auth; | ||
569 | 568 | ||
570 | clnt = rpci->private; | 569 | spin_lock(&inode->i_lock); |
571 | auth = clnt->cl_auth; | 570 | while (!list_empty(&rpci->in_downcall)) { |
572 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | ||
573 | spin_lock(&gss_auth->lock); | ||
574 | while (!list_empty(&gss_auth->upcalls)) { | ||
575 | struct gss_upcall_msg *gss_msg; | ||
576 | 571 | ||
577 | gss_msg = list_entry(gss_auth->upcalls.next, | 572 | gss_msg = list_entry(rpci->in_downcall.next, |
578 | struct gss_upcall_msg, list); | 573 | struct gss_upcall_msg, list); |
579 | gss_msg->msg.errno = -EPIPE; | 574 | gss_msg->msg.errno = -EPIPE; |
580 | atomic_inc(&gss_msg->count); | 575 | atomic_inc(&gss_msg->count); |
581 | __gss_unhash_msg(gss_msg); | 576 | __gss_unhash_msg(gss_msg); |
582 | spin_unlock(&gss_auth->lock); | 577 | spin_unlock(&inode->i_lock); |
583 | gss_release_msg(gss_msg); | 578 | gss_release_msg(gss_msg); |
584 | spin_lock(&gss_auth->lock); | 579 | spin_lock(&inode->i_lock); |
585 | } | 580 | } |
586 | spin_unlock(&gss_auth->lock); | 581 | spin_unlock(&inode->i_lock); |
587 | } | 582 | } |
588 | 583 | ||
589 | static void | 584 | static void |
@@ -637,18 +632,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
637 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | 632 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); |
638 | if (gss_auth->service == 0) | 633 | if (gss_auth->service == 0) |
639 | goto err_put_mech; | 634 | goto err_put_mech; |
640 | INIT_LIST_HEAD(&gss_auth->upcalls); | ||
641 | spin_lock_init(&gss_auth->lock); | ||
642 | auth = &gss_auth->rpc_auth; | 635 | auth = &gss_auth->rpc_auth; |
643 | auth->au_cslack = GSS_CRED_SLACK >> 2; | 636 | auth->au_cslack = GSS_CRED_SLACK >> 2; |
644 | auth->au_rslack = GSS_VERF_SLACK >> 2; | 637 | auth->au_rslack = GSS_VERF_SLACK >> 2; |
645 | auth->au_ops = &authgss_ops; | 638 | auth->au_ops = &authgss_ops; |
646 | auth->au_flavor = flavor; | 639 | auth->au_flavor = flavor; |
647 | atomic_set(&auth->au_count, 1); | 640 | atomic_set(&auth->au_count, 1); |
648 | 641 | kref_init(&gss_auth->kref); | |
649 | err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); | ||
650 | if (err) | ||
651 | goto err_put_mech; | ||
652 | 642 | ||
653 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, | 643 | gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name, |
654 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | 644 | clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); |
@@ -657,7 +647,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
657 | goto err_put_mech; | 647 | goto err_put_mech; |
658 | } | 648 | } |
659 | 649 | ||
650 | err = rpcauth_init_credcache(auth); | ||
651 | if (err) | ||
652 | goto err_unlink_pipe; | ||
653 | |||
660 | return auth; | 654 | return auth; |
655 | err_unlink_pipe: | ||
656 | rpc_unlink(gss_auth->dentry); | ||
661 | err_put_mech: | 657 | err_put_mech: |
662 | gss_mech_put(gss_auth->mech); | 658 | gss_mech_put(gss_auth->mech); |
663 | err_free: | 659 | err_free: |
@@ -668,6 +664,25 @@ out_dec: | |||
668 | } | 664 | } |
669 | 665 | ||
670 | static void | 666 | static void |
667 | gss_free(struct gss_auth *gss_auth) | ||
668 | { | ||
669 | rpc_unlink(gss_auth->dentry); | ||
670 | gss_auth->dentry = NULL; | ||
671 | gss_mech_put(gss_auth->mech); | ||
672 | |||
673 | kfree(gss_auth); | ||
674 | module_put(THIS_MODULE); | ||
675 | } | ||
676 | |||
677 | static void | ||
678 | gss_free_callback(struct kref *kref) | ||
679 | { | ||
680 | struct gss_auth *gss_auth = container_of(kref, struct gss_auth, kref); | ||
681 | |||
682 | gss_free(gss_auth); | ||
683 | } | ||
684 | |||
685 | static void | ||
671 | gss_destroy(struct rpc_auth *auth) | 686 | gss_destroy(struct rpc_auth *auth) |
672 | { | 687 | { |
673 | struct gss_auth *gss_auth; | 688 | struct gss_auth *gss_auth; |
@@ -675,23 +690,51 @@ gss_destroy(struct rpc_auth *auth) | |||
675 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", | 690 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", |
676 | auth, auth->au_flavor); | 691 | auth, auth->au_flavor); |
677 | 692 | ||
693 | rpcauth_destroy_credcache(auth); | ||
694 | |||
678 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 695 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); |
679 | rpc_unlink(gss_auth->dentry); | 696 | kref_put(&gss_auth->kref, gss_free_callback); |
680 | gss_auth->dentry = NULL; | 697 | } |
681 | gss_mech_put(gss_auth->mech); | ||
682 | 698 | ||
683 | rpcauth_free_credcache(auth); | 699 | /* |
684 | kfree(gss_auth); | 700 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call |
685 | module_put(THIS_MODULE); | 701 | * to the server with the GSS control procedure field set to |
702 | * RPC_GSS_PROC_DESTROY. This should normally cause the server to release | ||
703 | * all RPCSEC_GSS state associated with that context. | ||
704 | */ | ||
705 | static int | ||
706 | gss_destroying_context(struct rpc_cred *cred) | ||
707 | { | ||
708 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
709 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | ||
710 | struct rpc_task *task; | ||
711 | |||
712 | if (gss_cred->gc_ctx == NULL || | ||
713 | gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY) | ||
714 | return 0; | ||
715 | |||
716 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | ||
717 | cred->cr_ops = &gss_nullops; | ||
718 | |||
719 | /* Take a reference to ensure the cred will be destroyed either | ||
720 | * by the RPC call or by the put_rpccred() below */ | ||
721 | get_rpccred(cred); | ||
722 | |||
723 | task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC); | ||
724 | if (!IS_ERR(task)) | ||
725 | rpc_put_task(task); | ||
726 | |||
727 | put_rpccred(cred); | ||
728 | return 1; | ||
686 | } | 729 | } |
687 | 730 | ||
688 | /* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure | 731 | /* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure |
689 | * to create a new cred or context, so they check that things have been | 732 | * to create a new cred or context, so they check that things have been |
690 | * allocated before freeing them. */ | 733 | * allocated before freeing them. */ |
691 | static void | 734 | static void |
692 | gss_destroy_ctx(struct gss_cl_ctx *ctx) | 735 | gss_do_free_ctx(struct gss_cl_ctx *ctx) |
693 | { | 736 | { |
694 | dprintk("RPC: gss_destroy_ctx\n"); | 737 | dprintk("RPC: gss_free_ctx\n"); |
695 | 738 | ||
696 | if (ctx->gc_gss_ctx) | 739 | if (ctx->gc_gss_ctx) |
697 | gss_delete_sec_context(&ctx->gc_gss_ctx); | 740 | gss_delete_sec_context(&ctx->gc_gss_ctx); |
@@ -701,15 +744,46 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx) | |||
701 | } | 744 | } |
702 | 745 | ||
703 | static void | 746 | static void |
704 | gss_destroy_cred(struct rpc_cred *rc) | 747 | gss_free_ctx_callback(struct rcu_head *head) |
705 | { | 748 | { |
706 | struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); | 749 | struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu); |
750 | gss_do_free_ctx(ctx); | ||
751 | } | ||
707 | 752 | ||
708 | dprintk("RPC: gss_destroy_cred \n"); | 753 | static void |
754 | gss_free_ctx(struct gss_cl_ctx *ctx) | ||
755 | { | ||
756 | call_rcu(&ctx->gc_rcu, gss_free_ctx_callback); | ||
757 | } | ||
709 | 758 | ||
710 | if (cred->gc_ctx) | 759 | static void |
711 | gss_put_ctx(cred->gc_ctx); | 760 | gss_free_cred(struct gss_cred *gss_cred) |
712 | kfree(cred); | 761 | { |
762 | dprintk("RPC: gss_free_cred %p\n", gss_cred); | ||
763 | kfree(gss_cred); | ||
764 | } | ||
765 | |||
766 | static void | ||
767 | gss_free_cred_callback(struct rcu_head *head) | ||
768 | { | ||
769 | struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu); | ||
770 | gss_free_cred(gss_cred); | ||
771 | } | ||
772 | |||
773 | static void | ||
774 | gss_destroy_cred(struct rpc_cred *cred) | ||
775 | { | ||
776 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
777 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | ||
778 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | ||
779 | |||
780 | if (gss_destroying_context(cred)) | ||
781 | return; | ||
782 | rcu_assign_pointer(gss_cred->gc_ctx, NULL); | ||
783 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | ||
784 | if (ctx) | ||
785 | gss_put_ctx(ctx); | ||
786 | kref_put(&gss_auth->kref, gss_free_callback); | ||
713 | } | 787 | } |
714 | 788 | ||
715 | /* | 789 | /* |
@@ -734,16 +808,14 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
734 | if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL))) | 808 | if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL))) |
735 | goto out_err; | 809 | goto out_err; |
736 | 810 | ||
737 | atomic_set(&cred->gc_count, 1); | 811 | rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops); |
738 | cred->gc_uid = acred->uid; | ||
739 | /* | 812 | /* |
740 | * Note: in order to force a call to call_refresh(), we deliberately | 813 | * Note: in order to force a call to call_refresh(), we deliberately |
741 | * fail to flag the credential as RPCAUTH_CRED_UPTODATE. | 814 | * fail to flag the credential as RPCAUTH_CRED_UPTODATE. |
742 | */ | 815 | */ |
743 | cred->gc_flags = 0; | 816 | cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW; |
744 | cred->gc_base.cr_ops = &gss_credops; | ||
745 | cred->gc_base.cr_flags = RPCAUTH_CRED_NEW; | ||
746 | cred->gc_service = gss_auth->service; | 817 | cred->gc_service = gss_auth->service; |
818 | kref_get(&gss_auth->kref); | ||
747 | return &cred->gc_base; | 819 | return &cred->gc_base; |
748 | 820 | ||
749 | out_err: | 821 | out_err: |
@@ -774,7 +846,7 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | |||
774 | * we don't really care if the credential has expired or not, | 846 | * we don't really care if the credential has expired or not, |
775 | * since the caller should be prepared to reinitialise it. | 847 | * since the caller should be prepared to reinitialise it. |
776 | */ | 848 | */ |
777 | if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW)) | 849 | if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
778 | goto out; | 850 | goto out; |
779 | /* Don't match with creds that have expired. */ | 851 | /* Don't match with creds that have expired. */ |
780 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 852 | if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) |
@@ -830,7 +902,7 @@ gss_marshal(struct rpc_task *task, __be32 *p) | |||
830 | mic.data = (u8 *)(p + 1); | 902 | mic.data = (u8 *)(p + 1); |
831 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 903 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
832 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { | 904 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) { |
833 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 905 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
834 | } else if (maj_stat != 0) { | 906 | } else if (maj_stat != 0) { |
835 | printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); | 907 | printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat); |
836 | goto out_put_ctx; | 908 | goto out_put_ctx; |
@@ -855,6 +927,13 @@ gss_refresh(struct rpc_task *task) | |||
855 | return 0; | 927 | return 0; |
856 | } | 928 | } |
857 | 929 | ||
930 | /* Dummy refresh routine: used only when destroying the context */ | ||
931 | static int | ||
932 | gss_refresh_null(struct rpc_task *task) | ||
933 | { | ||
934 | return -EACCES; | ||
935 | } | ||
936 | |||
858 | static __be32 * | 937 | static __be32 * |
859 | gss_validate(struct rpc_task *task, __be32 *p) | 938 | gss_validate(struct rpc_task *task, __be32 *p) |
860 | { | 939 | { |
@@ -883,12 +962,15 @@ gss_validate(struct rpc_task *task, __be32 *p) | |||
883 | 962 | ||
884 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 963 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
885 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 964 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
886 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 965 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
887 | if (maj_stat) | 966 | if (maj_stat) { |
967 | dprintk("RPC: %5u gss_validate: gss_verify_mic returned" | ||
968 | "error 0x%08x\n", task->tk_pid, maj_stat); | ||
888 | goto out_bad; | 969 | goto out_bad; |
970 | } | ||
889 | /* We leave it to unwrap to calculate au_rslack. For now we just | 971 | /* We leave it to unwrap to calculate au_rslack. For now we just |
890 | * calculate the length of the verifier: */ | 972 | * calculate the length of the verifier: */ |
891 | task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2; | 973 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; |
892 | gss_put_ctx(ctx); | 974 | gss_put_ctx(ctx); |
893 | dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n", | 975 | dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n", |
894 | task->tk_pid); | 976 | task->tk_pid); |
@@ -917,7 +999,9 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
917 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; | 999 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; |
918 | *p++ = htonl(rqstp->rq_seqno); | 1000 | *p++ = htonl(rqstp->rq_seqno); |
919 | 1001 | ||
1002 | lock_kernel(); | ||
920 | status = encode(rqstp, p, obj); | 1003 | status = encode(rqstp, p, obj); |
1004 | unlock_kernel(); | ||
921 | if (status) | 1005 | if (status) |
922 | return status; | 1006 | return status; |
923 | 1007 | ||
@@ -937,7 +1021,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
937 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | 1021 | maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic); |
938 | status = -EIO; /* XXX? */ | 1022 | status = -EIO; /* XXX? */ |
939 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1023 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
940 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 1024 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
941 | else if (maj_stat) | 1025 | else if (maj_stat) |
942 | return status; | 1026 | return status; |
943 | q = xdr_encode_opaque(p, NULL, mic.len); | 1027 | q = xdr_encode_opaque(p, NULL, mic.len); |
@@ -1011,7 +1095,9 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
1011 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; | 1095 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; |
1012 | *p++ = htonl(rqstp->rq_seqno); | 1096 | *p++ = htonl(rqstp->rq_seqno); |
1013 | 1097 | ||
1098 | lock_kernel(); | ||
1014 | status = encode(rqstp, p, obj); | 1099 | status = encode(rqstp, p, obj); |
1100 | unlock_kernel(); | ||
1015 | if (status) | 1101 | if (status) |
1016 | return status; | 1102 | return status; |
1017 | 1103 | ||
@@ -1036,7 +1122,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
1036 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was | 1122 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was |
1037 | * done anyway, so it's safe to put the request on the wire: */ | 1123 | * done anyway, so it's safe to put the request on the wire: */ |
1038 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1124 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1039 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 1125 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1040 | else if (maj_stat) | 1126 | else if (maj_stat) |
1041 | return status; | 1127 | return status; |
1042 | 1128 | ||
@@ -1070,12 +1156,16 @@ gss_wrap_req(struct rpc_task *task, | |||
1070 | /* The spec seems a little ambiguous here, but I think that not | 1156 | /* The spec seems a little ambiguous here, but I think that not |
1071 | * wrapping context destruction requests makes the most sense. | 1157 | * wrapping context destruction requests makes the most sense. |
1072 | */ | 1158 | */ |
1159 | lock_kernel(); | ||
1073 | status = encode(rqstp, p, obj); | 1160 | status = encode(rqstp, p, obj); |
1161 | unlock_kernel(); | ||
1074 | goto out; | 1162 | goto out; |
1075 | } | 1163 | } |
1076 | switch (gss_cred->gc_service) { | 1164 | switch (gss_cred->gc_service) { |
1077 | case RPC_GSS_SVC_NONE: | 1165 | case RPC_GSS_SVC_NONE: |
1166 | lock_kernel(); | ||
1078 | status = encode(rqstp, p, obj); | 1167 | status = encode(rqstp, p, obj); |
1168 | unlock_kernel(); | ||
1079 | break; | 1169 | break; |
1080 | case RPC_GSS_SVC_INTEGRITY: | 1170 | case RPC_GSS_SVC_INTEGRITY: |
1081 | status = gss_wrap_req_integ(cred, ctx, encode, | 1171 | status = gss_wrap_req_integ(cred, ctx, encode, |
@@ -1123,7 +1213,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
1123 | 1213 | ||
1124 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | 1214 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); |
1125 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1215 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1126 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 1216 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1127 | if (maj_stat != GSS_S_COMPLETE) | 1217 | if (maj_stat != GSS_S_COMPLETE) |
1128 | return status; | 1218 | return status; |
1129 | return 0; | 1219 | return 0; |
@@ -1148,7 +1238,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
1148 | 1238 | ||
1149 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); | 1239 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); |
1150 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1240 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1151 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | 1241 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1152 | if (maj_stat != GSS_S_COMPLETE) | 1242 | if (maj_stat != GSS_S_COMPLETE) |
1153 | return status; | 1243 | return status; |
1154 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | 1244 | if (ntohl(*(*p)++) != rqstp->rq_seqno) |
@@ -1188,10 +1278,12 @@ gss_unwrap_resp(struct rpc_task *task, | |||
1188 | break; | 1278 | break; |
1189 | } | 1279 | } |
1190 | /* take into account extra slack for integrity and privacy cases: */ | 1280 | /* take into account extra slack for integrity and privacy cases: */ |
1191 | task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp) | 1281 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) |
1192 | + (savedlen - head->iov_len); | 1282 | + (savedlen - head->iov_len); |
1193 | out_decode: | 1283 | out_decode: |
1284 | lock_kernel(); | ||
1194 | status = decode(rqstp, p, obj); | 1285 | status = decode(rqstp, p, obj); |
1286 | unlock_kernel(); | ||
1195 | out: | 1287 | out: |
1196 | gss_put_ctx(ctx); | 1288 | gss_put_ctx(ctx); |
1197 | dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, | 1289 | dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid, |
@@ -1199,7 +1291,7 @@ out: | |||
1199 | return status; | 1291 | return status; |
1200 | } | 1292 | } |
1201 | 1293 | ||
1202 | static struct rpc_authops authgss_ops = { | 1294 | static const struct rpc_authops authgss_ops = { |
1203 | .owner = THIS_MODULE, | 1295 | .owner = THIS_MODULE, |
1204 | .au_flavor = RPC_AUTH_GSS, | 1296 | .au_flavor = RPC_AUTH_GSS, |
1205 | #ifdef RPC_DEBUG | 1297 | #ifdef RPC_DEBUG |
@@ -1211,7 +1303,7 @@ static struct rpc_authops authgss_ops = { | |||
1211 | .crcreate = gss_create_cred | 1303 | .crcreate = gss_create_cred |
1212 | }; | 1304 | }; |
1213 | 1305 | ||
1214 | static struct rpc_credops gss_credops = { | 1306 | static const struct rpc_credops gss_credops = { |
1215 | .cr_name = "AUTH_GSS", | 1307 | .cr_name = "AUTH_GSS", |
1216 | .crdestroy = gss_destroy_cred, | 1308 | .crdestroy = gss_destroy_cred, |
1217 | .cr_init = gss_cred_init, | 1309 | .cr_init = gss_cred_init, |
@@ -1223,6 +1315,17 @@ static struct rpc_credops gss_credops = { | |||
1223 | .crunwrap_resp = gss_unwrap_resp, | 1315 | .crunwrap_resp = gss_unwrap_resp, |
1224 | }; | 1316 | }; |
1225 | 1317 | ||
1318 | static const struct rpc_credops gss_nullops = { | ||
1319 | .cr_name = "AUTH_GSS", | ||
1320 | .crdestroy = gss_destroy_cred, | ||
1321 | .crmatch = gss_match, | ||
1322 | .crmarshal = gss_marshal, | ||
1323 | .crrefresh = gss_refresh_null, | ||
1324 | .crvalidate = gss_validate, | ||
1325 | .crwrap_req = gss_wrap_req, | ||
1326 | .crunwrap_resp = gss_unwrap_resp, | ||
1327 | }; | ||
1328 | |||
1226 | static struct rpc_pipe_ops gss_upcall_ops = { | 1329 | static struct rpc_pipe_ops gss_upcall_ops = { |
1227 | .upcall = gss_pipe_upcall, | 1330 | .upcall = gss_pipe_upcall, |
1228 | .downcall = gss_pipe_downcall, | 1331 | .downcall = gss_pipe_downcall, |