Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc2952a2 authored by Simo Sorce's avatar Simo Sorce Committed by J. Bruce Fields
Browse files

SUNRPC: split upcall function to extract reusable parts



This is needed to share code between the current server upcall mechanism
and the new gssproxy upcall mechanism introduced in a following patch.

Signed-off-by: default avatarSimo Sorce <simo@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent f69adb2f
Loading
Loading
Loading
Loading
+64 −36
Original line number Diff line number Diff line
@@ -964,16 +964,17 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
}

static inline int
gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi *rsip)
gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
		struct xdr_netobj *out_handle, int *major_status)
{
	struct rsc *rsci;
	int        rc;

	if (rsip->major_status != GSS_S_COMPLETE)
	if (*major_status != GSS_S_COMPLETE)
		return gss_write_null_verf(rqstp);
	rsci = gss_svc_searchbyctx(cd, &rsip->out_handle);
	rsci = gss_svc_searchbyctx(cd, out_handle);
	if (rsci == NULL) {
		rsip->major_status = GSS_S_NO_CONTEXT;
		*major_status = GSS_S_NO_CONTEXT;
		return gss_write_null_verf(rqstp);
	}
	rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
@@ -981,22 +982,13 @@ gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp, struct rsi
	return rc;
}

/*
 * Having read the cred already and found we're in the context
 * initiation case, read the verifier and initiate (or check the results
 * of) upcalls to userspace for help with context initiation.  If
 * the upcall results are available, write the verifier and result.
 * Otherwise, drop the request pending an answer to the upcall.
 */
static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
			struct rpc_gss_wire_cred *gc, __be32 *authp)
static inline int
gss_read_verf(struct rpc_gss_wire_cred *gc,
	      struct kvec *argv, __be32 *authp,
	      struct xdr_netobj *in_handle,
	      struct xdr_netobj *in_token)
{
	struct kvec *argv = &rqstp->rq_arg.head[0];
	struct kvec *resv = &rqstp->rq_res.head[0];
	struct xdr_netobj tmpobj;
	struct rsi *rsip, rsikey;
	int ret;
	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);

	/* Read the verifier; should be NULL: */
	*authp = rpc_autherr_badverf;
@@ -1006,24 +998,67 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
		return SVC_DENIED;
	if (svc_getnl(argv) != 0)
		return SVC_DENIED;

	/* Martial context handle and token for upcall: */
	*authp = rpc_autherr_badcred;
	if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
		return SVC_DENIED;
	memset(&rsikey, 0, sizeof(rsikey));
	if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
	if (dup_netobj(in_handle, &gc->gc_ctx))
		return SVC_CLOSE;
	*authp = rpc_autherr_badverf;
	if (svc_safe_getnetobj(argv, &tmpobj)) {
		kfree(rsikey.in_handle.data);
		kfree(in_handle->data);
		return SVC_DENIED;
	}
	if (dup_netobj(&rsikey.in_token, &tmpobj)) {
		kfree(rsikey.in_handle.data);
	if (dup_netobj(in_token, &tmpobj)) {
		kfree(in_handle->data);
		return SVC_CLOSE;
	}

	return 0;
}

static inline int
gss_write_resv(struct kvec *resv, size_t size_limit,
	       struct xdr_netobj *out_handle, struct xdr_netobj *out_token,
	       int major_status, int minor_status)
{
	if (resv->iov_len + 4 > size_limit)
		return -1;
	svc_putnl(resv, RPC_SUCCESS);
	if (svc_safe_putnetobj(resv, out_handle))
		return -1;
	if (resv->iov_len + 3 * 4 > size_limit)
		return -1;
	svc_putnl(resv, major_status);
	svc_putnl(resv, minor_status);
	svc_putnl(resv, GSS_SEQ_WIN);
	if (svc_safe_putnetobj(resv, out_token))
		return -1;
	return 0;
}

/*
 * Having read the cred already and found we're in the context
 * initiation case, read the verifier and initiate (or check the results
 * of) upcalls to userspace for help with context initiation.  If
 * the upcall results are available, write the verifier and result.
 * Otherwise, drop the request pending an answer to the upcall.
 */
static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
			struct rpc_gss_wire_cred *gc, __be32 *authp)
{
	struct kvec *argv = &rqstp->rq_arg.head[0];
	struct kvec *resv = &rqstp->rq_res.head[0];
	struct rsi *rsip, rsikey;
	int ret;
	struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net, sunrpc_net_id);

	memset(&rsikey, 0, sizeof(rsikey));
	ret = gss_read_verf(gc, argv, authp,
			    &rsikey.in_handle, &rsikey.in_token);
	if (ret)
		return ret;

	/* Perform upcall, or find upcall result: */
	rsip = rsi_lookup(sn->rsi_cache, &rsikey);
	rsi_free(&rsikey);
@@ -1035,19 +1070,12 @@ static int svcauth_gss_handle_init(struct svc_rqst *rqstp,

	ret = SVC_CLOSE;
	/* Got an answer to the upcall; use it: */
	if (gss_write_init_verf(sn->rsc_cache, rqstp, rsip))
		goto out;
	if (resv->iov_len + 4 > PAGE_SIZE)
	if (gss_write_init_verf(sn->rsc_cache, rqstp,
				&rsip->out_handle, &rsip->major_status))
		goto out;
	svc_putnl(resv, RPC_SUCCESS);
	if (svc_safe_putnetobj(resv, &rsip->out_handle))
		goto out;
	if (resv->iov_len + 3 * 4 > PAGE_SIZE)
		goto out;
	svc_putnl(resv, rsip->major_status);
	svc_putnl(resv, rsip->minor_status);
	svc_putnl(resv, GSS_SEQ_WIN);
	if (svc_safe_putnetobj(resv, &rsip->out_token))
	if (gss_write_resv(resv, PAGE_SIZE,
			   &rsip->out_handle, &rsip->out_token,
			   rsip->major_status, rsip->minor_status))
		goto out;

	ret = SVC_COMPLETE;