diff options
| -rw-r--r-- | fs/nfs/nfs4namespace.c | 39 | ||||
| -rw-r--r-- | include/linux/sunrpc/auth.h | 5 | ||||
| -rw-r--r-- | include/linux/sunrpc/gss_api.h | 5 | ||||
| -rw-r--r-- | net/sunrpc/auth.c | 35 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 1 | ||||
| -rw-r--r-- | net/sunrpc/auth_gss/gss_mech_switch.c | 28 | 
6 files changed, 88 insertions, 25 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 88231c92317..cdb0b41a481 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -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]; +		secinfo = &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); +		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) diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 58fda1c3c78..6851da4cb41 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -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 *); diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h index 98950e5a887..aba7687ca88 100644 --- a/include/linux/sunrpc/gss_api.h +++ b/include/linux/sunrpc/gss_api.h @@ -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 *); diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f5294047df7..9b81be8d994 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -124,6 +124,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   * @size: size of "array" diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 282dfb14db0..a7420076ef3 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -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 = { diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index f0f4eee63a3..4db66f5f490 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -171,8 +171,7 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)  }  EXPORT_SYMBOL_GPL(gss_mech_get_by_name); -struct gss_api_mech * -gss_mech_get_by_OID(struct xdr_netobj *obj) +static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)  {  	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);  	return gm; -  } -EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); -  static inline int  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); +/** + * 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  gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)  {  |