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/types.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/pagemap.h>
|
||||||
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
||||||
#include <linux/sunrpc/auth.h>
|
#include <linux/sunrpc/auth.h>
|
||||||
#include <linux/sunrpc/auth_gss.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;
|
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
|
static int
|
||||||
gss_wrap_req(struct rpc_task *task,
|
gss_wrap_req(struct rpc_task *task,
|
||||||
kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
|
kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
|
||||||
|
@ -1002,6 +1111,8 @@ gss_wrap_req(struct rpc_task *task,
|
||||||
rqstp, p, obj);
|
rqstp, p, obj);
|
||||||
break;
|
break;
|
||||||
case RPC_GSS_SVC_PRIVACY:
|
case RPC_GSS_SVC_PRIVACY:
|
||||||
|
status = gss_wrap_req_priv(cred, ctx, encode,
|
||||||
|
rqstp, p, obj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@ -1048,6 +1159,36 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||||
return 0;
|
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
|
static int
|
||||||
gss_unwrap_resp(struct rpc_task *task,
|
gss_unwrap_resp(struct rpc_task *task,
|
||||||
kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
|
kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
|
||||||
|
@ -1057,6 +1198,8 @@ gss_unwrap_resp(struct rpc_task *task,
|
||||||
gc_base);
|
gc_base);
|
||||||
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
|
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
|
||||||
u32 *savedp = p;
|
u32 *savedp = p;
|
||||||
|
struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
|
||||||
|
int savedlen = head->iov_len;
|
||||||
int status = -EIO;
|
int status = -EIO;
|
||||||
|
|
||||||
if (ctx->gc_proc != RPC_GSS_PROC_DATA)
|
if (ctx->gc_proc != RPC_GSS_PROC_DATA)
|
||||||
|
@ -1070,10 +1213,14 @@ gss_unwrap_resp(struct rpc_task *task,
|
||||||
goto out;
|
goto out;
|
||||||
break;
|
break;
|
||||||
case RPC_GSS_SVC_PRIVACY:
|
case RPC_GSS_SVC_PRIVACY:
|
||||||
|
status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* take into account extra slack for integrity and privacy cases: */
|
/* 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:
|
out_decode:
|
||||||
status = decode(rqstp, p, obj);
|
status = decode(rqstp, p, obj);
|
||||||
out:
|
out:
|
||||||
|
|
Loading…
Reference in New Issue