>From 97c47d3f12e6a236d34a12f5a66e6a1450b62388 Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Mon, 14 Oct 2013 16:41:13 -0400
Subject: [PATCH 2/2] Add option to specify allowed usage.

Credentials can often be used both to accept and to initiate contexts.
With this option admins can allow a specific usage only.
This is to avoid allowing an unprivileged process to fool a remote
client by allowing it to impersonate a server, when we only want to
allow this service to use credentials to initiate contexts.
---
 proxy/examples/gssproxy.conf.in |  1 +
 proxy/src/gp_config.c           | 19 +++++++++++++++++++
 proxy/src/gp_creds.c            | 14 ++++++++++++--
 proxy/src/gp_proxy.h            |  1 +
 4 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/proxy/examples/gssproxy.conf.in b/proxy/examples/gssproxy.conf.in
index 262125adf663c1943b8af10f2f476b4c526e7a21..f12119998a0efe7edf6c06e92cd455b00539fdab 100644
--- a/proxy/examples/gssproxy.conf.in
+++ b/proxy/examples/gssproxy.conf.in
@@ -13,6 +13,7 @@
   cred_store = keytab:/etc/krb5.keytab
   cred_store = ccache:FILE:@gpstatedir@/clients/krb5cc_%U
   cred_store = client_keytab:@gpstatedir@/clients/%U.keytab
+  cred_usage = initiate
   allow_any_uid = yes
   trusted = yes
   euid = 0
diff --git a/proxy/src/gp_config.c b/proxy/src/gp_config.c
index 943906aca344ae8d11cec8b4b90cdd7e6b78a5eb..2aeaaa9133b8c9c4b02fb3df19f1ddb1aa920eb4 100644
--- a/proxy/src/gp_config.c
+++ b/proxy/src/gp_config.c
@@ -163,6 +163,9 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx)
             }
             cfg->num_svcs++;
 
+            /* by default allow both */
+            cfg->svcs[n]->cred_usage = GSS_C_BOTH;
+
             cfg->svcs[n]->name = strdup(secname + 8);
             if (!cfg->svcs[n]->name) {
                 ret = ENOMEM;
@@ -271,6 +274,22 @@ static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx)
                     goto done;
                 }
             }
+
+            ret = gp_config_get_string(ctx, secname, "cred_usage", &value);
+            if (ret == 0) {
+                if (strcasecmp(value, "initiate") == 0) {
+                    cfg->svcs[n]->cred_usage = GSS_C_INITIATE;
+                } else if (strcasecmp(value, "accept") == 0) {
+                    cfg->svcs[n]->cred_usage = GSS_C_ACCEPT;
+                } else if (strcasecmp(value, "both") == 0) {
+                    cfg->svcs[n]->cred_usage = GSS_C_BOTH;
+                } else {
+                    GPDEBUG("Invalid value '%s' for cred_usage in [%s].\n",
+                            value, secname);
+                    ret = EINVAL;
+                    goto done;
+                }
+            }
         }
         safefree(secname);
     }
diff --git a/proxy/src/gp_creds.c b/proxy/src/gp_creds.c
index b047d8f65fe2169ce71d62229405c61bc2e23d1e..28a3d4591ec0067df79545796d6d8eca2986757a 100644
--- a/proxy/src/gp_creds.c
+++ b/proxy/src/gp_creds.c
@@ -205,7 +205,7 @@ static void free_cred_store_elements(gss_key_value_set_desc *cs)
 static int gp_get_cred_environment(struct gp_call_ctx *gpcall,
                                    gssx_name *desired_name,
                                    gss_name_t *requested_name,
-                                   gss_cred_usage_t cred_usage,
+                                   gss_cred_usage_t *cred_usage,
                                    gss_key_value_set_desc *cs)
 {
     struct gp_service *svc;
@@ -226,6 +226,16 @@ static int gp_get_cred_environment(struct gp_call_ctx *gpcall,
     target_uid = gp_conn_get_uid(gpcall->connection);
     svc = gpcall->service;
 
+    /* filter based on cred_usage */
+    if (svc->cred_usage != GSS_C_BOTH) {
+        if (*cred_usage == GSS_C_BOTH) {
+            *cred_usage = svc->cred_usage;
+        } else if (svc->cred_usage != *cred_usage) {
+            ret = EACCES;
+            goto done;
+        }
+    }
+
     if (desired_name) {
         gp_conv_gssx_to_oid(&desired_name->name_type, &name_type);
 
@@ -379,7 +389,7 @@ uint32_t gp_add_krb5_creds(uint32_t *min,
     }
 
     ret_min = gp_get_cred_environment(gpcall, desired_name, &req_name,
-                                      cred_usage, &cred_store);
+                                      &cred_usage, &cred_store);
     if (ret_min) {
         ret_maj = GSS_S_CRED_UNAVAIL;
         goto done;
diff --git a/proxy/src/gp_proxy.h b/proxy/src/gp_proxy.h
index a5b3a28887f91e37f36cdd5d7d9c578ef44ce78d..5f42ffa52135a9f53a915700684084026ba936f0 100644
--- a/proxy/src/gp_proxy.h
+++ b/proxy/src/gp_proxy.h
@@ -55,6 +55,7 @@ struct gp_service {
     bool kernel_nfsd;
     char *socket;
     SELINUX_CTX selinux_ctx;
+    gss_cred_usage_t cred_usage;
 
     uint32_t mechs;
     struct gp_cred_krb5 krb5;
-- 
1.8.3.1

