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 <[email protected]> --- 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 --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 */ /* _______________________________________________ fedfs-utils-devel mailing list [email protected] https://oss.oracle.com/mailman/listinfo/fedfs-utils-devel
