diff options
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 89 |
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; | |||
57 | static const struct rpc_credops gss_credops; | 57 | static const struct rpc_credops gss_credops; |
58 | static const struct rpc_credops gss_nullops; | 58 | static const struct rpc_credops gss_nullops; |
59 | 59 | ||
60 | #define GSS_RETRY_EXPIRED 5 | ||
61 | static 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 | ||
352 | static void | 355 | static void |
356 | gss_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 | |||
373 | static void | ||
353 | gss_upcall_callback(struct rpc_task *task) | 374 | gss_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) | |||
377 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | 394 | static 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); |
524 | out: | 545 | out: |
@@ -1117,6 +1138,23 @@ static int gss_renew_cred(struct rpc_task *task) | |||
1117 | return 0; | 1138 | return 0; |
1118 | } | 1139 | } |
1119 | 1140 | ||
1141 | static 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 | ||
1575 | MODULE_LICENSE("GPL"); | 1622 | MODULE_LICENSE("GPL"); |
1623 | module_param_named(expired_cred_retry_delay, | ||
1624 | gss_expired_cred_retry_delay, | ||
1625 | uint, 0644); | ||
1626 | MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until " | ||
1627 | "the RPC engine retries an expired credential"); | ||
1628 | |||
1576 | module_init(init_rpcsec_gss) | 1629 | module_init(init_rpcsec_gss) |
1577 | module_exit(exit_rpcsec_gss) | 1630 | module_exit(exit_rpcsec_gss) |