From patchwork Mon Feb 4 20:19:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuck Lever X-Patchwork-Id: 2095041 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id D9B413FD56 for ; Mon, 4 Feb 2013 20:19:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754689Ab3BDUTd (ORCPT ); Mon, 4 Feb 2013 15:19:33 -0500 Received: from mail-ia0-f177.google.com ([209.85.210.177]:35851 "EHLO mail-ia0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754500Ab3BDUTc (ORCPT ); Mon, 4 Feb 2013 15:19:32 -0500 Received: by mail-ia0-f177.google.com with SMTP id h8so8630336iaa.36 for ; Mon, 04 Feb 2013 12:19:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=x-received:sender:from:subject:to:cc:date:message-id:in-reply-to :references:user-agent:mime-version:content-type :content-transfer-encoding; bh=aXltZ3kB/ZwJGbAg1fdI+V3EsYUM0/gkuJyVZWVX9qU=; b=L6HXyOM7fCXqlys8oSF93ysoezve+hOcpbg5cZVvE4LjGRdmLsXMDqOA/0WRVvNP0O MmcGT6Wcfde0BAmt+cX/L/IXtiEiuS1090zwjTFnZzKQfMf21HnJtWsS0wpthPDvJb/G r2LK5hHKSVpJUDJaXann2uUbAGfW36VEdkLKDAVvTtn1fmaDQCBpXrkiy5ah8T3ED211 j3KiyJOZDkI9Kd34FljYNV5/tMwoC6k5S0Jir87mBriUZFBD91p9xiR6KwYFS4kSIDxp s31OlgVwEn3ixvcqN/+oXc6LfB33tQotyqJ+/Wqf1wc3aKXl4rIOwBvf0Ty9r3qEl6yw 23Ag== X-Received: by 10.50.57.164 with SMTP id j4mr8762057igq.91.1360009172234; Mon, 04 Feb 2013 12:19:32 -0800 (PST) Received: from seurat.1015granger.net (adsl-99-26-161-222.dsl.sfldmi.sbcglobal.net. [99.26.161.222]) by mx.google.com with ESMTPS id ww6sm16548030igb.2.2013.02.04.12.19.31 (version=TLSv1 cipher=RC4-SHA bits=128/128); Mon, 04 Feb 2013 12:19:31 -0800 (PST) From: Chuck Lever Subject: [PATCH v3 4/9] SUNRPC: Introduce rpcauth_get_pseudoflavor() To: trond.myklebust@netapp.com Cc: linux-nfs@vger.kernel.org Date: Mon, 04 Feb 2013 15:19:30 -0500 Message-ID: <20130204201930.1518.29020.stgit@seurat.1015granger.net> In-Reply-To: <20130204201458.1518.12931.stgit@seurat.1015granger.net> References: <20130204201458.1518.12931.stgit@seurat.1015granger.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org nfs_find_best_sec() now verifies all flavors requested in a SECINFO reply against those that have been explicitly registered via rpcauth_register(). For GSS pseudoflavors, these are verified against the list of GSS pseudoflavors registered via gss_mech_register(). Note that the current version of nfs_find_best_sec() can return RPC_AUTH_MAXFLAVOR if the server returns a recognized OID but an unsupported "service" value. The new code returns RPC_AUTH_UNIX in this case. Signed-off-by: Chuck Lever --- fs/nfs/nfs4namespace.c | 41 +++++++++++++++++++-------------- include/linux/sunrpc/auth.h | 4 +++ include/linux/sunrpc/gss_api.h | 5 ++-- net/sunrpc/auth.c | 34 +++++++++++++++++++++++++++ net/sunrpc/auth_gss/auth_gss.c | 1 + net/sunrpc/auth_gss/gss_mech_switch.c | 28 +++++++++++++++++++---- 6 files changed, 87 insertions(+), 26 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index f97b0a8..2187ae7 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -133,33 +133,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) diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index f25ba92..476e97c 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h @@ -21,6 +21,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 { uid_t uid; @@ -102,6 +104,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 { @@ -136,6 +139,7 @@ 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 98950e5..aba7687 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 b5c067b..ec18827 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c @@ -124,6 +124,40 @@ 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; + + if ((ops = auth_flavors[flavor]) == 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 4db065d..4522297 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1629,6 +1629,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 b174fcd..b09f25b 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) {