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

Commit 9568c5e9 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

SUNRPC: Introduce rpcauth_get_pseudoflavor()



A SECINFO reply may contain flavors whose kernel module is not
yet loaded by the client's kernel.  A new RPC client API, called
rpcauth_get_pseudoflavor(), is introduced to do proper checking
for support of a security flavor.

When this API is invoked, the RPC client now tries to load the
module for each flavor first before performing the "is this
supported?" check.  This means if a module is available on the
client, but has not been loaded yet, it will be loaded and
registered automatically when the SECINFO reply is processed.

The new API can take a full GSS tuple (OID, QoP, and service).
Previously only the OID and service were considered.

nfs_find_best_sec() is updated to verify all flavors requested in a
SECINFO reply, including AUTH_NULL and AUTH_UNIX.  Previously these
two flavors were simply assumed to be supported without consulting
the RPC client.

Note that the replaced version of nfs_find_best_sec() can return
RPC_AUTH_MAXFLAVOR if the server returns a recognized OID but an
unsupported "service" value.  nfs_find_best_sec() now returns
RPC_AUTH_UNIX in this case.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent fb15b26f
Loading
Loading
Loading
Loading
+23 −18
Original line number Diff line number Diff line
@@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
	return ret;
}

/**
 * nfs_find_best_sec - Find a security mechanism supported locally
 * @flavors: List of security tuples returned by SECINFO procedure
 *
 * Return the pseudoflavor of the first security mechanism in
 * "flavors" that is locally supported.  Return RPC_AUTH_UNIX if
 * no matching flavor is found in the array.  The "flavors" array
 * is searched in the order returned from the server, per RFC 3530
 * recommendation.
 */
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
{
	struct gss_api_mech *mech;
	struct xdr_netobj oid;
	rpc_authflavor_t pseudoflavor;
	struct nfs4_secinfo4 *secinfo;
	unsigned int i;
	rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;

	for (i = 0; i < flavors->num_flavors; i++) {
		struct nfs4_secinfo4 *flavor = &flavors->flavors[i];

		if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
			pseudoflavor = flavor->flavor;
			break;
		} else if (flavor->flavor == RPC_AUTH_GSS) {
			oid.len  = flavor->flavor_info.oid.len;
			oid.data = flavor->flavor_info.oid.data;
			mech = gss_mech_get_by_OID(&oid);
			if (!mech)
				continue;
			pseudoflavor = gss_svc_to_pseudoflavor(mech,
						flavor->flavor_info.service);
			gss_mech_put(mech);
		secinfo = &flavors->flavors[i];

		switch (secinfo->flavor) {
		case RPC_AUTH_NULL:
		case RPC_AUTH_UNIX:
		case RPC_AUTH_GSS:
			pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
							&secinfo->flavor_info);
			if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
				return pseudoflavor;
			break;
		}
	}

	return pseudoflavor;
	return RPC_AUTH_UNIX;
}

static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
+5 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
/* size of the nodename buffer */
#define UNX_MAXNODENAME	32

struct rpcsec_gss_info;

/* Work around the lack of a VFS credential */
struct auth_cred {
	kuid_t	uid;
@@ -103,6 +105,7 @@ struct rpc_authops {
	int			(*pipes_create)(struct rpc_auth *);
	void			(*pipes_destroy)(struct rpc_auth *);
	int			(*list_pseudoflavors)(rpc_authflavor_t *, int);
	rpc_authflavor_t	(*info2flavor)(struct rpcsec_gss_info *);
};

struct rpc_credops {
@@ -137,6 +140,8 @@ int rpcauth_register(const struct rpc_authops *);
int			rpcauth_unregister(const struct rpc_authops *);
struct rpc_auth *	rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
void			rpcauth_release(struct rpc_auth *);
rpc_authflavor_t	rpcauth_get_pseudoflavor(rpc_authflavor_t,
				struct rpcsec_gss_info *);
int			rpcauth_list_flavors(rpc_authflavor_t *, int);
struct rpc_cred *	rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
void			rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
+2 −3
Original line number Diff line number Diff line
@@ -127,9 +127,8 @@ struct gss_api_ops {
int gss_mech_register(struct gss_api_mech *);
void gss_mech_unregister(struct gss_api_mech *);

/* returns a mechanism descriptor given an OID, and increments the mechanism's
 * reference count. */
struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
/* Given a GSS security tuple, look up a pseudoflavor */
rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);

/* Returns a reference to a mechanism, given a name like "krb5" etc. */
struct gss_api_mech *gss_mech_get_by_name(const char *);
+35 −0
Original line number Diff line number Diff line
@@ -123,6 +123,41 @@ rpcauth_unregister(const struct rpc_authops *ops)
}
EXPORT_SYMBOL_GPL(rpcauth_unregister);

/**
 * rpcauth_get_pseudoflavor - check if security flavor is supported
 * @flavor: a security flavor
 * @info: a GSS mech OID, quality of protection, and service value
 *
 * Verifies that an appropriate kernel module is available or already loaded.
 * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
 * not supported locally.
 */
rpc_authflavor_t
rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
{
	const struct rpc_authops *ops;
	rpc_authflavor_t pseudoflavor;

	ops = auth_flavors[flavor];
	if (ops == NULL)
		request_module("rpc-auth-%u", flavor);
	spin_lock(&rpc_authflavor_lock);
	ops = auth_flavors[flavor];
	if (ops == NULL || !try_module_get(ops->owner)) {
		spin_unlock(&rpc_authflavor_lock);
		return RPC_AUTH_MAXFLAVOR;
	}
	spin_unlock(&rpc_authflavor_lock);

	pseudoflavor = flavor;
	if (ops->info2flavor != NULL)
		pseudoflavor = ops->info2flavor(info);

	module_put(ops->owner);
	return pseudoflavor;
}
EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);

/**
 * rpcauth_list_flavors - discover registered flavors and pseudoflavors
 * @array: array to fill in
+1 −0
Original line number Diff line number Diff line
@@ -1641,6 +1641,7 @@ static const struct rpc_authops authgss_ops = {
	.pipes_create	= gss_pipes_dentries_create,
	.pipes_destroy	= gss_pipes_dentries_destroy,
	.list_pseudoflavors = gss_mech_list_pseudoflavors,
	.info2flavor	= gss_mech_info2flavor,
};

static const struct rpc_credops gss_credops = {
Loading