Commit 1a994408 authored by Chuck Lever's avatar Chuck Lever
Browse files

NFSD: Replace READ* macros in nfsd4_decode_cb_sec()

parent a4a80c15
Loading
Loading
Loading
Loading
+107 −58
Original line number Diff line number Diff line
@@ -212,6 +212,25 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
 * NFSv4 basic data type decoders
 */

/*
 * This helper handles variable-length opaques which belong to protocol
 * elements that this implementation does not support.
 */
static __be32
nfsd4_decode_ignored_string(struct nfsd4_compoundargs *argp, u32 maxlen)
{
	u32 len;

	if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
		return nfserr_bad_xdr;
	if (maxlen && len > maxlen)
		return nfserr_bad_xdr;
	if (!xdr_inline_decode(argp->xdr, len))
		return nfserr_bad_xdr;

	return nfs_ok;
}

static __be32
nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
{
@@ -645,87 +664,117 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp,
	return nfsd4_decode_opaque(argp, owner);
}

static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
/* Defined in Appendix A of RFC 5531 */
static __be32
nfsd4_decode_authsys_parms(struct nfsd4_compoundargs *argp,
			   struct nfsd4_cb_sec *cbs)
{
	DECODE_HEAD;
	u32 stamp, gidcount, uid, gid;
	__be32 *p, status;

	if (xdr_stream_decode_u32(argp->xdr, &stamp) < 0)
		return nfserr_bad_xdr;
	/* machine name */
	status = nfsd4_decode_ignored_string(argp, 255);
	if (status)
		return status;
	if (xdr_stream_decode_u32(argp->xdr, &uid) < 0)
		return nfserr_bad_xdr;
	if (xdr_stream_decode_u32(argp->xdr, &gid) < 0)
		return nfserr_bad_xdr;
	if (xdr_stream_decode_u32(argp->xdr, &gidcount) < 0)
		return nfserr_bad_xdr;
	if (gidcount > 16)
		return nfserr_bad_xdr;
	p = xdr_inline_decode(argp->xdr, gidcount << 2);
	if (!p)
		return nfserr_bad_xdr;
	if (cbs->flavor == (u32)(-1)) {
		struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
	u32 dummy, uid, gid;
	char *machine_name;
	int i;
	int nr_secflavs;

		kuid_t kuid = make_kuid(userns, uid);
		kgid_t kgid = make_kgid(userns, gid);
		if (uid_valid(kuid) && gid_valid(kgid)) {
			cbs->uid = kuid;
			cbs->gid = kgid;
			cbs->flavor = RPC_AUTH_UNIX;
		} else {
			dprintk("RPC_AUTH_UNIX with invalid uid or gid, ignoring!\n");
		}
	}

	return nfs_ok;
}

static __be32
nfsd4_decode_gss_cb_handles4(struct nfsd4_compoundargs *argp,
			     struct nfsd4_cb_sec *cbs)
{
	__be32 status;
	u32 service;

	dprintk("RPC_AUTH_GSS callback secflavor not supported!\n");

	if (xdr_stream_decode_u32(argp->xdr, &service) < 0)
		return nfserr_bad_xdr;
	if (service < RPC_GSS_SVC_NONE || service > RPC_GSS_SVC_PRIVACY)
		return nfserr_bad_xdr;
	/* gcbp_handle_from_server */
	status = nfsd4_decode_ignored_string(argp, 0);
	if (status)
		return status;
	/* gcbp_handle_from_client */
	status = nfsd4_decode_ignored_string(argp, 0);
	if (status)
		return status;

	return nfs_ok;
}

/* a counted array of callback_sec_parms4 items */
static __be32
nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
{
	u32 i, secflavor, nr_secflavs;
	__be32 status;

	/* callback_sec_params4 */
	READ_BUF(4);
	nr_secflavs = be32_to_cpup(p++);
	if (xdr_stream_decode_u32(argp->xdr, &nr_secflavs) < 0)
		return nfserr_bad_xdr;
	if (nr_secflavs)
		cbs->flavor = (u32)(-1);
	else
		/* Is this legal? Be generous, take it to mean AUTH_NONE: */
		cbs->flavor = 0;

	for (i = 0; i < nr_secflavs; ++i) {
		READ_BUF(4);
		dummy = be32_to_cpup(p++);
		switch (dummy) {
		if (xdr_stream_decode_u32(argp->xdr, &secflavor) < 0)
			return nfserr_bad_xdr;
		switch (secflavor) {
		case RPC_AUTH_NULL:
			/* Nothing to read */
			/* void */
			if (cbs->flavor == (u32)(-1))
				cbs->flavor = RPC_AUTH_NULL;
			break;
		case RPC_AUTH_UNIX:
			READ_BUF(8);
			/* stamp */
			dummy = be32_to_cpup(p++);

			/* machine name */
			dummy = be32_to_cpup(p++);
			READ_BUF(dummy);
			SAVEMEM(machine_name, dummy);

			/* uid, gid */
			READ_BUF(8);
			uid = be32_to_cpup(p++);
			gid = be32_to_cpup(p++);

			/* more gids */
			READ_BUF(4);
			dummy = be32_to_cpup(p++);
			READ_BUF(dummy * 4);
			if (cbs->flavor == (u32)(-1)) {
				kuid_t kuid = make_kuid(userns, uid);
				kgid_t kgid = make_kgid(userns, gid);
				if (uid_valid(kuid) && gid_valid(kgid)) {
					cbs->uid = kuid;
					cbs->gid = kgid;
					cbs->flavor = RPC_AUTH_UNIX;
				} else {
					dprintk("RPC_AUTH_UNIX with invalid"
						"uid or gid ignoring!\n");
				}
			}
			status = nfsd4_decode_authsys_parms(argp, cbs);
			if (status)
				return status;
			break;
		case RPC_AUTH_GSS:
			dprintk("RPC_AUTH_GSS callback secflavor "
				"not supported!\n");
			READ_BUF(8);
			/* gcbp_service */
			dummy = be32_to_cpup(p++);
			/* gcbp_handle_from_server */
			dummy = be32_to_cpup(p++);
			READ_BUF(dummy);
			p += XDR_QUADLEN(dummy);
			/* gcbp_handle_from_client */
			READ_BUF(4);
			dummy = be32_to_cpup(p++);
			READ_BUF(dummy);
			status = nfsd4_decode_gss_cb_handles4(argp, cbs);
			if (status)
				return status;
			break;
		default:
			dprintk("Illegal callback secflavor\n");
			return nfserr_inval;
		}
	}
	DECODE_TAIL;

	return nfs_ok;
}


/*
 * NFSv4 operation argument decoders
 */