RPCSEC_GSS: client-side privacy support
Add the code to the client side to handle privacy. This is dead code until we actually add privacy support to krb5. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
24b2605bec
commit
2d2da60c63
|
@ -43,6 +43,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
|
@ -975,6 +976,114 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
priv_release_snd_buf(struct rpc_rqst *rqstp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < rqstp->rq_enc_pages_num; i++)
|
||||
__free_page(rqstp->rq_enc_pages[i]);
|
||||
kfree(rqstp->rq_enc_pages);
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_enc_pages(struct rpc_rqst *rqstp)
|
||||
{
|
||||
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
|
||||
int first, last, i;
|
||||
|
||||
if (snd_buf->page_len == 0) {
|
||||
rqstp->rq_enc_pages_num = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
|
||||
last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_CACHE_SHIFT;
|
||||
rqstp->rq_enc_pages_num = last - first + 1 + 1;
|
||||
rqstp->rq_enc_pages
|
||||
= kmalloc(rqstp->rq_enc_pages_num * sizeof(struct page *),
|
||||
GFP_NOFS);
|
||||
if (!rqstp->rq_enc_pages)
|
||||
goto out;
|
||||
for (i=0; i < rqstp->rq_enc_pages_num; i++) {
|
||||
rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS);
|
||||
if (rqstp->rq_enc_pages[i] == NULL)
|
||||
goto out_free;
|
||||
}
|
||||
rqstp->rq_release_snd_buf = priv_release_snd_buf;
|
||||
return 0;
|
||||
out_free:
|
||||
for (i--; i >= 0; i--) {
|
||||
__free_page(rqstp->rq_enc_pages[i]);
|
||||
}
|
||||
out:
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static inline int
|
||||
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
|
||||
{
|
||||
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
|
||||
u32 offset;
|
||||
u32 maj_stat;
|
||||
int status;
|
||||
u32 *opaque_len;
|
||||
struct page **inpages;
|
||||
int first;
|
||||
int pad;
|
||||
struct kvec *iov;
|
||||
char *tmp;
|
||||
|
||||
opaque_len = p++;
|
||||
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
|
||||
*p++ = htonl(rqstp->rq_seqno);
|
||||
|
||||
status = encode(rqstp, p, obj);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = alloc_enc_pages(rqstp);
|
||||
if (status)
|
||||
return status;
|
||||
first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
|
||||
inpages = snd_buf->pages + first;
|
||||
snd_buf->pages = rqstp->rq_enc_pages;
|
||||
snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
|
||||
/* Give the tail its own page, in case we need extra space in the
|
||||
* head when wrapping: */
|
||||
if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
|
||||
tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
|
||||
memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
|
||||
snd_buf->tail[0].iov_base = tmp;
|
||||
}
|
||||
maj_stat = gss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, offset,
|
||||
snd_buf, inpages);
|
||||
/* RPC_SLACK_SPACE should prevent this ever happening: */
|
||||
BUG_ON(snd_buf->len > snd_buf->buflen);
|
||||
status = -EIO;
|
||||
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
|
||||
* done anyway, so it's safe to put the request on the wire: */
|
||||
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
|
||||
cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
|
||||
else if (maj_stat)
|
||||
return status;
|
||||
|
||||
*opaque_len = htonl(snd_buf->len - offset);
|
||||
/* guess whether we're in the head or the tail: */
|
||||
if (snd_buf->page_len || snd_buf->tail[0].iov_len)
|
||||
iov = snd_buf->tail;
|
||||
else
|
||||
iov = snd_buf->head;
|
||||
p = iov->iov_base + iov->iov_len;
|
||||
pad = 3 - ((snd_buf->len - offset - 1) & 3);
|
||||
memset(p, 0, pad);
|
||||
iov->iov_len += pad;
|
||||
snd_buf->len += pad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_wrap_req(struct rpc_task *task,
|
||||
kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
|
||||
|
@ -1002,6 +1111,8 @@ gss_wrap_req(struct rpc_task *task,
|
|||
rqstp, p, obj);
|
||||
break;
|
||||
case RPC_GSS_SVC_PRIVACY:
|
||||
status = gss_wrap_req_priv(cred, ctx, encode,
|
||||
rqstp, p, obj);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
|
@ -1048,6 +1159,36 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
struct rpc_rqst *rqstp, u32 **p)
|
||||
{
|
||||
struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
|
||||
u32 offset;
|
||||
u32 opaque_len;
|
||||
u32 maj_stat;
|
||||
int status = -EIO;
|
||||
|
||||
opaque_len = ntohl(*(*p)++);
|
||||
offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
|
||||
if (offset + opaque_len > rcv_buf->len)
|
||||
return status;
|
||||
/* remove padding: */
|
||||
rcv_buf->len = offset + opaque_len;
|
||||
|
||||
maj_stat = gss_unwrap(ctx->gc_gss_ctx, NULL,
|
||||
offset, rcv_buf);
|
||||
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
|
||||
cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
|
||||
if (maj_stat != GSS_S_COMPLETE)
|
||||
return status;
|
||||
if (ntohl(*(*p)++) != rqstp->rq_seqno)
|
||||
return status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
gss_unwrap_resp(struct rpc_task *task,
|
||||
kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
|
||||
|
@ -1057,6 +1198,8 @@ gss_unwrap_resp(struct rpc_task *task,
|
|||
gc_base);
|
||||
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
|
||||
u32 *savedp = p;
|
||||
struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
|
||||
int savedlen = head->iov_len;
|
||||
int status = -EIO;
|
||||
|
||||
if (ctx->gc_proc != RPC_GSS_PROC_DATA)
|
||||
|
@ -1070,10 +1213,14 @@ gss_unwrap_resp(struct rpc_task *task,
|
|||
goto out;
|
||||
break;
|
||||
case RPC_GSS_SVC_PRIVACY:
|
||||
status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
/* take into account extra slack for integrity and privacy cases: */
|
||||
task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp);
|
||||
task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp)
|
||||
+ (savedlen - head->iov_len);
|
||||
out_decode:
|
||||
status = decode(rqstp, p, obj);
|
||||
out:
|
||||
|
|
Loading…
Reference in New Issue