From 9568c5e9a61de49f67f524404a27a1014a8d7f1e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:54:43 -0400 Subject: 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 Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') 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) } 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) { -- cgit From f783288f0cf47f1988f5284c89e325bd22c74f91 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:54:52 -0400 Subject: SUNRPC: Load GSS kernel module by OID The current GSS mech switch can find and load GSS pseudoflavor modules by name ("krb5") or pseudoflavor number ("390003"), but cannot find GSS modules by GSS tuple: [ "1.2.840.113554.1.2.2", GSS_C_QOP_DEFAULT, RPC_GSS_SVC_NONE ] This is important when dealing with a SECINFO request. A SECINFO reply contains a list of flavors the server supports for the requested export, but GSS flavors also have a GSS tuple that maps to a pseudoflavor (like 390003 for krb5). If the GSS module that supports the OID in the tuple is not loaded, our client is not able to load that module dynamically to support that pseudoflavor. Add a way for the GSS mech switch to load GSS pseudoflavor support by OID before searching for the pseudoflavor that matches the OID and service. Signed-off-by: Chuck Lever Cc: David Howells Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 4db66f5f490e..92a72404e6d5 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,12 @@ EXPORT_SYMBOL_GPL(gss_mech_get_by_name); static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) { struct gss_api_mech *pos, *gm = NULL; + char buf[32]; + + if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0) + return NULL; + dprintk("RPC: %s(%s)\n", __func__, buf); + request_module("rpc-auth-gss-%s", buf); spin_lock(®istered_mechs_lock); list_for_each_entry(pos, ®istered_mechs, gm_list) { -- cgit From 83523d083a045a2069e5f3443d2e4f810a6e6d9a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:55:01 -0400 Subject: SUNRPC: Consider qop when looking up pseudoflavors The NFSv4 SECINFO operation returns a list of security flavors that the server supports for a particular share. An NFSv4 client is supposed to pick a pseudoflavor it supports that corresponds to one of the flavors returned by the server. GSS flavors in this list have a GSS tuple that identify a specific GSS pseudoflavor. Currently our client ignores the GSS tuple's "qop" value. A matching pseudoflavor is chosen based only on the OID and service value. So far this omission has not had much effect on Linux. The NFSv4 protocol currently supports only one qop value: GSS_C_QOP_DEFAULT, also known as zero. However, if an NFSv4 server happens to return something other than zero in the qop field, our client won't notice. This could cause the client to behave in incorrect ways that could have security implications. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 92a72404e6d5..81fb6f3e2424 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -271,19 +271,27 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) return i; } -u32 -gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) +/** + * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor + * @gm: GSS mechanism handle + * @qop: GSS quality-of-protection value + * @service: GSS service value + * + * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found. + */ +rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop, + u32 service) { int i; for (i = 0; i < gm->gm_pf_num; i++) { - if (gm->gm_pfs[i].service == service) { + if (gm->gm_pfs[i].qop == qop && + gm->gm_pfs[i].service == service) { return gm->gm_pfs[i].pseudoflavor; } } - return RPC_AUTH_MAXFLAVOR; /* illegal value */ + return RPC_AUTH_MAXFLAVOR; } -EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); /** * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple @@ -301,7 +309,7 @@ rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info) if (gm == NULL) return RPC_AUTH_MAXFLAVOR; - pseudoflavor = gss_svc_to_pseudoflavor(gm, info->service); + pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service); gss_mech_put(gm); return pseudoflavor; -- cgit From a77c806fb9d097bb7733b64207cf52fc2c6438bb Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:55:10 -0400 Subject: SUNRPC: Refactor nfsd4_do_encode_secinfo() Clean up. This matches a similar API for the client side, and keeps ULP fingers out the of the GSS mech switch. Signed-off-by: Chuck Lever Acked-by: J. Bruce Fields Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 81fb6f3e2424..deaa7ae81cdf 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -240,8 +240,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) return gm; } -EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); - /** * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors * @array: array to fill in @@ -315,6 +313,39 @@ rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info) return pseudoflavor; } +/** + * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor + * @pseudoflavor: GSS pseudoflavor to match + * @info: rpcsec_gss_info structure to fill in + * + * Returns zero and fills in "info" if pseudoflavor matches a + * supported mechanism. Otherwise a negative errno is returned. + */ +int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor, + struct rpcsec_gss_info *info) +{ + struct gss_api_mech *gm; + int i; + + gm = gss_mech_get_by_pseudoflavor(pseudoflavor); + if (gm == NULL) + return -ENOENT; + + for (i = 0; i < gm->gm_pf_num; i++) { + if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) { + memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len); + info->oid.len = gm->gm_oid.len; + info->qop = gm->gm_pfs[i].qop; + info->service = gm->gm_pfs[i].service; + gss_mech_put(gm); + return 0; + } + } + + gss_mech_put(gm); + return -ENOENT; +} + u32 gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) { -- cgit From 6599c0acae10e929b5315821c1d064cd13fe7648 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:55:19 -0400 Subject: SUNRPC: Make gss_mech_get() static gss_mech_get() is no longer used outside of gss_mech_switch.c. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index deaa7ae81cdf..89416522ef79 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -132,15 +132,12 @@ gss_mech_unregister(struct gss_api_mech *gm) EXPORT_SYMBOL_GPL(gss_mech_unregister); -struct gss_api_mech * -gss_mech_get(struct gss_api_mech *gm) +static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) { __module_get(gm->gm_owner); return gm; } -EXPORT_SYMBOL_GPL(gss_mech_get); - static struct gss_api_mech * _gss_mech_get_by_name(const char *name) { -- cgit From 5007220b87d2ae9da1ab2025bfa35f6e2b3376f5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Sat, 16 Mar 2013 15:55:27 -0400 Subject: SUNRPC: Remove EXPORT_SYMBOL_GPL() from GSS mech switch Clean up: Reduce the symbol table footprint for auth_rpcgss.ko by removing exported symbols for functions that are no longer used outside of auth_rpcgss.ko. The remaining two EXPORTs in gss_mech_switch.c get documenting comments. Signed-off-by: Chuck Lever Signed-off-by: Trond Myklebust --- net/sunrpc/auth_gss/gss_mech_switch.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'net/sunrpc/auth_gss/gss_mech_switch.c') diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index 89416522ef79..79881d6e68a1 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c @@ -103,8 +103,13 @@ out: return status; } -int -gss_mech_register(struct gss_api_mech *gm) +/** + * gss_mech_register - register a GSS mechanism + * @gm: GSS mechanism handle + * + * Returns zero if successful, or a negative errno. + */ +int gss_mech_register(struct gss_api_mech *gm) { int status; @@ -117,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm) dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); return 0; } - EXPORT_SYMBOL_GPL(gss_mech_register); -void -gss_mech_unregister(struct gss_api_mech *gm) +/** + * gss_mech_unregister - release a GSS mechanism + * @gm: GSS mechanism handle + * + */ +void gss_mech_unregister(struct gss_api_mech *gm) { spin_lock(®istered_mechs_lock); list_del(&gm->gm_list); @@ -129,7 +137,6 @@ gss_mech_unregister(struct gss_api_mech *gm) dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); gss_mech_free(gm); } - EXPORT_SYMBOL_GPL(gss_mech_unregister); static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) @@ -167,7 +174,6 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name) } return gm; } -EXPORT_SYMBOL_GPL(gss_mech_get_by_name); static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) { @@ -355,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) return 0; } -EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service); - char * gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) { @@ -369,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) return NULL; } -EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name); - void gss_mech_put(struct gss_api_mech * gm) { @@ -378,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm) module_put(gm->gm_owner); } -EXPORT_SYMBOL_GPL(gss_mech_put); - /* The mech could probably be determined from the token instead, but it's just * as easy for now to pass it in. */ int -- cgit