Blob Blame History Raw
From 4b2643196c683b5ff300de2a1d41dd3cc900d4d1 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Sun, 8 May 2016 02:31:00 -0400
Subject: [PATCH 1/2] Implement unique ccache names

Unique ccache names may be requested using the GssapiDelegCcacheUnique
configuration option.  This option is off by default.  If both unique
ccache names and session use are enabled, then a mechanism for removing
old ccaches must be supplied.

Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Also-authored-by: Petr Vobornik <pvoborni@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
---
 README                     | 13 +++++++
 src/asn1c/GSSSessionData.c | 17 +++++++---
 src/asn1c/GSSSessionData.h |  2 +-
 src/asn1c/Uint32.c         |  1 -
 src/asn1c/Uint32.h         |  1 -
 src/asn1c/session.asn1     |  3 +-
 src/mod_auth_gssapi.c      | 84 ++++++++++++++++++++++++++++++----------------
 src/mod_auth_gssapi.h      |  4 +++
 src/sessions.c             |  8 +++++
 9 files changed, 96 insertions(+), 37 deletions(-)

diff --git a/README b/README
index 9d25fb3fd774888c19a38100b256243c172e6f36..285a48f68379e2cb305af85737eefd85fbbaf025 100644
--- a/README
+++ b/README
@@ -171,6 +171,19 @@ A user foo@EXAMPLE.COM delegating its credentials would cause the server to
 create a ccache file named /var/run/httpd/clientcaches/foo@EXAMPLE.COM
 
 
+### GssapiDelegCcacheUnique
+
+Enables using unique ccache names for delegation.  ccache files will be placed
+in GssapiDelegCcacheDir and named using the principal and a six-digit unique
+suffix.
+
+**Note:** Consuming application must delete the ccache otherwise it will
+litter the filesystem if sessions are used.  An example sweeper can be found
+in the contrib directory.
+
+#### Example
+    GssapiDelegCcacheUnique On
+
 ### GssapiUseS4U2Proxy
 
 Enables the use of the s4u2Proxy Kerberos extension also known as
diff --git a/src/asn1c/GSSSessionData.c b/src/asn1c/GSSSessionData.c
index 12a98e3f215c095131fe8a53453991f4134334f8..f0dcc2e721ac56b9c7741cc0e58de3e973be81c5 100644
--- a/src/asn1c/GSSSessionData.c
+++ b/src/asn1c/GSSSessionData.c
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #include "GSSSessionData.h"
@@ -62,6 +61,15 @@ static asn_TYPE_member_t asn_MBR_GSSSessionData_1[] = {
 		0,
 		"basichash"
 		},
