aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/auth_gss/svcauth_gss.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/auth_gss/svcauth_gss.c')
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c67
1 files changed, 37 insertions, 30 deletions
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 638c0b576203b..447d9aef46051 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -903,9 +903,9 @@ out_seq:
struct gss_svc_data {
/* decoded gss client cred: */
struct rpc_gss_wire_cred clcred;
- /* pointer to the beginning of the procedure-specific results,
- * which may be encrypted/checksummed in svcauth_gss_release: */
- __be32 *body_start;
+ /* save a pointer to the beginning of the encoded verifier,
+ * for use in encryption/checksumming in svcauth_gss_release: */
+ __be32 *verf_start;
struct rsc *rsci;
};
@@ -968,7 +968,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
if (!svcdata)
goto auth_err;
rqstp->rq_auth_data = svcdata;
- svcdata->body_start = NULL;
+ svcdata->verf_start = NULL;
svcdata->rsci = NULL;
gc = &svcdata->clcred;
@@ -1097,6 +1097,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
goto complete;
case RPC_GSS_PROC_DATA:
*authp = rpcsec_gsserr_ctxproblem;
+ svcdata->verf_start = resv->iov_base + resv->iov_len;
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
rqstp->rq_cred = rsci->cred;
@@ -1110,7 +1111,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
svc_putnl(resv, 0);
svc_putnl(resv, 0);
break;
@@ -1119,7 +1119,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
svc_putnl(resv, 0);
svc_putnl(resv, 0);
break;
@@ -1147,6 +1146,32 @@ out:
return ret;
}
+u32 *
+svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
+{
+ u32 *p, verf_len;
+
+ p = gsd->verf_start;
+ gsd->verf_start = NULL;
+
+ /* If the reply stat is nonzero, don't wrap: */
+ if (*(p-1) != rpc_success)
+ return NULL;
+ /* Skip the verifier: */
+ p += 1;
+ verf_len = ntohl(*p++);
+ p += XDR_QUADLEN(verf_len);
+ /* move accept_stat to right place: */
+ memcpy(p, p + 2, 4);
+ /* Also don't wrap if the accept stat is nonzero: */
+ if (*p != rpc_success) {
+ resbuf->head[0].iov_len -= 2 * 4;
+ return NULL;
+ }
+ p++;
+ return p;
+}
+
static inline int
svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
{
@@ -1160,17 +1185,9 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
int integ_offset, integ_len;
int stat = -EINVAL;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
goto out;
- }
- p++;
integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
integ_len = resbuf->len - integ_offset;
BUG_ON(integ_len % 4);
@@ -1191,7 +1208,6 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
resv = &resbuf->tail[0];
} else {
resv = &resbuf->tail[0];
@@ -1223,24 +1239,16 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
int offset;
int pad;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
return 0;
- }
- p++;
len = p++;
offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
*p++ = htonl(gc->gc_seq);
inpages = resbuf->pages;
/* XXX: Would be better to write some xdr helper functions for
* nfs{2,3,4}xdr.c that place the data right, instead of copying: */
- if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
+ if (resbuf->tail[0].iov_base) {
BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ PAGE_SIZE);
BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
@@ -1258,7 +1266,6 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
}
if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
return -ENOMEM;
@@ -1282,7 +1289,7 @@ svcauth_gss_release(struct svc_rqst *rqstp)
if (gc->gc_proc != RPC_GSS_PROC_DATA)
goto out;
/* Release can be called twice, but we only wrap once. */
- if (gsd->body_start == NULL)
+ if (gsd->verf_start == NULL)
goto out;
/* normally not set till svc_send, but we need it here: */
/* XXX: what for? Do we mess it up the moment we call svc_putu32