>From af477c1d8e5e9ce57ea3c740e1fdd7871b485e7d Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Sat, 16 Nov 2013 17:01:24 -0500
Subject: [PATCH 1/3] config: Add code to source flag filters

2 New configuration options are made available:
- filter_flags
- enforce_flags

Any GSS Flags listed in the filter_flags option is forcibly filtered
out before a gss_init_sec_context() call is invoked.
Any GSS Flags listed in the enforce_flags option is forcibly added
to the list of flags requested by a gss_init_sec_context() call is
invoked.

Flags can be either literals or numeric and must be preceded by the
sign + (to add to the list) or - (to remove from the list).

Resolves: https://fedorahosted.org/gss-proxy/ticket/109
---
 proxy/src/gp_config.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
 proxy/src/gp_proxy.h  |  2 ++
 2 files changed, 90 insertions(+)

diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c
index 08d29feea6f41926711466ab0d94fa984163c1a9..63f264e4855d02a2afe183d3b483aaf602eb716b 100644
--- a/proxy/src/gp_config.c
+++ b/proxy/src/gp_config.c
@@ -32,6 +32,27 @@
 #include "gp_config.h"
 #include "gp_selinux.h"
 
+#include <gssapi/gssapi.h>
+
+struct gp_flag_def {
+    const char *name;
+    uint32_t value;
+};
+
+struct gp_flag_def flag_names[] = {
+    { "DELEGATE", GSS_C_DELEG_FLAG },
+    { "MUTUAL_AUTH", GSS_C_MUTUAL_FLAG },
+    { "REPLAY_DETECT", GSS_C_REPLAY_FLAG },
+    { "SEQUENCE", GSS_C_SEQUENCE_FLAG },
+    { "CONFIDENTIALITY", GSS_C_CONF_FLAG },
+    { "INTEGRITIY", GSS_C_INTEG_FLAG },
+    { "ANONYMOUS", GSS_C_ANON_FLAG },
+    { NULL, 0 }
+};
+
+#define DEFAULT_FILTERED_FLAGS GSS_C_DELEG_FLAG
+#define DEFAULT_ENFORCED_FLAGS 0
+
 static void free_str_array(const char ***a, int *count)
 {
     const char **array;
@@ -117,6 +138,60 @@ static int get_krb5_mech_cfg(struct gp_service *svc,
     return ret;
 }
 
+static int parse_flags(const char *value, uint32_t *storage)
+{
+    char *handle;
+    char *token;
+    char *str;
+    bool add;
+    unsigned long int conv;
+    uint32_t flagval;
+    int i;
+
+    str = strdup(value);
+    if (!str) {
+        return ENOMEM;
+    }
+
+    token = strtok_r(str, ", ", &handle);
+    for (token = strtok_r(str, ", ", &handle);
+         token != NULL;
+         token = strtok_r(NULL, ", ", &handle)) {
+        switch (token[0]) {
+        case '+':
+            add = true;
+            break;
+        case '-':
+            add = false;
+            break;
+        default:
+            GPERROR("Ignoring flag [%s], missing +/- qualifier.\n", token);
+            continue;
+        }
+        token++;
+        for (i = 0; flag_names[i].name != NULL; i++) {
+            if (strcasecmp(token, flag_names[i].name) == 0) {
+                flagval = flag_names[i].value;
+                break;
+            }
+        }
+        if (flag_names[i].name == NULL) {
+            conv = strtoul(token, &handle, 0);
+            if (conv == 0 || conv == ULONG_MAX || *handle != '\0') {
+                GPERROR("Ignoring flag [%s], unrecognized value.\n", token);
+                continue;
+            }
+            flagval = conv;
+        }
+        GPDEBUG("%s Flag %s (%u).\n", add?"Add":"Remove", token, flagval);
+        if (add) *storage |= flagval;
+        else *storage &= ~flagval;
+    }
+    safefree(str);
+
+    return 0;
+}
+
 static int setup_service_creds_handle(struct gp_service *svc)
 {
     uint32_t ret_maj, ret_min;
@@ -305,6 +380,19 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx)
                     goto done;
                 }
             }
+
+            cfg->svcs[n]->filter_flags = DEFAULT_FILTERED_FLAGS;
+            ret = gp_config_get_string(ctx, secname, "filter_flags", &value);
+            if (ret == 0) {
+                parse_flags(value, &cfg->svcs[n]->filter_flags);
+            }
+
+            cfg->svcs[n]->enforce_flags = DEFAULT_ENFORCED_FLAGS;
+            ret = gp_config_get_string(ctx, secname, "enforce_flags", &value);
+            if (ret == 0) {
+                ret = parse_flags(value, &cfg->svcs[n]->enforce_flags);
+                if (ret) goto done;
+            }
         }
         safefree(secname);
     }
diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h
index 8390f5d9f8516364a9b4acd0e416d10b1d807ac0..b6c64ae727d902fa73e87226ab5c1cf8506b1bf4 100644
--- a/proxy/src/gp_proxy.h
+++ b/proxy/src/gp_proxy.h
@@ -57,6 +57,8 @@ struct gp_service {
     char *socket;
     SELINUX_CTX selinux_ctx;
     gss_cred_usage_t cred_usage;
+    uint32_t filter_flags;
+    uint32_t enforce_flags;
 
     uint32_t mechs;
     struct gp_cred_krb5 krb5;
-- 
1.8.4.2