+	{ ATF_NOFLAGS, 0, offsetof(struct GSSSessionData, ccname),
+		(ASN_TAG_CLASS_CONTEXT | (6 << 2)),
+		+1,	/* EXPLICIT tag at current level */
+		&asn_DEF_OCTET_STRING,
+		0,	/* Defer constraints checking to the member type */
+		0,	/* PER is not compiled, use -gen-PER */
+		0,
+		"ccname"
+		},
 };
 static ber_tlv_tag_t asn_DEF_GSSSessionData_tags_1[] = {
 	(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
@@ -72,13 +80,14 @@ static asn_TYPE_tag2member_t asn_MAP_GSSSessionData_tag2el_1[] = {
     { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* expiration */
     { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* username */
     { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* gssname */
-    { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 } /* basichash */
+    { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* basichash */
+    { (ASN_TAG_CLASS_CONTEXT | (6 << 2)), 6, 0, 0 } /* ccname */
 };
 static asn_SEQUENCE_specifics_t asn_SPC_GSSSessionData_specs_1 = {
 	sizeof(struct GSSSessionData),
 	offsetof(struct GSSSessionData, _asn_ctx),
 	asn_MAP_GSSSessionData_tag2el_1,
-	6,	/* Count of tags in the map */
+	7,	/* Count of tags in the map */
 	0, 0, 0,	/* Optional elements (not needed) */
 	-1,	/* Start extensions */
 	-1	/* Stop extensions */
@@ -103,7 +112,7 @@ asn_TYPE_descriptor_t asn_DEF_GSSSessionData = {
 		/sizeof(asn_DEF_GSSSessionData_tags_1[0]), /* 1 */
 	0,	/* No PER visible constraints */
 	asn_MBR_GSSSessionData_1,
-	6,	/* Elements count */
+	7,	/* Elements count */
 	&asn_SPC_GSSSessionData_specs_1	/* Additional specs */
 };
 
diff --git a/src/asn1c/GSSSessionData.h b/src/asn1c/GSSSessionData.h
index 53556d886347107d66bd640fea1241452e37b07a..4ae224f1bfacb47ec5567fda7ff38210cbc1abbb 100644
--- a/src/asn1c/GSSSessionData.h
+++ b/src/asn1c/GSSSessionData.h
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #ifndef	_GSSSessionData_H_
@@ -29,6 +28,7 @@ typedef struct GSSSessionData {
 	OCTET_STRING_t	 username;
 	OCTET_STRING_t	 gssname;
 	OCTET_STRING_t	 basichash;
+	OCTET_STRING_t	 ccname;
 	
 	/* Context for parsing across buffer boundaries */
 	asn_struct_ctx_t _asn_ctx;
diff --git a/src/asn1c/Uint32.c b/src/asn1c/Uint32.c
index 794f98b54838466234fdca75def963e814c31ffd..f5d125aec0dfffa6f87a69569550bfa1739bd9b1 100644
--- a/src/asn1c/Uint32.c
+++ b/src/asn1c/Uint32.c
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #include "Uint32.h"
diff --git a/src/asn1c/Uint32.h b/src/asn1c/Uint32.h
index a0ed87608505e5ddc7b1ae86b70710ee39788753..436e26ea73af1a194bc81387d6edcbf8be898c68 100644
--- a/src/asn1c/Uint32.h
+++ b/src/asn1c/Uint32.h
@@ -2,7 +2,6 @@
  * Generated by asn1c-0.9.27 (http://lionet.info/asn1c)
  * From ASN.1 module "GssapiSessionModule"
  * 	found in "session.asn1"
- * 	`asn1c -fskeletons-copy`
  */
 
 #ifndef	_Uint32_H_
diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c
index a480997bfccb57641fb0d9d86cd7fdb39c392ee3..48eb76f982b1b0f053fe6d8de41dfdc5c3faf8b6 100644
--- a/src/mod_auth_gssapi.c
+++ b/src/mod_auth_gssapi.c
@@ -225,10 +225,11 @@ static char *escape(apr_pool_t *pool, const char *name,
     return escaped;
 }
 
-static char *mag_gss_name_to_ccache_name(request_rec *req,
-                                         char *dir, const char *gss_name)
+static char *get_ccache_name(request_rec *req, char *dir, const char *gss_name,
+                             bool use_unique, struct mag_conn *mc)
 {
-    char *escaped;
+    char *ccname, *escaped;
+    int ccachefd;
 
     /* We need to escape away '/', we can't have path separators in
      * a ccache file name */
@@ -237,10 +238,24 @@ static char *mag_gss_name_to_ccache_name(request_rec *req,
     /* then escape away the separator (/) if any */
     escaped = escape(req->pool, escaped, '/', "~");
 
-    return apr_psprintf(req->pool, "%s/%s", dir, escaped);
+    if (use_unique == false) {
+        return apr_psprintf(req->pool, "%s/%s", dir, escaped);
+    }
+
+    ccname = apr_psprintf(mc->pool, "%s/%s-XXXXXX", dir, escaped);
+
+    ccachefd = mkstemp(ccname);
+    if (ccachefd == -1) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
+                      "creating unique ccache file %s failed", ccname);
+        return NULL;
+    }
+    close(ccachefd);
+    return ccname;
 }
 
-static void mag_set_KRB5CCANME(request_rec *req, char *ccname)
+static void mag_set_KRB5CCNAME(request_rec *req, const char *dir,
+                               const char *ccname)
 {
     apr_status_t status;
     apr_finfo_t finfo;
@@ -253,24 +268,20 @@ static void mag_set_KRB5CCANME(request_rec *req, char *ccname)
                       "KRB5CCNAME file (%s) lookup failed!", ccname);
     }
 
-    value = apr_psprintf(req->pool, "FILE:%s", ccname);
+    value = apr_psprintf(req->pool, "FILE:%s/%s", dir, ccname);
     apr_table_set(req->subprocess_env, "KRB5CCNAME", value);
 }
 
-static void mag_store_deleg_creds(request_rec *req,
-                                  char *dir, char *clientname,
-                                  gss_cred_id_t delegated_cred,
-                                  char **ccachefile)
+static void mag_store_deleg_creds(request_rec *req, const char *ccname,
+                                  gss_cred_id_t delegated_cred)
 {
     gss_key_value_element_desc element;
     gss_key_value_set_desc store;
-    char *ccname;
     uint32_t maj, min;
     element.key = "ccache";
     store.elements = &element;
     store.count = 1;
 
-    ccname = mag_gss_name_to_ccache_name(req, dir, clientname);
     element.value = apr_psprintf(req->pool, "FILE:%s", ccname);
 
     maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE,
@@ -280,8 +291,6 @@ static void mag_store_deleg_creds(request_rec *req,
                       mag_error(req, "failed to store delegated creds",
                                 maj, min));
     }
-
-    *ccachefile = ccname;
 }
 #endif
 
@@ -339,14 +348,8 @@ static void mag_set_req_data(request_rec *req,
     req->ap_auth_type = apr_pstrdup(req->pool,
                                     auth_types[mc->auth_type]);
     req->user = apr_pstrdup(req->pool, mc->user_name);
-    if (cfg->deleg_ccache_dir && mc->delegated) {
-        char *ccname;
-        ccname = mag_gss_name_to_ccache_name(req,
-                                             cfg->deleg_ccache_dir,
-                                             mc->gss_name);
-        if (ccname) {
-            mag_set_KRB5CCANME(req, ccname);
-        }
+    if (cfg->deleg_ccache_dir && mc->delegated && mc->ccname) {
+        mag_set_KRB5CCNAME(req, cfg->deleg_ccache_dir, mc->ccname);
     }
 }
 
@@ -943,18 +946,30 @@ complete:
 
 #ifdef HAVE_CRED_STORE
     if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
-        char *ccachefile = NULL;
+        char *ccache_path;
 
-        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
-                              delegated_cred, &ccachefile);
+        mc->ccname = 0;
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
+                      "requester: %s", mc->gss_name);
 
-        if (ccachefile) {
-            mag_set_KRB5CCANME(req, ccachefile);
+        ccache_path = get_ccache_name(req, cfg->deleg_ccache_dir, mc->gss_name,
+                                      cfg->deleg_ccache_unique, mc);
+        if (ccache_path == NULL) {
+            goto done;
         }
 
-        if (mc) {
-            mc->delegated = true;
+        mag_store_deleg_creds(req, ccache_path, delegated_cred);
+        mc->delegated = true;
+
+        if (!req_cfg->use_sessions && cfg->deleg_ccache_unique) {
+            /* queue removing ccache to avoid littering filesystem */
+            apr_pool_cleanup_register(mc->pool, ccache_path,
+                                      (int (*)(void *)) unlink,
+                                      apr_pool_cleanup_null);
         }
+
+        /* extract filename from full path */
+        mc->ccname = strrchr(ccache_path, '/') + 1;
     }
 #endif
 
@@ -1084,6 +1099,15 @@ static const char *mag_use_s4u2p(cmd_parms *parms, void *mconfig, int on)
 
     return NULL;
 }
+
+static const char *mag_deleg_ccache_unique(cmd_parms *parms, void *mconfig,
+                                           int on)
+{
+    struct mag_config *cfg = (struct mag_config *)mconfig;
+    cfg->deleg_ccache_unique = on ? true : false;
+    return NULL;
+}
+
 #endif
 
 static const char *mag_sess_key(cmd_parms *parms, void *mconfig, const char *w)
@@ -1338,6 +1362,8 @@ static const command_rec mag_commands[] = {
                     "Credential Store"),
     AP_INIT_RAW_ARGS("GssapiDelegCcacheDir", mag_deleg_ccache_dir, NULL,
                      OR_AUTHCFG, "Directory to store delegated credentials"),
+    AP_INIT_FLAG("GssapiDelegCcacheUnique", mag_deleg_ccache_unique, NULL,
+                 OR_AUTHCFG, "Use unique ccaches for delgation"),
 #endif
 #ifdef HAVE_GSS_ACQUIRE_CRED_WITH_PASSWORD
     AP_INIT_FLAG("GssapiBasicAuth", mag_use_basic_auth, NULL, OR_AUTHCFG,
diff --git a/src/mod_auth_gssapi.h b/src/mod_auth_gssapi.h
index d73036b2473f0e8da66de699194eacc8e6f7d83a..b5032def3c1835105b4d0909ce19b5be795ae33d 100644
--- a/src/mod_auth_gssapi.h
+++ b/src/mod_auth_gssapi.h
@@ -2,7 +2,9 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <time.h>
+#include <unistd.h>
 
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
@@ -56,6 +58,7 @@ struct mag_config {
     bool use_s4u2proxy;
     char *deleg_ccache_dir;
     gss_key_value_set_desc *cred_store;
+    bool deleg_ccache_unique;;
 #endif
     struct seal_key *mag_skey;
 
@@ -90,6 +93,7 @@ struct mag_conn {
     int auth_type;
     bool delegated;
     struct databuf basic_hash;
+    const char *ccname;
 };
 
 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
diff --git a/src/sessions.c b/src/sessions.c
index 70f39a291d4bcfa0117635cdd8c2fbb4ee8df305..c785d2784cd99845fff64529cf60a03892179242 100644
--- a/src/sessions.c
+++ b/src/sessions.c
@@ -177,6 +177,12 @@ void mag_check_session(struct mag_req_cfg *cfg, struct mag_conn **conn)
     memcpy(mc->basic_hash.value,
            gsessdata->basichash.buf, gsessdata->basichash.size);
 
+    /* ccname */
+    mc->ccname = apr_pstrndup(mc->pool,
+                              (char *)gsessdata->ccname.buf,
+                              gsessdata->ccname.size);
+    if (!mc->ccname) goto done;
+
     /* OK we have a valid token */
     mc->established = true;
 
@@ -222,6 +228,8 @@ void mag_attempt_session(struct mag_req_cfg *cfg, struct mag_conn *mc)
                              (const char *)mc->basic_hash.value,
                              mc->basic_hash.length) != 0)
         goto done;
+    if (OCTET_STRING_fromString(&gsessdata.ccname, mc->ccname) != 0)
+        goto done;
     ret = encode_GSSSessionData(req->pool, &gsessdata,
                                 &plainbuf.value, &plainbuf.length);
     if (ret == false) {
-- 
2.5.5