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: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
fb15b26f8b
commit
9568c5e9a6
|
@ -134,33 +134,38 @@ static size_t nfs_parse_server_name(char *string, size_t len,
|
||||||
return ret;
|
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)
|
rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
|
||||||
{
|
{
|
||||||
struct gss_api_mech *mech;
|
rpc_authflavor_t pseudoflavor;
|
||||||
struct xdr_netobj oid;
|
struct nfs4_secinfo4 *secinfo;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
|
|
||||||
|
|
||||||
for (i = 0; i < flavors->num_flavors; i++) {
|
for (i = 0; i < flavors->num_flavors; i++) {
|
||||||
struct nfs4_secinfo4 *flavor = &flavors->flavors[i];
|
secinfo = &flavors->flavors[i];
|
||||||
|
|
||||||
if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) {
|
switch (secinfo->flavor) {
|
||||||
pseudoflavor = flavor->flavor;
|
case RPC_AUTH_NULL:
|
||||||
break;
|
case RPC_AUTH_UNIX:
|
||||||
} else if (flavor->flavor == RPC_AUTH_GSS) {
|
case RPC_AUTH_GSS:
|
||||||
oid.len = flavor->flavor_info.oid.len;
|
pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
|
||||||
oid.data = flavor->flavor_info.oid.data;
|
&secinfo->flavor_info);
|
||||||
mech = gss_mech_get_by_OID(&oid);
|
if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
|
||||||
if (!mech)
|
return pseudoflavor;
|
||||||
continue;
|
|
||||||
pseudoflavor = gss_svc_to_pseudoflavor(mech,
|
|
||||||
flavor->flavor_info.service);
|
|
||||||
gss_mech_put(mech);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pseudoflavor;
|
return RPC_AUTH_UNIX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
|
static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name)
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
/* size of the nodename buffer */
|
/* size of the nodename buffer */
|
||||||
#define UNX_MAXNODENAME 32
|
#define UNX_MAXNODENAME 32
|
||||||
|
|
||||||
|
struct rpcsec_gss_info;
|
||||||
|
|
||||||
/* Work around the lack of a VFS credential */
|
/* Work around the lack of a VFS credential */
|
||||||
struct auth_cred {
|
struct auth_cred {
|
||||||
kuid_t uid;
|
kuid_t uid;
|
||||||
|
@ -103,6 +105,7 @@ struct rpc_authops {
|
||||||
int (*pipes_create)(struct rpc_auth *);
|
int (*pipes_create)(struct rpc_auth *);
|
||||||
void (*pipes_destroy)(struct rpc_auth *);
|
void (*pipes_destroy)(struct rpc_auth *);
|
||||||
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
|
int (*list_pseudoflavors)(rpc_authflavor_t *, int);
|
||||||
|
rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rpc_credops {
|
struct rpc_credops {
|
||||||
|
@ -137,6 +140,8 @@ int rpcauth_register(const struct rpc_authops *);
|
||||||
int rpcauth_unregister(const struct rpc_authops *);
|
int rpcauth_unregister(const struct rpc_authops *);
|
||||||
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
|
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
|
||||||
void rpcauth_release(struct rpc_auth *);
|
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);
|
int rpcauth_list_flavors(rpc_authflavor_t *, int);
|
||||||
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, 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 *);
|
void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
|
||||||
|
|
|
@ -127,9 +127,8 @@ struct gss_api_ops {
|
||||||
int gss_mech_register(struct gss_api_mech *);
|
int gss_mech_register(struct gss_api_mech *);
|
||||||
void gss_mech_unregister(struct gss_api_mech *);
|
void gss_mech_unregister(struct gss_api_mech *);
|
||||||
|
|
||||||
/* returns a mechanism descriptor given an OID, and increments the mechanism's
|
/* Given a GSS security tuple, look up a pseudoflavor */
|
||||||
* reference count. */
|
rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
|
||||||
struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
|
|
||||||
|
|
||||||
/* Returns a reference to a mechanism, given a name like "krb5" etc. */
|
/* Returns a reference to a mechanism, given a name like "krb5" etc. */
|
||||||
struct gss_api_mech *gss_mech_get_by_name(const char *);
|
struct gss_api_mech *gss_mech_get_by_name(const char *);
|
||||||
|
|
|
@ -123,6 +123,41 @@ rpcauth_unregister(const struct rpc_authops *ops)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpcauth_unregister);
|
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
|
* rpcauth_list_flavors - discover registered flavors and pseudoflavors
|
||||||
* @array: array to fill in
|
* @array: array to fill in
|
||||||
|
|
|
@ -1641,6 +1641,7 @@ static const struct rpc_authops authgss_ops = {
|
||||||
.pipes_create = gss_pipes_dentries_create,
|
.pipes_create = gss_pipes_dentries_create,
|
||||||
.pipes_destroy = gss_pipes_dentries_destroy,
|
.pipes_destroy = gss_pipes_dentries_destroy,
|
||||||
.list_pseudoflavors = gss_mech_list_pseudoflavors,
|
.list_pseudoflavors = gss_mech_list_pseudoflavors,
|
||||||
|
.info2flavor = gss_mech_info2flavor,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rpc_credops gss_credops = {
|
static const struct rpc_credops gss_credops = {
|
||||||
|
|
|
@ -171,8 +171,7 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
|
EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
|
||||||
|
|
||||||
struct gss_api_mech *
|
static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
|
||||||
gss_mech_get_by_OID(struct xdr_netobj *obj)
|
|
||||||
{
|
{
|
||||||
struct gss_api_mech *pos, *gm = NULL;
|
struct gss_api_mech *pos, *gm = NULL;
|
||||||
|
|
||||||
|
@ -188,11 +187,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
|
||||||
}
|
}
|
||||||
spin_unlock(®istered_mechs_lock);
|
spin_unlock(®istered_mechs_lock);
|
||||||
return gm;
|
return gm;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||||
{
|
{
|
||||||
|
@ -282,6 +278,28 @@ gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
|
EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
|
||||||
|
* @info: a GSS mech OID, quality of protection, and service value
|
||||||
|
*
|
||||||
|
* Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
|
||||||
|
* not supported.
|
||||||
|
*/
|
||||||
|
rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
|
||||||
|
{
|
||||||
|
rpc_authflavor_t pseudoflavor;
|
||||||
|
struct gss_api_mech *gm;
|
||||||
|
|
||||||
|
gm = gss_mech_get_by_OID(&info->oid);
|
||||||
|
if (gm == NULL)
|
||||||
|
return RPC_AUTH_MAXFLAVOR;
|
||||||
|
|
||||||
|
pseudoflavor = gss_svc_to_pseudoflavor(gm, info->service);
|
||||||
|
|
||||||
|
gss_mech_put(gm);
|
||||||
|
return pseudoflavor;
|
||||||
|
}
|
||||||
|
|
||||||
u32
|
u32
|
||||||
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
|
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue