summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2013-08-15 19:36:26 -0400
committerJakub Hrozek <jhrozek@redhat.com>2013-08-27 17:06:36 +0200
commit3b313392baa798dfa76b0e0d7af95218c5d22114 (patch)
tree7cebc4a0a6d1b86100a85682f2ba6a9aab409ec3
parenta9b3ecf7dbeb79d8e79a80c007b2ae4c88ef18e8 (diff)
downloadsssd-3b313392baa798dfa76b0e0d7af95218c5d22114.tar.gz
sssd-3b313392baa798dfa76b0e0d7af95218c5d22114.tar.xz
sssd-3b313392baa798dfa76b0e0d7af95218c5d22114.zip
KRB5: Add support for KEYRING cache type
https://fedorahosted.org/sssd/ticket/2036
-rw-r--r--src/man/sssd-krb5.5.xml23
-rw-r--r--src/providers/krb5/krb5_child.c49
-rw-r--r--src/providers/krb5/krb5_common.c5
-rw-r--r--src/providers/krb5/krb5_utils.c156
-rw-r--r--src/providers/krb5/krb5_utils.h2
-rw-r--r--src/util/sss_krb5.c14
-rw-r--r--src/util/sss_krb5.h2
7 files changed, 245 insertions, 6 deletions
diff --git a/src/man/sssd-krb5.5.xml b/src/man/sssd-krb5.5.xml
index df124b4d2..720f39b7b 100644
--- a/src/man/sssd-krb5.5.xml
+++ b/src/man/sssd-krb5.5.xml
@@ -158,12 +158,15 @@
<term>krb5_ccname_template (string)</term>
<listitem>
<para>
- Location of the user's credential cache. Two credential
- cache types are currently supported: <quote>FILE</quote>
- and <quote>DIR</quote>. The cache can be specified either
- as <replaceable>TYPE:RESIDUAL</replaceable>, or as an absolute
- path, which implies the <quote>FILE</quote> type. In the
- template, the following sequences are substituted:
+ Location of the user's credential cache. Three
+ credential cache types are currently supported:
+ <quote>FILE</quote>, <quote>DIR</quote> and
+ <quote>KEYRING:persistent</quote>. The cache can
+ be specified either as
+ <replaceable>TYPE:RESIDUAL</replaceable>, or as an
+ absolute path, which implies the
+ <quote>FILE</quote> type. In the template, the
+ following sequences are substituted:
<variablelist>
<varlistentry>
<term>%u</term>
@@ -209,6 +212,14 @@
used to create a unique filename in a safe way.
</para>
<para>
+ When using KEYRING types, the only supported
+ mechanism is <quote>KEYRING:persistent:%U</quote>,
+ which uses the Linux kernel keyring to store
+ credentials on a per-UID basis. This is also the
+ recommended choice, as it is the most secure and
+ predictable method.
+ </para>
+ <para>
Default: FILE:%d/krb5cc_%U_XXXXXX
</para>
</listitem>
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 02eea79ab..e7ace14ac 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -505,6 +505,19 @@ store_creds_in_ccache(krb5_context ctx, krb5_principal princ,
{
krb5_error_code kerr;
krb5_creds *l_cred;
+ char *ccname;
+
+ if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
+ kerr = krb5_cc_get_full_name(ctx, cc, &ccname);
+ if (kerr != 0) {
+ DEBUG(SSSDBG_TRACE_ALL,
+ ("Couldn't determine full name of ccache\n"));
+ } else {
+ DEBUG(SSSDBG_TRACE_ALL,
+ ("Storing credentials in [%s]\n", ccname));
+ krb5_free_string(ctx, ccname);
+ }
+ }
kerr = krb5_cc_initialize(ctx, cc, princ);
if (kerr != 0) {
@@ -775,6 +788,37 @@ done:
return kerr;
}
+static krb5_error_code
+create_ccache_keyring(krb5_context ctx,
+ krb5_principal princ,
+ char *ccname,
+ krb5_creds *creds)
+{
+ krb5_error_code kerr;
+ krb5_ccache tmp_cc = NULL;
+
+ DEBUG(SSSDBG_FUNC_DATA, ("Creating ccache at [%s]\n", ccname));
+
+ kerr = krb5_cc_resolve(ctx, ccname, &tmp_cc);
+ if (kerr != 0) {
+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+ goto done;
+ }
+
+ kerr = store_creds_in_ccache(ctx, princ, tmp_cc, creds);
+ if (kerr != 0) {
+ KRB5_CHILD_DEBUG(SSSDBG_CRIT_FAILURE, kerr);
+ goto done;
+ }
+
+done:
+ if (kerr != 0 && tmp_cc != NULL) {
+ krb5_cc_destroy(ctx, tmp_cc);
+ }
+
+ return kerr;
+}
+
#endif /* HAVE_KRB5_CC_COLLECTION */
static krb5_error_code
@@ -787,10 +831,15 @@ create_ccache(uid_t uid, gid_t gid, krb5_context ctx,
switch (cctype) {
case SSS_KRB5_TYPE_FILE:
return create_ccache_file(ctx, princ, ccname, creds);
+
#ifdef HAVE_KRB5_CC_COLLECTION
case SSS_KRB5_TYPE_DIR:
return create_ccache_in_dir(uid, gid, ctx, princ, ccname, creds);
+
+ case SSS_KRB5_TYPE_KEYRING:
+ return create_ccache_keyring(ctx, princ, ccname, creds);
#endif /* HAVE_KRB5_CC_COLLECTION */
+
default:
DEBUG(SSSDBG_CRIT_FAILURE, ("Unknown cache type\n"));
return EINVAL;
diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c
index e56dc6245..86e72157a 100644
--- a/src/providers/krb5/krb5_common.c
+++ b/src/providers/krb5/krb5_common.c
@@ -215,6 +215,11 @@ errno_t check_and_export_options(struct dp_option *opts,
DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type DIR\n"));
krb5_ctx->cc_be = &dir_cc;
break;
+
+ case SSS_KRB5_TYPE_KEYRING:
+ DEBUG(SSSDBG_CONF_SETTINGS, ("ccache is of type KEYRING\n"));
+ krb5_ctx->cc_be = &keyring_cc;
+ break;
#endif /* HAVE_KRB5_CC_COLLECTION */
default:
diff --git a/src/providers/krb5/krb5_utils.c b/src/providers/krb5/krb5_utils.c
index f8fbb29eb..d4fb93adb 100644
--- a/src/providers/krb5/krb5_utils.c
+++ b/src/providers/krb5/krb5_utils.c
@@ -760,6 +760,8 @@ done:
return ret;
}
+
+
/*======== ccache back end utilities ========*/
struct sss_krb5_cc_be *
get_cc_be_ops(enum sss_krb5_cc_type type)
@@ -775,6 +777,10 @@ get_cc_be_ops(enum sss_krb5_cc_type type)
case SSS_KRB5_TYPE_DIR:
be = &dir_cc;
break;
+
+ case SSS_KRB5_TYPE_KEYRING:
+ be = &keyring_cc;
+ break;
#endif /* HAVE_KRB5_CC_COLLECTION */
case SSS_KRB5_TYPE_UNKNOWN:
@@ -1189,6 +1195,156 @@ struct sss_krb5_cc_be dir_cc = {
.remove = cc_dir_remove
};
+
+/*======== Operations on the KEYRING: back end ========*/
+
+errno_t
+cc_keyring_create(const char *location, pcre *illegal_re,
+ uid_t uid, gid_t gid, bool private_path)
+{
+ const char *residual;
+
+ residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+ if (residual == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Bad ccache type %s\n", location));
+ return EINVAL;
+ }
+
+ /* No special steps are needed to create a kernel keyring.
+ * Everything is handled in libkrb5.
+ */
+ return EOK;
+}
+
+errno_t
+cc_keyring_check_existing(const char *location, uid_t uid,
+ const char *realm, const char *princ,
+ const char *cc_template, bool *_active,
+ bool *_valid)
+{
+ errno_t ret;
+ bool active;
+ bool valid;
+ const char *residual;
+
+ residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+ if (!residual) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("%s is not of type KEYRING:\n", location));
+ return EINVAL;
+ }
+
+ /* The keyring cache is always active */
+ active = true;
+
+ /* Check if any user is actively using this cache */
+ ret = check_cc_validity(location, realm, princ, &valid);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ *_active = active;
+ *_valid = valid;
+ return EOK;
+}
+
+const char *
+cc_keyring_cache_for_princ(TALLOC_CTX *mem_ctx, const char *location,
+ const char *princ)
+{
+ krb5_context context = NULL;
+ krb5_error_code krberr;
+ char *name = NULL;
+ const char *residual;
+ size_t i;
+ size_t count;
+ krb5_principal client_principal = NULL;
+
+ residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+ if (!residual) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot get residual from %s\n",
+ location));
+ return NULL;
+ }
+
+ /* residual already points to a subsidiary cache if it of the
+ * form "KEYRING:<type>:<UID>:krb5_cc_XXXXXXX"
+ * For simplicity, we'll count the colons, up to three.
+ */
+ i = count = 0;
+ while (residual[i] && count < 3) {
+ if (residual[i] == ':') {
+ count ++;
+ }
+ i++;
+ }
+
+ if (count >= 3) {
+ return talloc_strdup(mem_ctx, location);
+ }
+
+ krberr = krb5_init_context(&context);
+ if (krberr) {
+ DEBUG(SSSDBG_OP_FAILURE, ("Failed to init kerberos context\n"));
+ return NULL;
+ }
+
+ krberr = krb5_parse_name(context, princ, &client_principal);
+ if (krberr != 0) {
+ KRB5_DEBUG(SSSDBG_OP_FAILURE, context, krberr);
+ DEBUG(SSSDBG_CRIT_FAILURE, ("krb5_parse_name failed.\n"));
+ goto done;
+ }
+
+ name = sss_get_ccache_name_for_principal(mem_ctx, context,
+ client_principal, location);
+ if (name == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, ("Could not get full name of ccache\n"));
+ goto done;
+ }
+
+ talloc_zfree(name);
+
+ /* Always return the master name here.
+ * We do the above only to ensure that the
+ * principal-specific name exists and can
+ * be found.
+ */
+ name = talloc_strdup(mem_ctx, location);
+
+done:
+ krb5_free_principal(context, client_principal);
+ krb5_free_context(context);
+
+ return name;
+}
+
+errno_t
+cc_keyring_remove(const char *location)
+{
+ const char *residual;
+
+ residual = sss_krb5_residual_check_type(location, SSS_KRB5_TYPE_KEYRING);
+ if (!residual) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ ("%s is not of type KEYRING:\n", location));
+ return EINVAL;
+ }
+
+ /* No special steps are needed to create a kernel keyring.
+ * Everything is handled in libkrb5.
+ */
+ return EOK;
+}
+
+struct sss_krb5_cc_be keyring_cc = {
+ .type = SSS_KRB5_TYPE_KEYRING,
+ .create = cc_keyring_create,
+ .check_existing = cc_keyring_check_existing,
+ .ccache_for_princ = cc_keyring_cache_for_princ,
+ .remove = cc_keyring_remove
+};
+
#endif /* HAVE_KRB5_CC_COLLECTION */
errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
diff --git a/src/providers/krb5/krb5_utils.h b/src/providers/krb5/krb5_utils.h
index 4a5904cd7..cdc9f2364 100644
--- a/src/providers/krb5/krb5_utils.h
+++ b/src/providers/krb5/krb5_utils.h
@@ -87,12 +87,14 @@ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name,
#ifdef HAVE_KRB5_CC_COLLECTION
extern struct sss_krb5_cc_be dir_cc;
+extern struct sss_krb5_cc_be keyring_cc;
errno_t cc_dir_create(const char *location, pcre *illegal_re,
uid_t uid, gid_t gid, bool private_path);
#endif /* HAVE_KRB5_CC_COLLECTION */
+
errno_t get_domain_or_subdomain(TALLOC_CTX *mem_ctx, struct be_ctx *be_ctx,
char *domain_name,
struct sss_domain_info **dom);
diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
index 457a52c0b..b25ed2491 100644
--- a/src/util/sss_krb5.c
+++ b/src/util/sss_krb5.c
@@ -928,6 +928,7 @@ sss_krb5_free_keytab_entry_contents(krb5_context context,
#define SSS_KRB5_FILE "FILE:"
#define SSS_KRB5_DIR "DIR:"
+#define SSS_KRB5_KEYRING "KEYRING:"
enum sss_krb5_cc_type
sss_krb5_get_type(const char *full_location)
@@ -945,7 +946,12 @@ sss_krb5_get_type(const char *full_location)
sizeof(SSS_KRB5_DIR)-1) == 0) {
return SSS_KRB5_TYPE_DIR;
}
+ else if (strncmp(full_location, SSS_KRB5_KEYRING,
+ sizeof(SSS_KRB5_KEYRING)-1) == 0) {
+ return SSS_KRB5_TYPE_KEYRING;
+ }
#endif /* HAVE_KRB5_CC_COLLECTION */
+
else if (full_location[0] == '/') {
return SSS_KRB5_TYPE_FILE;
}
@@ -973,7 +979,12 @@ sss_krb5_residual_by_type(const char *full_location,
case SSS_KRB5_TYPE_DIR:
offset = sizeof(SSS_KRB5_DIR)-1;
break;
+
+ case SSS_KRB5_TYPE_KEYRING:
+ offset = sizeof(SSS_KRB5_KEYRING)-1;
+ break;
#endif /* HAVE_KRB5_CC_COLLECTION */
+
default:
return NULL;
}
@@ -991,6 +1002,9 @@ sss_krb5_cc_file_path(const char *full_location)
residual = sss_krb5_residual_by_type(full_location, cc_type);
switch(cc_type) {
+#ifdef HAVE_KRB5_CC_COLLECTION
+ case SSS_KRB5_TYPE_KEYRING:
+#endif /* HAVE_KRB5_CC_COLLECTION */
case SSS_KRB5_TYPE_FILE:
return residual;
#ifdef HAVE_KRB5_CC_COLLECTION
diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
index 1c10d4713..b1074f813 100644
--- a/src/util/sss_krb5.h
+++ b/src/util/sss_krb5.h
@@ -147,7 +147,9 @@ enum sss_krb5_cc_type {
SSS_KRB5_TYPE_FILE,
#ifdef HAVE_KRB5_CC_COLLECTION
SSS_KRB5_TYPE_DIR,
+ SSS_KRB5_TYPE_KEYRING,
#endif /* HAVE_KRB5_CC_COLLECTION */
+
SSS_KRB5_TYPE_UNKNOWN
};