aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth_gss/auth_gss.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c89
1 files changed, 71 insertions, 18 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index c389ccf6437d..8da2a0e68574 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -57,11 +57,14 @@ static const struct rpc_authops authgss_ops;
57static const struct rpc_credops gss_credops; 57static const struct rpc_credops gss_credops;
58static const struct rpc_credops gss_nullops; 58static const struct rpc_credops gss_nullops;
59 59
60#define GSS_RETRY_EXPIRED 5
61static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
62
60#ifdef RPC_DEBUG 63#ifdef RPC_DEBUG
61# define RPCDBG_FACILITY RPCDBG_AUTH 64# define RPCDBG_FACILITY RPCDBG_AUTH
62#endif 65#endif
63 66
64#define GSS_CRED_SLACK 1024 67#define GSS_CRED_SLACK (RPC_MAX_AUTH_SIZE * 2)
65/* length of a krb5 verifier (48), plus data added before arguments when 68/* length of a krb5 verifier (48), plus data added before arguments when
66 * using integrity (two 4-byte integers): */ 69 * using integrity (two 4-byte integers): */
67#define GSS_VERF_SLACK 100 70#define GSS_VERF_SLACK 100
@@ -229,7 +232,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
229 p = ERR_PTR(-EFAULT); 232 p = ERR_PTR(-EFAULT);
230 goto err; 233 goto err;
231 } 234 }
232 ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx); 235 ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, GFP_NOFS);
233 if (ret < 0) { 236 if (ret < 0) {
234 p = ERR_PTR(ret); 237 p = ERR_PTR(ret);
235 goto err; 238 goto err;
@@ -350,6 +353,24 @@ gss_unhash_msg(struct gss_upcall_msg *gss_msg)
350} 353}
351 354
352static void 355static void
356gss_handle_downcall_result(struct gss_cred *gss_cred, struct gss_upcall_msg *gss_msg)
357{
358 switch (gss_msg->msg.errno) {
359 case 0:
360 if (gss_msg->ctx == NULL)
361 break;
362 clear_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
363 gss_cred_set_ctx(&gss_cred->gc_base, gss_msg->ctx);
364 break;
365 case -EKEYEXPIRED:
366 set_bit(RPCAUTH_CRED_NEGATIVE, &gss_cred->gc_base.cr_flags);
367 }
368 gss_cred->gc_upcall_timestamp = jiffies;
369 gss_cred->gc_upcall = NULL;
370 rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
371}
372
373static void
353gss_upcall_callback(struct rpc_task *task) 374gss_upcall_callback(struct rpc_task *task)
354{ 375{
355 struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred, 376 struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
@@ -358,13 +379,9 @@ gss_upcall_callback(struct rpc_task *task)
358 struct inode *inode = &gss_msg->inode->vfs_inode; 379 struct inode *inode = &gss_msg->inode->vfs_inode;
359 380
360 spin_lock(&inode->i_lock); 381 spin_lock(&inode->i_lock);
361 if (gss_msg->ctx) 382 gss_handle_downcall_result(gss_cred, gss_msg);
362 gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
363 else
364 task->tk_status = gss_msg->msg.errno;
365 gss_cred->gc_upcall = NULL;
366 rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
367 spin_unlock(&inode->i_lock); 383 spin_unlock(&inode->i_lock);
384 task->tk_status = gss_msg->msg.errno;
368 gss_release_msg(gss_msg); 385 gss_release_msg(gss_msg);
369} 386}
370 387
@@ -377,11 +394,12 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
377static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, 394static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
378 struct rpc_clnt *clnt, int machine_cred) 395 struct rpc_clnt *clnt, int machine_cred)
379{ 396{
397 struct gss_api_mech *mech = gss_msg->auth->mech;
380 char *p = gss_msg->databuf; 398 char *p = gss_msg->databuf;
381 int len = 0; 399 int len = 0;
382 400
383 gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ", 401 gss_msg->msg.len = sprintf(gss_msg->databuf, "mech=%s uid=%d ",
384 gss_msg->auth->mech->gm_name, 402 mech->gm_name,
385 gss_msg->uid); 403 gss_msg->uid);
386 p += gss_msg->msg.len; 404 p += gss_msg->msg.len;
387 if (clnt->cl_principal) { 405 if (clnt->cl_principal) {
@@ -398,6 +416,11 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
398 p += len; 416 p += len;
399 gss_msg->msg.len += len; 417 gss_msg->msg.len += len;
400 } 418 }
419 if (mech->gm_upcall_enctypes) {
420 len = sprintf(p, mech->gm_upcall_enctypes);
421 p += len;
422 gss_msg->msg.len += len;
423 }
401 len = sprintf(p, "\n"); 424 len = sprintf(p, "\n");
402 gss_msg->msg.len += len; 425 gss_msg->msg.len += len;
403 426
@@ -507,18 +530,16 @@ gss_refresh_upcall(struct rpc_task *task)
507 spin_lock(&inode->i_lock); 530 spin_lock(&inode->i_lock);
508 if (gss_cred->gc_upcall != NULL) 531 if (gss_cred->gc_upcall != NULL)
509 rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL); 532 rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL);
510 else if (gss_msg->ctx != NULL) { 533 else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
511 gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_msg->ctx);
512 gss_cred->gc_upcall = NULL;
513 rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
514 } else if (gss_msg->msg.errno >= 0) {
515 task->tk_timeout = 0; 534 task->tk_timeout = 0;
516 gss_cred->gc_upcall = gss_msg; 535 gss_cred->gc_upcall = gss_msg;
517 /* gss_upcall_callback will release the reference to gss_upcall_msg */ 536 /* gss_upcall_callback will release the reference to gss_upcall_msg */
518 atomic_inc(&gss_msg->count); 537 atomic_inc(&gss_msg->count);
519 rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback); 538 rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback);
520 } else 539 } else {
540 gss_handle_downcall_result(gss_cred, gss_msg);
521 err = gss_msg->msg.errno; 541 err = gss_msg->msg.errno;
542 }
522 spin_unlock(&inode->i_lock); 543 spin_unlock(&inode->i_lock);
523 gss_release_msg(gss_msg); 544 gss_release_msg(gss_msg);
524out: 545out:
@@ -1117,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task)
1117 return 0; 1138 return 0;
1118} 1139}
1119 1140
1141static int gss_cred_is_negative_entry(struct rpc_cred *cred)
1142{
1143 if (test_bit(RPCAUTH_CRED_NEGATIVE, &cred->cr_flags)) {
1144 unsigned long now = jiffies;
1145 unsigned long begin, expire;
1146 struct gss_cred *gss_cred;
1147
1148 gss_cred = container_of(cred, struct gss_cred, gc_base);
1149 begin = gss_cred->gc_upcall_timestamp;
1150 expire = begin + gss_expired_cred_retry_delay * HZ;
1151
1152 if (time_in_range_open(now, begin, expire))
1153 return 1;
1154 }
1155 return 0;
1156}
1157
1120/* 1158/*
1121* Refresh credentials. XXX - finish 1159* Refresh credentials. XXX - finish
1122*/ 1160*/
@@ -1126,6 +1164,9 @@ gss_refresh(struct rpc_task *task)
1126 struct rpc_cred *cred = task->tk_msg.rpc_cred; 1164 struct rpc_cred *cred = task->tk_msg.rpc_cred;
1127 int ret = 0; 1165 int ret = 0;
1128 1166
1167 if (gss_cred_is_negative_entry(cred))
1168 return -EKEYEXPIRED;
1169
1129 if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && 1170 if (!test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) &&
1130 !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) { 1171 !test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags)) {
1131 ret = gss_renew_cred(task); 1172 ret = gss_renew_cred(task);
@@ -1316,15 +1357,21 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
1316 inpages = snd_buf->pages + first; 1357 inpages = snd_buf->pages + first;
1317 snd_buf->pages = rqstp->rq_enc_pages; 1358 snd_buf->pages = rqstp->rq_enc_pages;
1318 snd_buf->page_base -= first << PAGE_CACHE_SHIFT; 1359 snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
1319 /* Give the tail its own page, in case we need extra space in the 1360 /*
1320 * head when wrapping: */ 1361 * Give the tail its own page, in case we need extra space in the
1362 * head when wrapping:
1363 *
1364 * call_allocate() allocates twice the slack space required
1365 * by the authentication flavor to rq_callsize.
1366 * For GSS, slack is GSS_CRED_SLACK.
1367 */
1321 if (snd_buf->page_len || snd_buf->tail[0].iov_len) { 1368 if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
1322 tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]); 1369 tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
1323 memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); 1370 memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
1324 snd_buf->tail[0].iov_base = tmp; 1371 snd_buf->tail[0].iov_base = tmp;
1325 } 1372 }
1326 maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages); 1373 maj_stat = gss_wrap(ctx->gc_gss_ctx, offset, snd_buf, inpages);
1327 /* RPC_SLACK_SPACE should prevent this ever happening: */ 1374 /* slack space should prevent this ever happening: */
1328 BUG_ON(snd_buf->len > snd_buf->buflen); 1375 BUG_ON(snd_buf->len > snd_buf->buflen);
1329 status = -EIO; 1376 status = -EIO;
1330 /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was 1377 /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
@@ -1573,5 +1620,11 @@ static void __exit exit_rpcsec_gss(void)
1573} 1620}
1574 1621
1575MODULE_LICENSE("GPL"); 1622MODULE_LICENSE("GPL");
1623module_param_named(expired_cred_retry_delay,
1624 gss_expired_cred_retry_delay,
1625 uint, 0644);
1626MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until "
1627 "the RPC engine retries an expired credential");
1628
1576module_init(init_rpcsec_gss) 1629module_init(init_rpcsec_gss)
1577module_exit(exit_rpcsec_gss) 1630module_exit(exit_rpcsec_gss)