diff mbox

[11/11] fedfsd: Use GSS callbacks for access control

Message ID 20150708182741.24274.1934.stgit@seurat.1015granger.net
State Accepted
Headers show

Commit Message

Chuck Lever July 8, 2015, 6:27 p.m. UTC
Use a GSS callback to verify a client is using a permitted service
and mechanism. fedfsd can now reject requests that do not have an
appropriately high service level (say, at least "integrity") before
even looking at the incoming principal.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 src/fedfsd/access.c |  125 ++++++++++++++++++++++++++++++++++-----------------
 src/fedfsd/fedfsd.h |    3 -
 src/fedfsd/gss.c    |   58 ++++++++++++++----------
 src/fedfsd/svc.c    |    2 -
 4 files changed, 120 insertions(+), 68 deletions(-)
diff mbox

Patch

diff --git a/src/fedfsd/access.c b/src/fedfsd/access.c
index ffee857..92f7976 100644
--- a/src/fedfsd/access.c
+++ b/src/fedfsd/access.c
@@ -36,6 +36,7 @@ 
 #include <linux/limits.h>
 #include <rpc/auth.h>
 #include <rpc/auth_unix.h>
+#include <rpc/rpcsec_gss.h>
 #include <libconfig.h>
 
 #include "fedfs.h"
@@ -473,57 +474,75 @@  fedfsd_auth_unix(struct svc_req *rqstp)
  *
  * @param setting config setting containing a list
  * @param i index of list element to check
- * @param caller NUL-terminated C string containing principal to check
+ * @param caller C string containing principal to check
+ * @param len length of "caller" in bytes
  * @return true if "caller" matches the list element at "i"
  */
 static _Bool
-fedfsd_check_list(config_setting_t *setting, int i, const char *caller)
+fedfsd_check_list(config_setting_t *setting, int i, const char *caller, int len)
 {
 	const char *name;
 
 	name = config_setting_get_string_elem(setting, i);
 	if (name == NULL)
 		return false;
-	return strcasecmp(name, caller) == 0;
+	return strncasecmp(name, caller, len) == 0;
 }
 
-/*
- * Decide if an RPCSEC_GSS Kerberos v5 principal is authorized
+/**
+ * Decide if an RPCSEC_GSS context may be established
  *
- * @param rqstp incoming RPC request
- * @return true if access is authorized
+ * @param rcred raw RPC GSS credential
+ * @result true if credential is authorized
+ *
+ * The only supported mechanism today is Kerberos 5.
  */
