summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2011-09-21 16:28:54 +0000
committerGreg Hudson <ghudson@mit.edu>2011-09-21 16:28:54 +0000
commit237e57c297708c8009cf2af4833b78abc4e05bbc (patch)
tree14a0837807841de1b1211b1ecb7a69131c24d476
parente3e006d3aedccb88d5238d0175c81a6bf535c18f (diff)
downloadkrb5-237e57c297708c8009cf2af4833b78abc4e05bbc.tar.gz
krb5-237e57c297708c8009cf2af4833b78abc4e05bbc.tar.xz
krb5-237e57c297708c8009cf2af4833b78abc4e05bbc.zip
Add KRB5_TL_STRING_ATTRS and libkdb5 accessors
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25214 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/include/kdb.h34
-rw-r--r--src/lib/kdb/Makefile.in10
-rw-r--r--src/lib/kdb/kdb5.c178
-rw-r--r--src/lib/kdb/libkdb5.exports5
-rw-r--r--src/lib/kdb/t_stringattr.c94
-rw-r--r--src/lib/krb5/error_tables/kdb5_err.et1
6 files changed, 321 insertions, 1 deletions
diff --git a/src/include/kdb.h b/src/include/kdb.h
index b666225e6..31f48b151 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -145,6 +145,13 @@ typedef struct _krb5_tl_data {
krb5_octet * tl_data_contents;
} krb5_tl_data;
+/* String attributes (currently stored inside tl-data) map C string keys to
+ * values. They can be set via kadmin and consumed by KDC plugins. */
+typedef struct krb5_string_attr_st {
+ char *key;
+ char *value;
+} krb5_string_attr;
+
/*
* If this ever changes up the version number and make the arrays be as
* big as necessary.
@@ -235,6 +242,10 @@ typedef struct __krb5_key_salt_tuple {
#define KRB5_TL_ACTKVNO 0x0009
#define KRB5_TL_MKEY_AUX 0x000a
+/* String attributes may not always be represented in tl-data. kadmin clients
+ * must use the modify_strings and get_strings RPCs. */
+#define KRB5_TL_STRING_ATTRS 0x000b
+
#define KRB5_TL_PAC_LOGON_INFO 0x0100 /* NDR encoded validation info */
#define KRB5_TL_SERVER_REFERRAL 0x0200 /* ASN.1 encoded ServerReferralInfo */
#define KRB5_TL_SVR_REFERRAL_DATA 0x0300 /* ASN.1 encoded PA-SVR-REFERRAL-DATA */
@@ -538,6 +549,23 @@ krb5_dbe_lookup_last_admin_unlock( krb5_context context,
krb5_db_entry * entry,
krb5_timestamp * stamp);
+/* Retrieve the set of string attributes in entry, in no particular order.
+ * Free *strings_out with krb5_dbe_free_strings when done. */
+krb5_error_code
+krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry,
+ krb5_string_attr **strings_out, int *count_out);
+
+/* Retrieve a single string attribute from entry, or NULL if there is no
+ * attribute for key. Free *value_out with krb5_dbe_free_string when done. */
+krb5_error_code
+krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry,
+ const char *key, char **value_out);
+
+/* Change or add a string attribute in entry, or delete it if value is NULL. */
+krb5_error_code
+krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry,
+ const char *key, const char *value);
+
krb5_error_code
krb5_dbe_delete_tl_data( krb5_context context,
krb5_db_entry * entry,
@@ -741,6 +769,12 @@ krb5_dbe_free_mkey_aux_list(krb5_context, krb5_mkey_aux_node *);
void
krb5_dbe_free_tl_data(krb5_context, krb5_tl_data *);
+void
+krb5_dbe_free_strings(krb5_context, krb5_string_attr *, int count);
+
+void
+krb5_dbe_free_string(krb5_context, char *);
+
#define KRB5_KDB_DEF_FLAGS 0
#define KDB_MAX_DB_NAME 128
diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in
index c49e1b56c..e8f44ae2f 100644
--- a/src/lib/kdb/Makefile.in
+++ b/src/lib/kdb/Makefile.in
@@ -1,5 +1,6 @@
mydir=lib$(S)kdb
BUILDTOP=$(REL)..$(S)..
+RUN_SETUP = @KRB5_RUN_ENV@
KRB5_RUN_ENV = @KRB5_RUN_ENV@
KRB5_CONFIG_SETUP = KRB5_CONFIG=$(top_srcdir)/config-files/krb5.conf ; export KRB5_CONFIG ;
PROG_LIBPATH=-L$(TOPLIBD)
@@ -56,12 +57,19 @@ STLIBOBJS= \
all-unix:: all-liblinks
install-unix:: install-libs
clean-unix:: clean-liblinks clean-libs clean-libobjs
- $(RM) adb_err.c adb_err.h
+ $(RM) adb_err.c adb_err.h t_stringattr.o t_stringattr
+check-unix:: t_stringattr
+ KRB5_CONFIG=$(top_srcdir)/config-files/krb5.conf; export KRB5_CONFIG; \
+ $(RUN_SETUP) $(VALGRIND) ./t_stringattr
generate-files-mac: darwin.exports
depend:: adb_err.h
+t_stringattr: t_stringattr.o $(KDB5_DEPLIBS) $(KADM_COMM_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ t_stringattr.o $(KDB5_LIBS) $(KADM_COMM_LIBS) \
+ $(KRB5_BASE_LIBS)
+
@lib_frag@
@libobj_frag@
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index b82bbcb40..4dfe66151 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -162,6 +162,27 @@ krb5_dbe_free_tl_data(krb5_context context, krb5_tl_data *tl_data)
}
}
+void
+krb5_dbe_free_strings(krb5_context context, krb5_string_attr *strings,
+ int count)
+{
+ int i;
+
+ if (strings == NULL)
+ return;
+ for (i = 0; i < count; i++) {
+ free(strings[i].key);
+ free(strings[i].value);
+ }
+ free(strings);
+}
+
+void
+krb5_dbe_free_string(krb5_context context, char *string)
+{
+ free(string);
+}
+
/* Set *section to the appropriate section to use for a database module's
* profile queries. The caller must free the result. */
static krb5_error_code
@@ -1960,6 +1981,163 @@ krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
return (krb5_dbe_update_tl_data(context, entry, &tl_data));
}
+/*
+ * Prepare to iterate over the string attributes of entry. The returned
+ * pointers are aliases into entry's tl_data (or into an empty string literal)
+ * and remain valid until the entry's tl_data is changed.
+ */
+static krb5_error_code
+begin_attrs(krb5_context context, krb5_db_entry *entry, const char **pos_out,
+ const char **end_out)
+{
+ krb5_error_code code;
+ krb5_tl_data tl_data;
+
+ *pos_out = *end_out = NULL;
+ tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
+ code = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
+ if (code)
+ return code;
+
+ /* Copy the current mapping to buf, updating key with value if found. */
+ *pos_out = (const char *)tl_data.tl_data_contents;
+ *end_out = *pos_out + tl_data.tl_data_length;
+ return 0;
+}
+
+/* Find the next key and value pair in *pos and update *pos. */
+static krb5_boolean
+next_attr(const char **pos, const char *end, const char **key_out,
+ const char **val_out)
+{
+ const char *key, *key_end, *val, *val_end;
+
+ *key_out = *val_out = NULL;
+ if (*pos == end)
+ return FALSE;
+ key = *pos;
+ key_end = memchr(key, '\0', end - key);
+ if (key_end == NULL) /* Malformed representation; give up. */
+ return FALSE;
+ val = key_end + 1;
+ val_end = memchr(val, '\0', end - val);
+ if (val_end == NULL) /* Malformed representation; give up. */
+ return FALSE;
+
+ *key_out = key;
+ *val_out = val;
+ *pos = val_end + 1;
+ return TRUE;
+}
+
+krb5_error_code
+krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry,
+ krb5_string_attr **strings_out, int *count_out)
+{
+ krb5_error_code code;
+ const char *pos, *end, *mapkey, *mapval;
+ char *key = NULL, *val = NULL;
+ krb5_string_attr *strings = NULL, *newstrings;
+ int count = 0;
+
+ *strings_out = NULL;
+ *count_out = 0;
+ code = begin_attrs(context, entry, &pos, &end);
+ if (code)
+ return code;
+
+ while (next_attr(&pos, end, &mapkey, &mapval)) {
+ /* Add a copy of mapkey and mapvalue to strings. */
+ key = strdup(mapkey);
+ val = strdup(mapval);
+ newstrings = realloc(strings, (count + 1) * sizeof(*strings));
+ if (key == NULL || val == NULL || newstrings == NULL) {
+ free(key);
+ free(val);
+ krb5_dbe_free_strings(context, strings, count);
+ return ENOMEM;
+ }
+ strings = newstrings;
+ strings[count].key = key;
+ strings[count].value = val;
+ count++;
+ }
+
+ *strings_out = strings;
+ *count_out = count;
+ return 0;
+}
+
+krb5_error_code
+krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry,
+ const char *key, char **value_out)
+{
+ krb5_error_code code;
+ const char *pos, *end, *mapkey, *mapval;
+
+ *value_out = NULL;
+ code = begin_attrs(context, entry, &pos, &end);
+ if (code)
+ return code;
+ while (next_attr(&pos, end, &mapkey, &mapval)) {
+ if (strcmp(mapkey, key) == 0) {
+ *value_out = strdup(mapval);
+ return (*value_out == NULL) ? ENOMEM : 0;
+ }
+ }
+
+ return 0;
+}
+
+krb5_error_code
+krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry,
+ const char *key, const char *value)
+{
+ krb5_error_code code;
+ const char *pos, *end, *mapkey, *mapval;
+ struct k5buf buf;
+ krb5_boolean found = FALSE;
+ krb5_tl_data tl_data;
+ ssize_t len;
+
+ /* Copy the current mapping to buf, updating key with value if found. */
+ code = begin_attrs(context, entry, &pos, &end);
+ if (code)
+ return code;
+ krb5int_buf_init_dynamic(&buf);
+ while (next_attr(&pos, end, &mapkey, &mapval)) {
+ if (strcmp(mapkey, key) == 0) {
+ if (value != NULL) {
+ krb5int_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
+ krb5int_buf_add_len(&buf, value, strlen(value) + 1);
+ }
+ found = TRUE;
+ } else {
+ krb5int_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
+ krb5int_buf_add_len(&buf, mapval, strlen(mapval) + 1);
+ }
+ }
+
+ /* If key wasn't found in the map, add a new entry for it. */
+ if (!found && value != NULL) {
+ krb5int_buf_add_len(&buf, key, strlen(key) + 1);
+ krb5int_buf_add_len(&buf, value, strlen(value) + 1);
+ }
+
+ len = krb5int_buf_len(&buf);
+ if (len == -1)
+ return ENOMEM;
+ if (len > 65535)
+ return KRB5_KDB_STRINGS_TOOLONG;
+ tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
+ tl_data.tl_data_contents = (krb5_octet *)krb5int_buf_data(&buf);
+ tl_data.tl_data_length = len;
+
+ code = krb5_dbe_update_tl_data(context, entry, &tl_data);
+ krb5int_free_buf(&buf);
+ return code;
+}
+
krb5_error_code
krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry,
krb5_int16 tl_data_type)
diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports
index f9f66eba2..3ea179a46 100644
--- a/src/lib/kdb/libkdb5.exports
+++ b/src/lib/kdb/libkdb5.exports
@@ -43,7 +43,11 @@ krb5_dbe_free_actkvno_list
krb5_dbe_free_key_data_contents
krb5_dbe_free_mkey_aux_list
krb5_dbe_free_key_list
+krb5_dbe_free_string
+krb5_dbe_free_strings
krb5_dbe_get_mkvno
+krb5_dbe_get_string
+krb5_dbe_get_strings
krb5_dbe_lookup_last_admin_unlock
krb5_dbe_lookup_last_pwd_change
krb5_dbe_lookup_actkvno
@@ -52,6 +56,7 @@ krb5_dbe_lookup_mkvno
krb5_dbe_lookup_mod_princ_data
krb5_dbe_lookup_tl_data
krb5_dbe_search_enctype
+krb5_dbe_set_string
krb5_dbe_update_actkvno
krb5_dbe_update_last_admin_unlock
krb5_dbe_update_last_pwd_change
diff --git a/src/lib/kdb/t_stringattr.c b/src/lib/kdb/t_stringattr.c
new file mode 100644
index 000000000..8b943124c
--- /dev/null
+++ b/src/lib/kdb/t_stringattr.c
@@ -0,0 +1,94 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/kdb/t_strings.c - Test program for KDB string attribute functions */
+/*
+ * Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include <kdb.h>
+
+/*
+ * This program exercises the KDB entry APIs for string attributes. It relies
+ * on some implementation knowledge:
+ *
+ * - The APIs will work on a DB entry initialized to all zeros (because it has
+ * an empty tl_data list).
+ *
+ * - Attribute order in krb5_dbe_get_strings matches attribute insertion order.
+ */
+
+int
+main()
+{
+ krb5_db_entry *ent;
+ krb5_context context;
+ krb5_string_attr *strings;
+ char *val;
+ int count;
+
+ assert(krb5_init_context(&context) == 0);
+
+ /* Start with an empty entry. */
+ ent = krb5_db_alloc(context, NULL, sizeof(*ent));
+ if (ent == NULL)
+ return ENOMEM;
+ memset(ent, 0, sizeof(*ent));
+
+ /* Check that the entry has no strings to start. */
+ assert(krb5_dbe_get_strings(context, ent, &strings, &count) == 0);
+ assert(strings == NULL && count == 0);
+ krb5_dbe_free_strings(context, strings, count);
+
+ /* Check that we get a null value querying a specific attribute. */
+ assert(krb5_dbe_get_string(context, ent, "foo", &val) == 0);
+ assert(val == NULL);
+
+ /* Set some attributes one at a time, including a deletion. */
+ assert(krb5_dbe_set_string(context, ent, "eggs", "dozen") == 0);
+ assert(krb5_dbe_set_string(context, ent, "price", "right") == 0);
+ assert(krb5_dbe_set_string(context, ent, "eggs", NULL) == 0);
+ assert(krb5_dbe_set_string(context, ent, "time", "flies") == 0);
+
+ /* Query each attribute. */
+ assert(krb5_dbe_get_string(context, ent, "price", &val) == 0);
+ assert(strcmp(val, "right") == 0);
+ krb5_dbe_free_string(context, val);
+ assert(krb5_dbe_get_string(context, ent, "time", &val) == 0);
+ assert(strcmp(val, "flies") == 0);
+ krb5_dbe_free_string(context, val);
+ assert(krb5_dbe_get_string(context, ent, "eggs", &val) == 0);
+ assert(val == NULL);
+
+ /* Query the list of attributes and verify it. */
+ assert(krb5_dbe_get_strings(context, ent, &strings, &count) == 0);
+ assert(count == 2);
+ assert(strcmp(strings[0].key, "price") == 0);
+ assert(strcmp(strings[0].value, "right") == 0);
+ assert(strcmp(strings[1].key, "time") == 0);
+ assert(strcmp(strings[1].value, "flies") == 0);
+ krb5_dbe_free_strings(context, strings, count);
+
+ krb5_db_free_principal(context, ent);
+ krb5_free_context(context);
+ return 0;
+}
diff --git a/src/lib/krb5/error_tables/kdb5_err.et b/src/lib/krb5/error_tables/kdb5_err.et
index 6fb19d031..1b08ec1a6 100644
--- a/src/lib/krb5/error_tables/kdb5_err.et
+++ b/src/lib/krb5/error_tables/kdb5_err.et
@@ -84,5 +84,6 @@ ec KRB5_LOG_CORRUPT, "Update log is corrupt"
ec KRB5_LOG_ERROR, "Generic update log error"
ec KRB5_KDB_DBTYPE_MISMATCH, "Database module does not match KDC version"
ec KRB5_KDB_POLICY_REF, "Policy is in use"
+ec KRB5_KDB_STRINGS_TOOLONG, "Too much string mapping data"
end