summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJan Zeleny <jzeleny@redhat.com>2011-03-29 02:50:28 -0400
committerStephen Gallagher <sgallagh@redhat.com>2011-04-25 08:06:34 -0400
commitcfd79b92d3813ed53ef51ae2cf93be6287e73a27 (patch)
tree1607a23b6699d270cd6a783b0e7e9678100b5538 /src
parent743475e5d730f1438bff4bb086600186adfe8311 (diff)
Extend and move function for finding principal in keytab
The function now supports finding principal in keytab not only based on realm, but based on both realm and primary/instance parts. The function also supports * wildcard at the beginning or at the end of primary principal part. The function for finding principal has been moved to util/sss_krb5.c, so it can be used in other parts of the code.
Diffstat (limited to 'src')
-rw-r--r--src/providers/krb5/krb5_child.c82
-rw-r--r--src/util/sss_krb5.c155
-rw-r--r--src/util/sss_krb5.h6
3 files changed, 163 insertions, 80 deletions
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 335da423..1ed63f6b 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -30,6 +30,7 @@
#include <security/pam_modules.h>
#include "util/util.h"
+#include "util/sss_krb5.h"
#include "util/user_info_msg.h"
#include "providers/child_common.h"
#include "providers/dp_backend.h"
@@ -492,85 +493,6 @@ static errno_t add_ticket_times_to_response(struct krb5_req *kr)
return ret;
}
-static krb5_error_code find_principal_in_keytab(krb5_context ctx,
- krb5_keytab keytab,
- const char *realm,
- krb5_principal *princ)
-{
- krb5_error_code kerr;
- krb5_error_code kt_err;
- krb5_error_code kerr_d;
- krb5_kt_cursor cursor;
- krb5_keytab_entry entry;
- bool principal_found = false;
-
- memset(&cursor, 0, sizeof(cursor));
- kerr = krb5_kt_start_seq_get(ctx, keytab, &cursor);
- if (kerr != 0) {
- DEBUG(1, ("krb5_kt_start_seq_get failed.\n"));
- KRB5_DEBUG(1, kerr);
- return kerr;
- }
-
- /* We look for the first entry from our realm or take the last one */
- memset(&entry, 0, sizeof(entry));
- while ((kt_err = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) {
- if (krb5_princ_realm(ctx, entry.principal)->length == strlen(realm) &&
- strncmp(krb5_princ_realm(ctx, entry.principal)->data, realm,
- krb5_princ_realm(ctx, entry.principal)->length) == 0) {
- DEBUG(9, ("Found keytab entry with the realm of the credential.\n"));
- principal_found = true;
- break;
- }
-
- kerr = krb5_free_keytab_entry_contents(ctx, &entry);
- if (kerr != 0) {
- DEBUG(1, ("Failed to free keytab entry.\n"));
- }
- memset(&entry, 0, sizeof(entry));
- }
-
- /* Close the keytab here. Even though we're using cursors, the file
- * handle is stored in the krb5_keytab structure, and it gets
- * overwritten by other keytab calls, creating a leak. */
- kerr = krb5_kt_end_seq_get(ctx, keytab, &cursor);
- if (kerr != 0) {
- DEBUG(1, ("krb5_kt_end_seq_get failed.\n"));
- goto done;
- }
-
- if (!principal_found) {
- kerr = KRB5_KT_NOTFOUND;
- DEBUG(1, ("No principal from realm [%s] found in keytab.\n", realm));
- goto done;
- }
-
- /* check if we got any errors from krb5_kt_next_entry */
- if (kt_err != 0 && kt_err != KRB5_KT_END) {
- DEBUG(1, ("Error while reading keytab.\n"));
- KRB5_DEBUG(1, kerr);
- goto done;
- }
-
- kerr = krb5_copy_principal(ctx, entry.principal, princ);
- if (kerr != 0) {
- DEBUG(1, ("krb5_copy_principal failed.\n"));
- KRB5_DEBUG(1, kerr);
- goto done;
- }
-
- kerr = 0;
-
-done:
- kerr_d = krb5_free_keytab_entry_contents(ctx, &entry);
- if (kerr_d != 0) {
- DEBUG(1, ("Failed to free keytab entry.\n"));
- KRB5_DEBUG(1, kerr_d);
- }
-
- return kerr;
-}
-
static krb5_error_code validate_tgt(struct krb5_req *kr)
{
krb5_error_code kerr;
@@ -1338,7 +1260,7 @@ static krb5_error_code check_fast_ccache(krb5_context ctx, const char *realm,
goto done;
}
- kerr = find_principal_in_keytab(ctx, keytab, realm, &client_princ);
+ kerr = find_principal_in_keytab(ctx, keytab, NULL, realm, &client_princ);
if (kerr != 0) {
DEBUG(1, ("find_principal_in_keytab failed.\n"));
goto done;
diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c
index 894dd443..459f48b5 100644
--- a/src/util/sss_krb5.c
+++ b/src/util/sss_krb5.c
@@ -188,6 +188,161 @@ int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
return EOK;
}
+
+enum matching_mode {MODE_NORMAL, MODE_PREFIX, MODE_POSTFIX};
+/**
+ * We only have primary and instances stored separately, we need to
+ * join them to one string and compare that string.
+ *
+ * @param ctx kerberos context
+ * @param principal principal we want to match
+ * @param pattern_primary primary part of the principal we want to
+ * perform matching against. It is possible to use * wildcard
+ * at the beginning or at the end of the string. If NULL, it
+ * will act as "*"
+ * @param pattern_realm realm part of the principal we want to perform
+ * the matching against. If NULL, it will act as "*"
+ */
+static bool match_principal(krb5_context ctx,
+ krb5_principal principal,
+ const char *pattern_primary,
+ const char *pattern_realm)
+{
+ krb5_data *realm_data;
+ char *primary = NULL;
+ char *primary_str = NULL;
+ int primary_str_len = 0;
+ int tmp_len;
+ int len_diff;
+
+ int mode = MODE_NORMAL;
+ TALLOC_CTX *tmp_ctx;
+ bool ret;
+
+ realm_data = krb5_princ_realm(ctx, principal);
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) {
+ DEBUG(1, ("talloc_new failed\n"));
+ return false;
+ }
+
+ if (pattern_primary) {
+ tmp_len = strlen(pattern_primary);
+ if (pattern_primary[tmp_len] == '*') {
+ mode = MODE_PREFIX;
+ primary_str = talloc_strdup(tmp_ctx, pattern_primary);
+ primary_str[tmp_len] = '\0';
+ primary_str_len = tmp_len-1;
+ } else if (pattern_primary[0] == '*') {
+ mode = MODE_POSTFIX;
+ primary_str = talloc_strdup(tmp_ctx, pattern_primary+1);
+ primary_str_len = tmp_len-1;
+ }
+
+ krb5_unparse_name_flags(ctx, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+ &primary);
+
+ len_diff = strlen(primary)-primary_str_len;
+
+ if ((mode == MODE_NORMAL &&
+ strcmp(primary, pattern_primary) != 0) ||
+ (mode == MODE_PREFIX &&
+ strncmp(primary, primary_str, primary_str_len) != 0) ||
+ (mode == MODE_POSTFIX &&
+ strcmp(primary+len_diff, primary_str) != 0)) {
+ ret = false;
+ goto done;
+ }
+ }
+
+ if (!pattern_realm || (realm_data->length == strlen(pattern_realm) &&
+ strncmp(realm_data->data, pattern_realm, realm_data->length) == 0)) {
+ DEBUG(7, ("Principal matched to the sample (%s@%s).\n", pattern_primary,
+ pattern_realm));
+ ret = true;
+ }
+
+done:
+ free(primary);
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+krb5_error_code find_principal_in_keytab(krb5_context ctx,
+ krb5_keytab keytab,
+ const char *pattern_primary,
+ const char *pattern_realm,
+ krb5_principal *princ)
+{
+ krb5_error_code kerr;
+ krb5_error_code kt_err;
+ krb5_error_code kerr_d;
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ bool principal_found = false;
+
+ memset(&cursor, 0, sizeof(cursor));
+ kerr = krb5_kt_start_seq_get(ctx, keytab, &cursor);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_kt_start_seq_get failed.\n"));
+ return kerr;
+ }
+
+ DEBUG(9, ("Trying to find principal %s@%s in keytab.\n", pattern_primary, pattern_realm));
+ memset(&entry, 0, sizeof(entry));
+ while ((kt_err = krb5_kt_next_entry(ctx, keytab, &entry, &cursor)) == 0) {
+ principal_found = match_principal(ctx, entry.principal, pattern_primary, pattern_realm);
+ if (principal_found) {
+ break;
+ }
+
+ kerr = krb5_free_keytab_entry_contents(ctx, &entry);
+ if (kerr != 0) {
+ DEBUG(1, ("Failed to free keytab entry.\n"));
+ }
+ memset(&entry, 0, sizeof(entry));
+ }
+
+ /* Close the keytab here. Even though we're using cursors, the file
+ * handle is stored in the krb5_keytab structure, and it gets
+ * overwritten by other keytab calls, creating a leak. */
+ kerr = krb5_kt_end_seq_get(ctx, keytab, &cursor);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_kt_end_seq_get failed.\n"));
+ goto done;
+ }
+
+ if (!principal_found) {
+ kerr = KRB5_KT_NOTFOUND;
+ DEBUG(1, ("No principal matching %s@%s found in keytab.\n",
+ pattern_primary, pattern_realm));
+ goto done;
+ }
+
+ /* check if we got any errors from krb5_kt_next_entry */
+ if (kt_err != 0 && kt_err != KRB5_KT_END) {
+ DEBUG(1, ("Error while reading keytab.\n"));
+ goto done;
+ }
+
+ kerr = krb5_copy_principal(ctx, entry.principal, princ);
+ if (kerr != 0) {
+ DEBUG(1, ("krb5_copy_principal failed.\n"));
+ goto done;
+ }
+
+ kerr = 0;
+
+done:
+ kerr_d = krb5_free_keytab_entry_contents(ctx, &entry);
+ if (kerr_d != 0) {
+ DEBUG(1, ("Failed to free keytab entry.\n"));
+ }
+
+ return kerr;
+}
+
const char *KRB5_CALLCONV sss_krb5_get_error_message(krb5_context ctx,
krb5_error_code ec)
{
diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h
index 0a82315c..f25f3285 100644
--- a/src/util/sss_krb5.h
+++ b/src/util/sss_krb5.h
@@ -58,6 +58,12 @@ int sss_krb5_verify_keytab(const char *principal,
int sss_krb5_verify_keytab_ex(const char *principal, const char *keytab_name,
krb5_context context, krb5_keytab keytab);
+krb5_error_code find_principal_in_keytab(krb5_context ctx,
+ krb5_keytab keytab,
+ const char *pattern_primary,
+ const char *pattern_realm,
+ krb5_principal *princ);
+
#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_EXPIRE_CALLBACK
typedef void krb5_expire_callback_func(krb5_context context, void *data,
krb5_timestamp password_expiration,