aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2013-03-16 15:54:43 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-29 15:43:07 -0400
commit9568c5e9a61de49f67f524404a27a1014a8d7f1e (patch)
tree5bc8c5496bae61b6e5dfac11e620f7aef18a58b6
parentfb15b26f8ba3ff629a052faf3f4a4744585ca2dc (diff)
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>
-rw-r--r--fs/nfs/nfs4namespace.c41
-rw-r--r--include/linux/sunrpc/auth.h5
-rw-r--r--include/linux/sunrpc/gss_api.h5
-rw-r--r--net/sunrpc/auth.c35
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c1
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c28
6 files changed, 89 insertions, 26 deletions
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 88231c92317c..cdb0b41a4810 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,
134 return ret; 134 return ret;
135} 135}
136 136
137/**
138 * nfs_find_best_sec - Find a security mechanism supported locally
139 * @flavors: List of security tuples returned by SECINFO procedure
140 *
141 * Return the pseudoflavor of the first security mechanism in
142 * "flavors" that is locally supported. Return RPC_AUTH_UNIX if
143 * no matching flavor is found in the array. The "flavors" array
144 * is searched in the order returned from the server, per RFC 3530
145 * recommendation.
146 */
137rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) 147rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors)
138{ 148{
139 struct gss_api_mech *mech; 149 rpc_authflavor_t pseudoflavor;
140 struct xdr_netobj oid; 150 struct nfs4_secinfo4 *secinfo;
141 unsigned int i; 151 unsigned int i;
142 rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
143 152
144 for (i = 0; i < flavors->num_flavors; i++) { 153 for (i = 0; i < flavors->num_flavors; i++) {
145 struct nfs4_secinfo4 *flavor = &flavors->flavors[i]; 154 secinfo = &flavors->flavors[i];
146 155
147 if (flavor->flavor == RPC_AUTH_NULL || flavor->flavor == RPC_AUTH_UNIX) { 156 switch (secinfo->flavor) {
148 pseudoflavor = flavor->flavor; 157 case RPC_AUTH_NULL:
149 break; 158 case RPC_AUTH_UNIX:
150 } else if (flavor->flavor == RPC_AUTH_GSS) { 159 case RPC_AUTH_GSS:
151 oid.len = flavor->flavor_info.oid.len; 160 pseudoflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
152 oid.data = flavor->flavor_info.oid.data; 161 &secinfo->flavor_info);
153 mech = gss_mech_get_by_OID(&oid); 162 if (pseudoflavor != RPC_AUTH_MAXFLAVOR)
154 if (!mech) 163 return pseudoflavor;
155 continue;
156 pseudoflavor = gss_svc_to_pseudoflavor(mech,
157 flavor->flavor_info.service);
158 gss_mech_put(mech);
159 break; 164 break;
160 } 165 }
161 } 166 }
162 167
163 return pseudoflavor; 168 return RPC_AUTH_UNIX;
164} 169}
165 170
166static rpc_authflavor_t nfs4_negotiate_security(struct inode *inode, struct qstr *name) 171static 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 58fda1c3c783..6851da4cb416 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -22,6 +22,8 @@
22/* size of the nodename buffer */ 22/* size of the nodename buffer */
23#define UNX_MAXNODENAME 32 23#define UNX_MAXNODENAME 32
24 24
25struct rpcsec_gss_info;
26
25/* Work around the lack of a VFS credential */ 27/* Work around the lack of a VFS credential */
26struct auth_cred { 28struct auth_cred {
27 kuid_t uid; 29 kuid_t uid;
@@ -103,6 +105,7 @@ struct rpc_authops {
103 int (*pipes_create)(struct rpc_auth *); 105 int (*pipes_create)(struct rpc_auth *);
104 void (*pipes_destroy)(struct rpc_auth *); 106 void (*pipes_destroy)(struct rpc_auth *);
105 int (*list_pseudoflavors)(rpc_authflavor_t *, int); 107 int (*list_pseudoflavors)(rpc_authflavor_t *, int);
108 rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *);
106}; 109};
107 110
108struct rpc_credops { 111struct rpc_credops {
@@ -137,6 +140,8 @@ int rpcauth_register(const struct rpc_authops *);
137int rpcauth_unregister(const struct rpc_authops *); 140int rpcauth_unregister(const struct rpc_authops *);
138struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *); 141struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
139void rpcauth_release(struct rpc_auth *); 142void rpcauth_release(struct rpc_auth *);
143rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
144 struct rpcsec_gss_info *);
140int rpcauth_list_flavors(rpc_authflavor_t *, int); 145int rpcauth_list_flavors(rpc_authflavor_t *, int);
141struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int); 146struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
142void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); 147void 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 98950e5a8877..aba7687ca884 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -127,9 +127,8 @@ struct gss_api_ops {
127int gss_mech_register(struct gss_api_mech *); 127int gss_mech_register(struct gss_api_mech *);
128void gss_mech_unregister(struct gss_api_mech *); 128void gss_mech_unregister(struct gss_api_mech *);
129 129
130/* returns a mechanism descriptor given an OID, and increments the mechanism's 130/* Given a GSS security tuple, look up a pseudoflavor */
131 * reference count. */ 131rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *);
132struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
133 132
134/* Returns a reference to a mechanism, given a name like "krb5" etc. */ 133/* Returns a reference to a mechanism, given a name like "krb5" etc. */
135struct gss_api_mech *gss_mech_get_by_name(const char *); 134struct gss_api_mech *gss_mech_get_by_name(const char *);
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index f5294047df77..9b81be8d9946 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -124,6 +124,41 @@ rpcauth_unregister(const struct rpc_authops *ops)
124EXPORT_SYMBOL_GPL(rpcauth_unregister); 124EXPORT_SYMBOL_GPL(rpcauth_unregister);
125 125
126/** 126/**
127 * rpcauth_get_pseudoflavor - check if security flavor is supported
128 * @flavor: a security flavor
129 * @info: a GSS mech OID, quality of protection, and service value
130 *
131 * Verifies that an appropriate kernel module is available or already loaded.
132 * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is
133 * not supported locally.
134 */
135rpc_authflavor_t
136rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info)
137{
138 const struct rpc_authops *ops;
139 rpc_authflavor_t pseudoflavor;
140
141 ops = auth_flavors[flavor];
142 if (ops == NULL)
143 request_module("rpc-auth-%u", flavor);
144 spin_lock(&rpc_authflavor_lock);
145 ops = auth_flavors[flavor];
146 if (ops == NULL || !try_module_get(ops->owner)) {
147 spin_unlock(&rpc_authflavor_lock);
148 return RPC_AUTH_MAXFLAVOR;
149 }
150 spin_unlock(&rpc_authflavor_lock);
151
152 pseudoflavor = flavor;
153 if (ops->info2flavor != NULL)
154 pseudoflavor = ops->info2flavor(info);
155
156 module_put(ops->owner);
157 return pseudoflavor;
158}
159EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor);
160
161/**
127 * rpcauth_list_flavors - discover registered flavors and pseudoflavors 162 * rpcauth_list_flavors - discover registered flavors and pseudoflavors
128 * @array: array to fill in 163 * @array: array to fill in
129 * @size: size of "array" 164 * @size: size of "array"
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 282dfb14db05..a7420076ef39 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 = {
1641 .pipes_create = gss_pipes_dentries_create, 1641 .pipes_create = gss_pipes_dentries_create,
1642 .pipes_destroy = gss_pipes_dentries_destroy, 1642 .pipes_destroy = gss_pipes_dentries_destroy,
1643 .list_pseudoflavors = gss_mech_list_pseudoflavors, 1643 .list_pseudoflavors = gss_mech_list_pseudoflavors,
1644 .info2flavor = gss_mech_info2flavor,
1644}; 1645};
1645 1646
1646static const struct rpc_credops gss_credops = { 1647static 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 f0f4eee63a35..4db66f5f490e 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)
171} 171}
172EXPORT_SYMBOL_GPL(gss_mech_get_by_name); 172EXPORT_SYMBOL_GPL(gss_mech_get_by_name);
173 173
174struct gss_api_mech * 174static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
175gss_mech_get_by_OID(struct xdr_netobj *obj)
176{ 175{
177 struct gss_api_mech *pos, *gm = NULL; 176 struct gss_api_mech *pos, *gm = NULL;
178 177
@@ -188,11 +187,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj)
188 } 187 }
189 spin_unlock(&registered_mechs_lock); 188 spin_unlock(&registered_mechs_lock);
190 return gm; 189 return gm;
191
192} 190}
193 191
194EXPORT_SYMBOL_GPL(gss_mech_get_by_OID);
195
196static inline int 192static inline int
197mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) 193mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor)
198{ 194{
@@ -282,6 +278,28 @@ gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
282} 278}
283EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); 279EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor);
284 280
281/**
282 * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple
283 * @info: a GSS mech OID, quality of protection, and service value
284 *
285 * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is
286 * not supported.
287 */
288rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info)
289{
290 rpc_authflavor_t pseudoflavor;
291 struct gss_api_mech *gm;
292
293 gm = gss_mech_get_by_OID(&info->oid);
294 if (gm == NULL)
295 return RPC_AUTH_MAXFLAVOR;
296
297 pseudoflavor = gss_svc_to_pseudoflavor(gm, info->service);
298
299 gss_mech_put(gm);
300 return pseudoflavor;
301}
302
285u32 303u32
286gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) 304gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
287{ 305{