-static _Bool
-fedfsd_auth_rpc_gss_krb5_principal(struct svc_req *rqstp)
+_Bool
+fedfsd_auth_rpc_gss_allowed(rpc_gss_rawcred_t *rcred)
 {
-	config_setting_t *principals;
-	char *principal;
+	int value, err;
+	const char *path;
 	_Bool result;
-	int i, count;
-
-	principal = fedfsd_get_gss_cred(rqstp);
 
 	result = false;
-	principals = config_lookup(&fedfsd_acl,
-					"gss.kerberos_v5.allowed_principals");
-	if (principals == NULL)
+	if (!fedfsd_reread_access_config())
+		goto out;
+	if (fedfsd_gss_krb5_is_allowed() == 0) {
+		xlog(D_CALL, "%s: GSS callers not authorized", __func__);
 		goto out;
+	}
 
-	count = config_setting_length(principals);
-	for (i = 0; i < count; i++) {
-		if (fedfsd_check_list(principals, i, principal)) {
-			result = true;
-			break;
-		}
+	if (strcmp(rcred->mechanism, "kerberos_v5") != 0) {
+		xlog(D_CALL, "%s: mechanism not supported", __func__);
+		goto out;
 	}
 
-out:
-	if (!result)
-		xlog(D_CALL, "%s: '%s' not authorized", __func__, principal);
-	else
-		xlog(D_CALL, "%s: '%s' authorized", __func__, principal);
+	if (strcmp(rcred->qop, "GSS_C_QOP_DEFAULT") != 0) {
+		xlog(D_CALL, "%s: mechanism not supported", __func__);
+		goto out;
+	}
+
+	switch (rcred->service) {
+	case rpcsec_gss_svc_integrity:
+		path = "gss.kerberos_v5.required_services.integrity";
+		break;
+	case rpcsec_gss_svc_privacy:
+		path = "gss.kerberos_v5.required_services.privacy";
+		break;
+	default:
+		path = "gss.kerberos_v5.required_services.authentication";
+	}
+	err = config_lookup_bool(&fedfsd_acl, path, &value);
+	if (err == CONFIG_FALSE)
+		goto out;	/* "path not there" is the same as "false" */
+	if (value == 0)
+		goto out;
+
+	result = true;
 
-	free(principal);
+out:
+	xlog(D_CALL, "%s: mechanism and service %s authorized",
+		__func__, result ? "are" : "are not");
 	return result;
 }
 
@@ -532,23 +551,47 @@  out:
  *
  * @param rqstp incoming RPC request
  * @return true if access is authorized
- *
- * This is provisional because the current libtirpc GSS API provides
- * only the caller's princpal, not the GSS mechanism or the GSS
- * service.
- *
- * For now, assume that the GSS mechanism is always "Kerberos v5" and
- * don't check to see if the service is enabled.
  */
 _Bool
 fedfsd_auth_rpc_gss(struct svc_req *rqstp)
 {
+	config_setting_t *principals;
+	rpc_gss_rawcred_t *rcred;
+	rpc_gss_principal_t cp;
+	int i, count;
+	_Bool result;
+	void *cookie;
+
+	result = false;
 	if (!fedfsd_reread_access_config())
-		return false;
+		goto out;
+	if (fedfsd_gss_krb5_is_allowed() == 0)
+		goto out;
 
-	if (fedfsd_gss_krb5_is_allowed() == 0) {
-		xlog(D_CALL, "%s: GSS callers not authorized", __func__);
-		return false;
+	/* Check if the GSS context is trusted */
+	if (rpc_gss_getcred(rqstp, &rcred, NULL, &cookie) == FALSE)
+		goto out;
+	if (cookie == NULL)
+		goto out;
+
+	/* Check if the principal is allowed */
+	cp = rcred->client_principal;
+	principals = config_lookup(&fedfsd_acl,
+					"gss.kerberos_v5.allowed_principals");
+	if (principals == NULL)
+		goto out;
+
+	count = config_setting_length(principals);
+	for (i = 0; i < count; i++) {
+		if (fedfsd_check_list(principals, i, cp->name, cp->len)) {
+			result = true;
+			break;
+		}
 	}
-	return fedfsd_auth_rpc_gss_krb5_principal(rqstp);
+
+	xlog(D_CALL, "%s: Principal '%*s' %s authorized", __func__,
+		cp->len, cp->name, (result ? "is" : "is not"));
+
+out:
+	return result;
 }
diff --git a/src/fedfsd/fedfsd.h b/src/fedfsd/fedfsd.h
index 220e7e1..3c128b9 100644
--- a/src/fedfsd/fedfsd.h
+++ b/src/fedfsd/fedfsd.h
@@ -40,7 +40,7 @@ 
 #define FEDFSD_ACCESS_CONFIG	"/etc/fedfsd/access.conf"
 
 /*
- * auth.c
+ * access.c
  */
 _Bool		fedfsd_read_access_config(const char *pathname);
 
@@ -52,7 +52,6 @@  _Bool		fedfsd_auth_rpc_gss(struct svc_req *rqstp);
  * gss.c
  */
 _Bool		fedfsd_set_up_authenticators(void);
-char *		fedfsd_get_gss_cred(struct svc_req *rqstp);
 
 /*
  * listen.c
diff --git a/src/fedfsd/gss.c b/src/fedfsd/gss.c
index 639f204..fe92986 100644
--- a/src/fedfsd/gss.c
+++ b/src/fedfsd/gss.c
@@ -36,22 +36,46 @@ 
 #include <netinet/in.h>
 
 #include <rpc/rpc.h>
-#include <rpc/auth.h>
-#include <rpc/svc.h>
 #include <rpc/svc_auth.h>
 #include <rpc/rpcsec_gss.h>
 
 #include "fedfs.h"
-#include "nsdb.h"
 #include "fedfsd.h"
 #include "xlog.h"
 
+_Bool		fedfsd_auth_rpc_gss_allowed(rpc_gss_rawcred_t *);
 
 /**
- * TI-RPC API for retrieving the caller's principal
- * (Not currently provided by any libtirpc header)
+ * Verify that incoming GSS context may be established
+ *
+ * @param rqstp incoming RPC request
+ * @param cred delegated GSS credentials
+ * @param ctxt GSS context
+ * @param lock enforce a particular QOP and service
+ * @param cookie not used
+ * @result true if GSS context may be established
  */
-char			*svcauth_gss_get_principal(SVCAUTH *auth);
+static bool_t
+fedfsd_gss_new_context(__attribute__((unused)) struct svc_req *rqstp,
+		       __attribute__((unused)) gss_cred_id_t cred,
+		       __attribute__((unused)) gss_ctx_id_t ctxt,
+		       rpc_gss_lock_t *lock,
+		       void **cookie)
+{
+	*cookie = NULL;
+	if (!fedfsd_auth_rpc_gss_allowed(lock->raw_cred))
+		return FALSE;
+
+	*cookie = (void *)1;
+	lock->locked = TRUE;
+	return TRUE;
+}
+
+static rpc_gss_callback_t fedfsd_gss_callback = {
+	.program	= FEDFS_PROG,
+	.version	= FEDFS_V1,
+	.callback	= fedfsd_gss_new_context,
+};
 
 /**
  * Ensure GSS Kerberos authentication is enabled
@@ -74,22 +98,10 @@  fedfsd_set_up_authenticators(void)
 		return false;
 	}
 
-	return true;
-}
-
-/**
- * Extract the RPCSEC GSS principal from an incoming request
- *
- * @param rqstp incoming RPC request
- * @return NUL-terminated C string containing GSS principal
- *
- * Caller must free principal with free(3).
- */
-char *
-fedfsd_get_gss_cred(struct svc_req *rqstp)
-{
-	SVCAUTH *auth;
+	if (!rpc_gss_set_callback(&fedfsd_gss_callback)) {
+		xlog(D_GENERAL, "%s: Could not set GSS callback", __func__);
+		return false;
+	}
 
-	auth = rqstp->rq_xprt->xp_auth;
-	return svcauth_gss_get_principal(auth);
+	return true;
 }
diff --git a/src/fedfsd/svc.c b/src/fedfsd/svc.c
index ea057d4..2e97924 100644
--- a/src/fedfsd/svc.c
+++ b/src/fedfsd/svc.c
@@ -2,8 +2,6 @@ 
  * @file src/fedfsd/svc.c
  * @brief Convert incoming FedFS admin RPC requests into local function calls.
  *
- * @todo
- *	Support RPCGSS authentication of clients
  */
 
 /*