summaryrefslogtreecommitdiff
path: root/src/lib/kadm5/str_conv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/kadm5/str_conv.c')
-rw-r--r--src/lib/kadm5/str_conv.c402
1 files changed, 402 insertions, 0 deletions
diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
new file mode 100644
index 000000000000..7cf51d3168e1
--- /dev/null
+++ b/src/lib/kadm5/str_conv.c
@@ -0,0 +1,402 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/kadm5/str_conv.c */
+/*
+ * Copyright (C) 1995-2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Convert between strings and Kerberos internal data. */
+
+#include "k5-int.h"
+#include "admin_internal.h"
+#include "adm_proto.h"
+
+#include <ctype.h>
+
+static const char default_tupleseps[] = ", \t";
+static const char default_ksaltseps[] = ":";
+
+struct flag_table_row {
+ const char *spec; /* Input specifier string */
+ krb5_flags flag; /* Flag */
+ int invert; /* Whether to invert the sense */
+};
+
+static const struct flag_table_row ftbl[] = {
+ {"allow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 1},
+ {"postdateable", KRB5_KDB_DISALLOW_POSTDATED, 1},
+ {"disallow_postdated", KRB5_KDB_DISALLOW_POSTDATED, 0},
+ {"allow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},
+ {"forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 1},
+ {"disallow_forwardable", KRB5_KDB_DISALLOW_FORWARDABLE, 0},
+ {"allow_tgs_req", KRB5_KDB_DISALLOW_TGT_BASED, 1},
+ {"tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 1},
+ {"disallow_tgt_based", KRB5_KDB_DISALLOW_TGT_BASED, 0},
+ {"allow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},
+ {"renewable", KRB5_KDB_DISALLOW_RENEWABLE, 1},
+ {"disallow_renewable", KRB5_KDB_DISALLOW_RENEWABLE, 0},
+ {"allow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},
+ {"proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 1},
+ {"disallow_proxiable", KRB5_KDB_DISALLOW_PROXIABLE, 0},
+ {"allow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},
+ {"dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 1},
+ {"disallow_dup_skey", KRB5_KDB_DISALLOW_DUP_SKEY, 0},
+ {"allow_tickets", KRB5_KDB_DISALLOW_ALL_TIX, 1},
+ {"allow_tix", KRB5_KDB_DISALLOW_ALL_TIX, 1},
+ {"disallow_all_tix", KRB5_KDB_DISALLOW_ALL_TIX, 0},
+ {"preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
+ {"requires_pre_auth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
+ {"requires_preauth", KRB5_KDB_REQUIRES_PRE_AUTH, 0},
+ {"hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
+ {"requires_hw_auth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
+ {"requires_hwauth", KRB5_KDB_REQUIRES_HW_AUTH, 0},
+ {"needchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
+ {"pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
+ {"requires_pwchange", KRB5_KDB_REQUIRES_PWCHANGE, 0},
+ {"allow_svr", KRB5_KDB_DISALLOW_SVR, 1},
+ {"service", KRB5_KDB_DISALLOW_SVR, 1},
+ {"disallow_svr", KRB5_KDB_DISALLOW_SVR, 0},
+ {"password_changing_service", KRB5_KDB_PWCHANGE_SERVICE, 0},
+ {"pwchange_service", KRB5_KDB_PWCHANGE_SERVICE, 0},
+ {"pwservice", KRB5_KDB_PWCHANGE_SERVICE, 0},
+ {"md5", KRB5_KDB_SUPPORT_DESMD5, 0},
+ {"support_desmd5", KRB5_KDB_SUPPORT_DESMD5, 0},
+ {"new_princ", KRB5_KDB_NEW_PRINC, 0},
+ {"ok_as_delegate", KRB5_KDB_OK_AS_DELEGATE, 0},
+ {"ok_to_auth_as_delegate", KRB5_KDB_OK_TO_AUTH_AS_DELEGATE, 0},
+ {"no_auth_data_required", KRB5_KDB_NO_AUTH_DATA_REQUIRED, 0},
+ {"lockdown_keys", KRB5_KDB_LOCKDOWN_KEYS, 0},
+};
+#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))
+
+static const char *outflags[] = {
+ "DISALLOW_POSTDATED", /* 0x00000001 */
+ "DISALLOW_FORWARDABLE", /* 0x00000002 */
+ "DISALLOW_TGT_BASED", /* 0x00000004 */
+ "DISALLOW_RENEWABLE", /* 0x00000008 */
+ "DISALLOW_PROXIABLE", /* 0x00000010 */
+ "DISALLOW_DUP_SKEY", /* 0x00000020 */
+ "DISALLOW_ALL_TIX", /* 0x00000040 */
+ "REQUIRES_PRE_AUTH", /* 0x00000080 */
+ "REQUIRES_HW_AUTH", /* 0x00000100 */
+ "REQUIRES_PWCHANGE", /* 0x00000200 */
+ NULL, /* 0x00000400 */
+ NULL, /* 0x00000800 */
+ "DISALLOW_SVR", /* 0x00001000 */
+ "PWCHANGE_SERVICE", /* 0x00002000 */
+ "SUPPORT_DESMD5", /* 0x00004000 */
+ "NEW_PRINC", /* 0x00008000 */
+ NULL, /* 0x00010000 */
+ NULL, /* 0x00020000 */
+ NULL, /* 0x00040000 */
+ NULL, /* 0x00080000 */
+ "OK_AS_DELEGATE", /* 0x00100000 */
+ "OK_TO_AUTH_AS_DELEGATE", /* 0x00200000 */
+ "NO_AUTH_DATA_REQUIRED", /* 0x00400000 */
+ "LOCKDOWN_KEYS", /* 0x00800000 */
+};
+#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))
+
+/*
+ * Given s, which is a normalized flagspec with the prefix stripped off, and
+ * req_neg indicating whether the flagspec is negated, update the toset and
+ * toclear masks.
+ */
+static krb5_error_code
+raw_flagspec_to_mask(const char *s, int req_neg, krb5_flags *toset,
+ krb5_flags *toclear)
+{
+ int found = 0, invert = 0;
+ size_t i;
+ krb5_flags flag;
+ unsigned long ul;
+
+ for (i = 0; !found && i < NFTBL; i++) {
+ if (strcmp(s, ftbl[i].spec) != 0)
+ continue;
+ /* Found a match */
+ found = 1;
+ invert = ftbl[i].invert;
+ flag = ftbl[i].flag;
+ }
+ /* Accept hexadecimal numbers. */
+ if (!found && strncmp(s, "0x", 2) == 0) {
+ /* Assume that krb5_flags are 32 bits long. */
+ ul = strtoul(s, NULL, 16) & 0xffffffff;
+ flag = (krb5_flags)ul;
+ found = 1;
+ }
+ if (!found)
+ return EINVAL;
+ if (req_neg)
+ invert = !invert;
+ if (invert)
+ *toclear &= ~flag;
+ else
+ *toset |= flag;
+ return 0;
+}
+
+/*
+ * Update the toset and toclear flag masks according to flag specifier string
+ * spec, which is of the form {+|-}flagname. toset and toclear can point to
+ * the same flag word.
+ */
+krb5_error_code
+krb5_flagspec_to_mask(const char *spec, krb5_flags *toset, krb5_flags *toclear)
+{
+ int req_neg = 0;
+ char *copy, *cp, *s;
+ krb5_error_code retval;
+
+ s = copy = strdup(spec);
+ if (s == NULL)
+ return ENOMEM;
+
+ if (*s == '-') {
+ req_neg = 1;
+ s++;
+ } else if (*s == '+')
+ s++;
+
+ for (cp = s; *cp != '\0'; cp++) {
+ /* Transform hyphens to underscores.*/
+ if (*cp == '-')
+ *cp = '_';
+ /* Downcase. */
+ if (isupper((unsigned char)*cp))
+ *cp = tolower((unsigned char)*cp);
+ }
+ retval = raw_flagspec_to_mask(s, req_neg, toset, toclear);
+ free(copy);
+ return retval;
+}
+
+/*
+ * Copy the flag name of flagnum to outstr. On error, outstr points to a null
+ * pointer.
+ */
+krb5_error_code
+krb5_flagnum_to_string(int flagnum, char **outstr)
+{
+ const char *s = NULL;
+
+ *outstr = NULL;
+ if ((unsigned int)flagnum < NOUTFLAGS)
+ s = outflags[flagnum];
+ if (s == NULL) {
+ /* Assume that krb5_flags are 32 bits long. */
+ if (asprintf(outstr, "0x%08lx", 1UL << flagnum) == -1)
+ *outstr = NULL;
+ } else {
+ *outstr = strdup(s);
+ }
+ if (*outstr == NULL)
+ return ENOMEM;
+ return 0;
+}
+
+/*
+ * Create a null-terminated array of string representations of flags. Store a
+ * null pointer into outarray if there would be no strings.
+ */
+krb5_error_code
+krb5_flags_to_strings(krb5_int32 flags, char ***outarray)
+{
+ char **a = NULL, **a_new = NULL, **ap;
+ size_t amax = 0, i;
+ krb5_error_code retval;
+
+ *outarray = NULL;
+
+ /* Assume that krb5_flags are 32 bits long. */
+ for (i = 0; i < 32; i++) {
+ if (!(flags & (1UL << i)))
+ continue;
+
+ a_new = realloc(a, (amax + 2) * sizeof(*a));
+ if (a_new == NULL) {
+ retval = ENOMEM;
+ goto cleanup;
+ }
+ a = a_new;
+ retval = krb5_flagnum_to_string(i, &a[amax++]);
+ a[amax] = NULL;
+ if (retval)
+ goto cleanup;
+ }
+ *outarray = a;
+ return 0;
+cleanup:
+ for (ap = a; ap != NULL && *ap != NULL; ap++) {
+ free(*ap);
+ }
+ free(a);
+ return retval;
+}
+
+/*
+ * krb5_keysalt_is_present() - Determine if a key/salt pair is present
+ * in a list of key/salt tuples.
+ *
+ * Salttype may be negative to indicate a search for only a enctype.
+ */
+krb5_boolean
+krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype)
+ krb5_key_salt_tuple *ksaltlist;
+ krb5_int32 nksalts;
+ krb5_enctype enctype;
+ krb5_int32 salttype;
+{
+ krb5_boolean foundit;
+ int i;
+
+ foundit = 0;
+ if (ksaltlist) {
+ for (i=0; i<nksalts; i++) {
+ if ((ksaltlist[i].ks_enctype == enctype) &&
+ ((ksaltlist[i].ks_salttype == salttype) ||
+ (salttype < 0))) {
+ foundit = 1;
+ break;
+ }
+ }
+ }
+ return(foundit);
+}
+
+/* NOTE: This is a destructive parser (writes NULs). */
+static krb5_error_code
+string_to_keysalt(char *s, const char *ksaltseps,
+ krb5_enctype *etype, krb5_int32 *stype)
+{
+ char *sp;
+ const char *ksseps = (ksaltseps != NULL) ? ksaltseps : default_ksaltseps;
+ krb5_error_code ret = 0;
+
+ sp = strpbrk(s, ksseps);
+ if (sp != NULL) {
+ *sp++ = '\0';
+ }
+ ret = krb5_string_to_enctype(s, etype);
+ if (ret)
+ return ret;
+
+ /* Default to normal salt if omitted. */
+ *stype = KRB5_KDB_SALTTYPE_NORMAL;
+ if (sp == NULL)
+ return 0;
+ return krb5_string_to_salttype(sp, stype);
+}
+
+/*
+ * krb5_string_to_keysalts() - Convert a string representation to a list
+ * of key/salt tuples.
+ */
+krb5_error_code
+krb5_string_to_keysalts(const char *string, const char *tupleseps,
+ const char *ksaltseps, krb5_boolean dups,
+ krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp)
+{
+ char *copy, *p, *ksp;
+ char *tlasts = NULL;
+ const char *tseps = (tupleseps != NULL) ? tupleseps : default_tupleseps;
+ krb5_int32 nksalts = 0;
+ krb5_int32 stype;
+ krb5_enctype etype;
+ krb5_error_code ret = 0;
+ krb5_key_salt_tuple *ksalts = NULL, *ksalts_new = NULL;
+
+ *ksaltp = NULL;
+ *nksaltp = 0;
+ p = copy = strdup(string);
+ if (p == NULL)
+ return ENOMEM;
+ while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {
+ /* Pass a null pointer to subsequent calls to strtok_r(). */
+ p = NULL;
+ ret = string_to_keysalt(ksp, ksaltseps, &etype, &stype);
+ if (ret)
+ goto cleanup;
+
+ /* Ignore duplicate keysalts if caller asks. */
+ if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))
+ continue;
+
+ ksalts_new = realloc(ksalts, (nksalts + 1) * sizeof(*ksalts));
+ if (ksalts_new == NULL) {
+ ret = ENOMEM;
+ goto cleanup;
+ }
+ ksalts = ksalts_new;
+ ksalts[nksalts].ks_enctype = etype;
+ ksalts[nksalts].ks_salttype = stype;
+ nksalts++;
+ }
+ *ksaltp = ksalts;
+ *nksaltp = nksalts;
+cleanup:
+ if (ret)
+ free(ksalts);
+ free(copy);
+ return ret;
+}
+
+/*
+ * krb5_keysalt_iterate() - Do something for each unique key/salt
+ * combination.
+ *
+ * If ignoresalt set, then salttype is ignored.
+ */
+krb5_error_code
+krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg)
+ krb5_key_salt_tuple *ksaltlist;
+ krb5_int32 nksalt;
+ krb5_boolean ignoresalt;
+ krb5_error_code (*iterator) (krb5_key_salt_tuple *, krb5_pointer);
+ krb5_pointer arg;
+{
+ int i;
+ krb5_error_code kret;
+ krb5_key_salt_tuple scratch;
+
+ kret = 0;
+ for (i=0; i<nksalt; i++) {
+ scratch.ks_enctype = ksaltlist[i].ks_enctype;
+ scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype;
+ if (!krb5_keysalt_is_present(ksaltlist,
+ i,
+ scratch.ks_enctype,
+ scratch.ks_salttype)) {
+ kret = (*iterator)(&scratch, arg);
+ if (kret)
+ break;
+ }
+ }
+ return(kret);
+}