Implement unique ccache names
authorRobbie Harwood <rharwood@redhat.com>
Sun, 8 May 2016 06:31:00 +0000 (02:31 -0400)
committerSimo Sorce <simo@redhat.com>
Wed, 18 May 2016 21:46:14 +0000 (17:46 -0400)
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
src/asn1c/GSSSessionData.c
src/asn1c/GSSSessionData.h
src/asn1c/Uint32.c
src/asn1c/Uint32.h
src/asn1c/session.asn1
src/environ.c
src/mod_auth_gssapi.c
src/mod_auth_gssapi.h
src/sessions.c

diff --git a/README b/README
index b4eca28..781f3ea 100644 (file)
--- 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
index 12a98e3..f0dcc2e 100644 (file)
@@ -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 */
 };
 
index 53556d8..4ae224f 100644 (file)
@@ -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;
index 794f98b..f5d125a 100644 (file)
@@ -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"
index a0ed876..436e26e 100644 (file)
@@ -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_
index 1762812..f499779 100644 (file)
@@ -8,6 +8,7 @@ GssapiSessionModule DEFINITIONS ::= BEGIN
         expiration  [2] Uint32,
         username    [3] OCTET STRING,
         gssname     [4] OCTET STRING,
-        basichash   [5] OCTET STRING
+        basichash   [5] OCTET STRING,
+        ccname      [6] OCTET STRING
     }
 END
index 1fffc90..c9378b1 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2015 mod_auth_gssapi contributors - See COPYING for (C) terms */
+/* Copyright (C) 2015, 2016 mod_auth_gssapi contributors - See COPYING for (C) terms */
 
 #include "mod_auth_gssapi.h"
 
@@ -243,7 +243,8 @@ static void mag_set_name_attributes(request_rec *req, struct mag_conn *mc)
     }
 }
 
-static void mag_set_KRB5CCANME(request_rec *req, char *ccname)
+static void mag_set_KRB5CCANME(request_rec *req, const char *dir,
+                               const char *ccname)
 {
     apr_status_t status;
     apr_finfo_t finfo;
@@ -256,7 +257,7 @@ 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);
 }
 
@@ -277,14 +278,8 @@ void mag_set_req_data(request_rec *req,
     }
 
 #ifdef HAVE_CRED_STORE
-    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_KRB5CCANME(req, cfg->deleg_ccache_dir, mc->ccname);
     }
 #endif
 }
index 35bb9a1..d2b5d2b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 mod_auth_gssapi contributors - See COPYING for (C) terms */
+/* Copyright (C) 2014, 2016 mod_auth_gssapi contributors - See COPYING for (C) terms */
 
 #include "mod_auth_gssapi.h"
 
@@ -202,10 +202,11 @@ static char *escape(apr_pool_t *pool, const char *name,
     return escaped;
 }
 
-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 */
@@ -214,22 +215,32 @@ 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_store_deleg_creds(request_rec *req,
-                                  char *dir, const char *gss_name,
+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, gss_name);
     element.value = apr_psprintf(req->pool, "FILE:%s", ccname);
 
     maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE,
@@ -877,9 +888,30 @@ complete:
 
 #ifdef HAVE_CRED_STORE
     if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
-        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, mc->gss_name,
-                              delegated_cred);
+        char *ccache_path;
+
+        mc->ccname = 0;
+        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, req,
+                      "requester: %s", mc->gss_name);
+
+        ccache_path = get_ccache_name(req, cfg->deleg_ccache_dir, mc->gss_name,
+                                      cfg->deleg_ccache_unique, mc);
+        if (ccache_path == NULL) {
+            goto done;
+        }
+
+        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
 
@@ -1006,6 +1038,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)
@@ -1330,6 +1371,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,
index 1973b2b..0c77b8b 100644 (file)
@@ -1,8 +1,10 @@
-/* Copyright (C) 2014 mod_auth_gssapi contributors - See COPYING for (C) terms */
+/* Copyright (C) 2014, 2016 mod_auth_gssapi contributors - See COPYING for (C) terms */
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <time.h>
+#include <unistd.h>
 
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
@@ -68,6 +70,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;
 
@@ -112,12 +115,11 @@ struct mag_conn {
     bool is_preserved;
     int na_count;
     struct mag_attr *name_attributes;
+    const char *ccname;
 };
 
 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
 
 struct mag_conn *mag_new_conn_ctx(apr_pool_t *pool);
 const char *mag_str_auth_type(int auth_type);
-char *mag_gss_name_to_ccache_name(request_rec *req,
-                                  char *dir, const char *gss_name);
 char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min);
index d8c4873..d99b92d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 mod_auth_gssapi contributors - See COPYING for (C) terms */
+/* Copyright (C) 2014, 2016 mod_auth_gssapi contributors - See COPYING for (C) terms */
 
 #include "mod_auth_gssapi.h"
 #include "asn1c/GSSSessionData.h"
@@ -179,6 +179,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;
 
@@ -224,6 +230,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) {