@@ -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;
}
@@ -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
@@ -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;
}
@@ -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
*/
/*
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(-)