summaryrefslogtreecommitdiff
path: root/third_party/heimdal/admin
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2022-10-31 14:33:09 +1300
committerAndrew Bartlett <abartlet@samba.org>2022-11-02 04:23:34 +0000
commitef28247f3bbbd7cf9daed7a4dba28855496ce38e (patch)
treef97d5b9b41ebbfb7e52269486b3c41d9a0fd9575 /third_party/heimdal/admin
parentab4c7bda8daccdb99adaf6ec7fddf8b5f84be09a (diff)
downloadsamba-ef28247f3bbbd7cf9daed7a4dba28855496ce38e.tar.gz
third_party/heimdal: import lorikeet-heimdal-202210310104 (commit 0fc20ff4144973047e6aaaeb2fc8708bd75be222)
This commit won't compile on it's own, as we need to fix the build system to cope in the next commit. The purpose of this commit is to update to a new lorikeet-heimdal tree that includes the previous two patches and is rebased on a current Heimdal master snapshot. Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Diffstat (limited to 'third_party/heimdal/admin')
-rw-r--r--third_party/heimdal/admin/Makefile.am1
-rw-r--r--third_party/heimdal/admin/add.c178
-rw-r--r--third_party/heimdal/admin/copy.c19
-rw-r--r--third_party/heimdal/admin/get.c38
-rw-r--r--third_party/heimdal/admin/ktutil-commands.in33
-rw-r--r--third_party/heimdal/admin/ktutil.172
-rw-r--r--third_party/heimdal/admin/list.c139
7 files changed, 440 insertions, 40 deletions
diff --git a/third_party/heimdal/admin/Makefile.am b/third_party/heimdal/admin/Makefile.am
index a4a7bb4c0f9..1821d4b2e4b 100644
--- a/third_party/heimdal/admin/Makefile.am
+++ b/third_party/heimdal/admin/Makefile.am
@@ -37,6 +37,7 @@ LDADD = \
$(LIB_hcrypto) \
$(top_builddir)/lib/asn1/libasn1.la \
$(top_builddir)/lib/sl/libsl.la \
+ $(LIB_heimbase) \
$(LIB_readline) \
$(LIB_roken)
diff --git a/third_party/heimdal/admin/add.c b/third_party/heimdal/admin/add.c
index 13580b9bb57..5f1920ff8be 100644
--- a/third_party/heimdal/admin/add.c
+++ b/third_party/heimdal/admin/add.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -32,6 +32,8 @@
*/
#include "ktutil_locl.h"
+#include <heimbase.h>
+#include <base64.h>
RCSID("$Id$");
@@ -153,6 +155,178 @@ kt_add(struct add_options *opt, int argc, char **argv)
krb5_warn(context, ret, "add");
out:
krb5_kt_free_entry(context, &entry);
- krb5_kt_close(context, keytab);
+ if (ret == 0) {
+ ret = krb5_kt_close(context, keytab);
+ if (ret)
+ krb5_warn(context, ret, "Could not write the keytab");
+ } else {
+ krb5_kt_close(context, keytab);
+ }
+ return ret != 0;
+}
+
+/* We might be reading from a pipe, so we can't use rk_undumpdata() */
+static char *
+read_file(FILE *f)
+{
+ size_t alloced;
+ size_t len = 0;
+ size_t bytes;
+ char *res, *end, *p;
+
+ if ((res = malloc(1024)) == NULL)
+ err(1, "Out of memory");
+ alloced = 1024;
+
+ end = res + alloced;
+ p = res;
+ do {
+ if (p == end) {
+ char *tmp;
+
+ if ((tmp = realloc(res, alloced + (alloced > 1))) == NULL)
+ err(1, "Out of memory");
+ alloced += alloced > 1;
+ p = tmp + (p - res);
+ res = tmp;
+ end = res + alloced;
+ }
+ bytes = fread(p, 1, end - p, f);
+ len += bytes;
+ p += bytes;
+ } while (bytes && !feof(f) && !ferror(f));
+
+ if (ferror(f))
+ errx(1, "Could not read all input");
+ if (p == end) {
+ char *tmp;
+
+ if ((tmp = strndup(res, len)) == NULL)
+ err(1, "Out of memory");
+ free(res);
+ res = tmp;
+ }
+ if (strlen(res) != len)
+ err(1, "Embedded NULs in input!");
+ return res;
+}
+
+static void
+json2keytab_entry(heim_dict_t d, krb5_keytab kt, size_t idx)
+{
+ krb5_keytab_entry e;
+ krb5_error_code ret;
+ heim_object_t v;
+ uint64_t u;
+ int64_t i;
+ char *buf = NULL;
+
+ memset(&e, 0, sizeof(e));
+
+ v = heim_dict_get_value(d, HSTR("timestamp"));
+ if (heim_get_tid(v) != HEIM_TID_NUMBER)
+ goto bad;
+ u = heim_number_get_long(v);
+ e.timestamp = u;
+ if (u != (uint64_t)e.timestamp)
+ goto bad;
+
+ v = heim_dict_get_value(d, HSTR("kvno"));
+ if (heim_get_tid(v) != HEIM_TID_NUMBER)
+ goto bad;
+ i = heim_number_get_long(v);
+ e.vno = i;
+ if (i != (int64_t)e.vno)
+ goto bad;
+
+ v = heim_dict_get_value(d, HSTR("enctype_number"));
+ if (heim_get_tid(v) != HEIM_TID_NUMBER)
+ goto bad;
+ i = heim_number_get_long(v);
+ e.keyblock.keytype = i;
+ if (i != (int64_t)e.keyblock.keytype)
+ goto bad;
+
+ v = heim_dict_get_value(d, HSTR("key"));
+ if (heim_get_tid(v) != HEIM_TID_STRING)
+ goto bad;
+ {
+ const char *s = heim_string_get_utf8(v);
+ int declen;
+
+ if ((buf = malloc(strlen(s))) == NULL)
+ err(1, "Out of memory");
+ declen = rk_base64_decode(s, buf);
+ if (declen < 0)
+ goto bad;
+ e.keyblock.keyvalue.data = buf;
+ e.keyblock.keyvalue.length = declen;
+ }
+
+ v = heim_dict_get_value(d, HSTR("principal"));
+ if (heim_get_tid(v) != HEIM_TID_STRING)
+ goto bad;
+ ret = krb5_parse_name(context, heim_string_get_utf8(v), &e.principal);
+ if (ret == 0)
+ ret = krb5_kt_add_entry(context, kt, &e);
+
+ /* For now, ignore aliases; besides, they're never set anywhere in-tree */
+
+ if (ret)
+ krb5_warn(context, ret,
+ "Could not parse or write keytab entry %lu",
+ (unsigned long)idx);
+bad:
+ krb5_free_principal(context, e.principal);
+}
+
+int
+kt_import(void *opt, int argc, char **argv)
+{
+ krb5_error_code ret;
+ krb5_keytab kt;
+ heim_object_t o;
+ heim_error_t json_err = NULL;
+ heim_json_flags_t flags = HEIM_JSON_F_STRICT;
+ FILE *f = argc == 0 ? stdin : fopen(argv[0], "r");
+ size_t alen, i;
+ char *json;
+
+ if (f == NULL)
+ err(1, "Could not open file %s", argv[0]);
+
+ json = read_file(f);
+ o = heim_json_create(json, 10, flags, &json_err);
+ free(json);
+ if (o == NULL) {
+ if (json_err != NULL) {
+ o = heim_error_copy_string(json_err);
+ if (o)
+ errx(1, "Could not parse JSON: %s", heim_string_get_utf8(o));
+ }
+ errx(1, "Could not parse JSON");
+ }
+
+ if (heim_get_tid(o) != HEIM_TID_ARRAY)
+ errx(1, "JSON text must be an array");
+
+ alen = heim_array_get_length(o);
+ if (alen == 0)
+ errx(1, "Empty JSON array; not overwriting keytab");
+
+ if ((kt = ktutil_open_keytab()) == NULL)
+ err(1, "Could not open keytab");
+
+ for (i = 0; i < alen; i++) {
+ heim_object_t e = heim_array_get_value(o, i);
+
+ if (heim_get_tid(e) != HEIM_TID_DICT)
+ warnx("Element %ld of JSON text array is not an object", (long)i);
+ else
+ json2keytab_entry(heim_array_get_value(o, i), kt, i);
+ }
+ ret = krb5_kt_close(context, kt);
+ if (ret)
+ krb5_warn(context, ret, "Could not write the keytab");
return ret != 0;
}
diff --git a/third_party/heimdal/admin/copy.c b/third_party/heimdal/admin/copy.c
index 7b50de1c3cb..8acd6e48ed0 100644
--- a/third_party/heimdal/admin/copy.c
+++ b/third_party/heimdal/admin/copy.c
@@ -47,7 +47,7 @@ compare_keyblock(const krb5_keyblock *a, const krb5_keyblock *b)
}
int
-kt_copy (void *opt, int argc, char **argv)
+kt_copy (struct copy_options *opt, int argc, char **argv)
{
krb5_error_code ret;
krb5_keytab src_keytab, dst_keytab;
@@ -106,11 +106,18 @@ kt_copy (void *opt, int argc, char **argv)
"already exists for %s, keytype %s, kvno %d",
name_str, etype_str, entry.vno);
}
- krb5_kt_free_entry(context, &dummy);
- krb5_kt_free_entry (context, &entry);
- free(name_str);
- free(etype_str);
- continue;
+ if (!opt->copy_duplicates_flag) {
+ krb5_kt_free_entry(context, &dummy);
+ krb5_kt_free_entry (context, &entry);
+ free(name_str);
+ free(etype_str);
+ continue;
+ }
+ /*
+ * Because we can end up trying all keys that match the enctype,
+ * copying entries with duplicate principal, vno, and enctype, but
+ * different keys, can be useful.
+ */
} else if(ret != KRB5_KT_NOTFOUND) {
krb5_warn (context, ret, "%s: fetching %s/%s/%u",
to, name_str, etype_str, entry.vno);
diff --git a/third_party/heimdal/admin/get.c b/third_party/heimdal/admin/get.c
index f56e50f4359..ecd6f6a160e 100644
--- a/third_party/heimdal/admin/get.c
+++ b/third_party/heimdal/admin/get.c
@@ -197,23 +197,27 @@ kt_get(struct get_options *opt, int argc, char **argv)
break;
}
- ret = kadm5_create_principal(kadm_handle, &princ, mask, "thisIs_aUseless.password123");
- if(ret == 0)
- created = 1;
- else if(ret != KADM5_DUP) {
- krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[a]);
- krb5_free_principal(context, princ_ent);
- failed++;
- continue;
- }
- ret = kadm5_randkey_principal_3(kadm_handle, princ_ent, keep, nks, ks,
- &keys, &n_keys);
- if (ret) {
- krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[a]);
- krb5_free_principal(context, princ_ent);
- failed++;
- continue;
- }
+ if (opt->create_flag) {
+ ret = kadm5_create_principal(kadm_handle, &princ, mask, "thisIs_aUseless.password123");
+ if(ret == 0)
+ created = 1;
+ else if(ret != KADM5_DUP) {
+ krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[a]);
+ krb5_free_principal(context, princ_ent);
+ failed++;
+ continue;
+ }
+ }
+ if (opt->change_keys_flag) {
+ ret = kadm5_randkey_principal_3(kadm_handle, princ_ent, keep, nks, ks,
+ &keys, &n_keys);
+ if (ret) {
+ krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[a]);
+ krb5_free_principal(context, princ_ent);
+ failed++;
+ continue;
+ }
+ }
ret = kadm5_get_principal(kadm_handle, princ_ent, &princ,
KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
diff --git a/third_party/heimdal/admin/ktutil-commands.in b/third_party/heimdal/admin/ktutil-commands.in
index 2b771e931a1..a85eb5c5715 100644
--- a/third_party/heimdal/admin/ktutil-commands.in
+++ b/third_party/heimdal/admin/ktutil-commands.in
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 2004-2022 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -151,11 +151,17 @@ command = {
}
command = {
name = "copy"
+ name = "merge"
function = "kt_copy"
+ option = {
+ long = "copy-duplicates"
+ type = "flag"
+ help = "copy entries for the same principal and kvno, but different keys"
+ }
argument = "source destination"
min_args = "2"
max_args = "2"
- help = "Copies one keytab to another."
+ help = "Merges one keytab into another."
}
command = {
name = "get"
@@ -167,6 +173,16 @@ command = {
argument = "principal"
}
option = {
+ long = "create"
+ type = "-flag"
+ help = "do not create the principal"
+ }
+ option = {
+ long = "change-keys"
+ type = "-flag"
+ help = "do not change the principal's keys"
+ }
+ option = {
long = "enctypes"
short = "e"
type = "strings"
@@ -215,6 +231,14 @@ command = {
help = "Change keys for specified principals, and add them to the keytab."
}
command = {
+ name = "import"
+ function = "kt_import"
+ help = "Imports a keytab from JSON output of ktutil list --json --keys."
+ min_args = "0"
+ max_args = "1"
+ argument = "JSON-FILE"
+}
+command = {
name = "list"
option = {
long = "keys"
@@ -226,6 +250,11 @@ command = {
type = "flag"
help = "show timestamps"
}
+ option = {
+ long = "json"
+ type = "flag"
+ help = "output JSON representation"
+ }
max_args = "0"
function = "kt_list"
help = "Show contents of keytab."
diff --git a/third_party/heimdal/admin/ktutil.1 b/third_party/heimdal/admin/ktutil.1
index 125b5e8f0d5..0036edcbd9b 100644
--- a/third_party/heimdal/admin/ktutil.1
+++ b/third_party/heimdal/admin/ktutil.1
@@ -60,7 +60,7 @@ Verbose output.
.Ar command
can be one of the following:
.Bl -tag -width srvconvert
-.It add Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \
+.It Nm add Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \
Oo Fl V Ar kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e Ar enctype Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctype= Ns Ar enctype Oc Oo Fl w Ar password Oc \
@@ -72,7 +72,7 @@ principal to add; if what you really want is to add a new principal to
the keytab, you should consider the
.Ar get
command, which talks to the kadmin server.
-.It change Oo Fl r Ar realm Oc Oo Fl Fl realm= Ns Ar realm Oc \
+.It Nm change Oo Fl r Ar realm Oc Oo Fl Fl realm= Ns Ar realm Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctype= Ns Ar enctype Oc \
Oo Fl Fl a Ar host Oc Oo Fl Fl admin-server= Ns Ar host Oc \
@@ -82,30 +82,68 @@ server for the realm of a keytab entry. Otherwise it will use the
values specified by the options.
.Pp
If no principals are given, all the ones in the keytab are updated.
-.It copy Ar keytab-src Ar keytab-dest
+.It Nm copy Oo Fl Fl copy-duplicates Oc Ar keytab-src Ar keytab-dest
Copies all the entries from
.Ar keytab-src
to
.Ar keytab-dest .
-.It get Oo Fl p Ar admin principal Oc \
+Because entries already in
+.Ar keytab-dest
+are kept, this command functions to merge keytabs.
+Entries for the same principal, key version number, and
+encryption type in the
+.Ar keytab-src
+that are also in the
+.Ar keytab-dest
+will not be copied to the
+.Ar keytab-dest
+unless the
+.Fl Fl copy-duplicates
+option is given.
+.It Nm get Oo Fl p Ar admin principal Oc \
Oo Fl Fl principal= Ns Ar admin principal Oc Oo Fl e Ar enctype Oc \
+Oo Fl Fl no-create Oc \
+Oo Fl Fl no-change-keys Oc \
Oo Fl Fl keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctypes= Ns Ar enctype Oc Oo Fl r Ar realm Oc \
Oo Fl Fl realm= Ns Ar realm Oc Oo Fl a Ar admin server Oc \
Oo Fl Fl admin-server= Ns Ar admin server Oc Oo Fl s Ar server port Oc \
Oo Fl Fl server-port= Ns Ar server port Oc Ar principal ...
+.Pp
For each
.Ar principal ,
-generate a new key for it (creating it if it doesn't already exist),
-and put that key in the keytab.
+get a the principal's keys from the KDC via the kadmin protocol,
+creating the principal if it doesn't exist (unless
+.Fl Fl no-create
+is given), and changing its keys to new random keys (unless
+.Fl Fl no-change-keys
+is given).
.Pp
If no
.Ar realm
is specified, the realm to operate on is taken from the first
principal.
-.It list Oo Fl Fl keys Oc Op Fl Fl timestamp
+.It Nm import Oo JSON-FILE Oc
+Read an array of keytab entries in a JSON file and copy them to
+the keytab.
+Use the
+.Nm list
+command with its
+.Fl Fl json
+option
+and
+.Fl Fl keys
+option to export a keytab.
+.It Nm list Oo Fl Fl keys Oc Op Fl Fl timestamp Oo Op Fl Fl json Oc
List the keys stored in the keytab.
-.It remove Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \
+Use the
+.Fl Fl json
+and
+.Fl Fl keys
+options to export a keytab as JSON for importing with the
+.Nm import
+command.
+.It Nm remove Oo Fl p Ar principal Oc Oo Fl Fl principal= Ns Ar principal Oc \
Oo Fl V kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e enctype Oc \
Oo Fl Fl enctype= Ns Ar enctype Oc
Removes the specified key or keys. Not specifying a
@@ -113,16 +151,28 @@ Removes the specified key or keys. Not specifying a
removes keys with any version number. Not specifying an
.Ar enctype
removes keys of any type.
-.It rename Ar from-principal Ar to-principal
-Renames all entries in the keytab that match the
+.It Nm merge Oo Fl Fl copy-duplicates Oc Ar keytab-src Ar keytab-dest
+An alias for the
+.Nm copy
+command.
+.It Nm rename Ar from-principal Ar to-principal
+Renames all entries for the
+.Ar from-principal
+in the keytab
.Ar from-principal
to
.Ar to-principal .
-.It purge Op Fl Fl age= Ns Ar age
+.It Nm purge Op Fl Fl age= Ns Ar age
Removes all old versions of a key for which there is a newer version
that is at least
.Ar age
(default one week) old.
+Note that this does not update the KDC database.
+The
+.Xr kadmin 1
+command has a
+.Nm prune
+command that can do this on the KDC side.
.El
.Sh SEE ALSO
.Xr kadmin 1
diff --git a/third_party/heimdal/admin/list.c b/third_party/heimdal/admin/list.c
index 31be5461115..9d1e9d5d483 100644
--- a/third_party/heimdal/admin/list.c
+++ b/third_party/heimdal/admin/list.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
+ * Copyright (c) 1997-2022 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -32,6 +32,7 @@
*/
#include "ktutil_locl.h"
+#include <heimbase.h>
#include <rtbl.h>
RCSID("$Id$");
@@ -131,7 +132,8 @@ do_list(struct list_options *opt, const char *keytab_str)
struct rk_strpool *p = NULL;
for (i = 0; i< entry.aliases->len; i++) {
- krb5_unparse_name_fixed(context, entry.principal, buf, sizeof(buf));
+ krb5_unparse_name_fixed(context, &entry.aliases->val[i],
+ buf, sizeof(buf));
p = rk_strpoolprintf(p, "%s%s", buf,
i + 1 < entry.aliases->len ? ", " : "");
@@ -152,6 +154,137 @@ out:
return ret;
}
+static int
+do_list1_json(struct list_options *opt,
+ const char *keytab_str,
+ heim_array_t a)
+{
+ krb5_error_code ret;
+ krb5_keytab keytab;
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+
+ ret = krb5_kt_resolve(context, keytab_str, &keytab);
+ if (ret) {
+ krb5_warn(context, ret, "resolving keytab %s", keytab_str);
+ return ret;
+ }
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if(ret) {
+ krb5_warn(context, ret, "krb5_kt_start_seq_get %s", keytab_str);
+ krb5_kt_close(context, keytab);
+ return ret;
+ }
+
+ //if (opt->timestamp_flag)
+ //if (opt->keys_flag)
+
+ while (krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) {
+ heim_dict_t d = heim_dict_create(5);
+ heim_object_t o;
+ char *s;
+
+ heim_array_append_value(a, d);
+ heim_dict_set_value(d, HSTR("keytab"),
+ o = heim_string_create(keytab_str)); heim_release(o);
+ heim_dict_set_value(d, HSTR("kvno"), o = heim_number_create(entry.vno));
+ heim_release(o);
+ heim_dict_set_value(d, HSTR("enctype_number"),
+ o = heim_number_create(entry.keyblock.keytype));
+ heim_release(o);
+ heim_dict_set_value(d, HSTR("flags"),
+ o = heim_number_create(entry.flags));
+ heim_release(o);
+ ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &s);
+ if (ret == 0) {
+ heim_dict_set_value(d, HSTR("enctype"), o = heim_string_create(s));
+ heim_release(o);
+ free(s);
+ }
+ heim_dict_set_value(d, HSTR("timestamp"),
+ o = heim_number_create(entry.timestamp));
+ heim_release(o);
+
+ ret = krb5_unparse_name(context, entry.principal, &s);
+ if (ret)
+ krb5_err(context, 1, ret, "Could not format principal");
+ heim_dict_set_value(d, HSTR("principal"), o = heim_string_create(s));
+ heim_release(o);
+ free(s);
+
+ if (opt->keys_flag) {
+ o = heim_data_create(entry.keyblock.keyvalue.data,
+ entry.keyblock.keyvalue.length);
+ heim_dict_set_value(d, HSTR("key"), o);
+ heim_release(o);
+ }
+ if (entry.aliases) {
+ heim_array_t aliases = heim_array_create();
+ unsigned int i;
+
+ for (i = 0; i< entry.aliases->len; i++) {
+ ret = krb5_unparse_name(context, &entry.aliases->val[i], &s);
+ if (ret)
+ krb5_err(context, 1, ret, "Could not format principal");
+ heim_array_append_value(aliases, o = heim_string_create(s));
+ heim_release(o);
+ free(s);
+ }
+ heim_dict_set_value(d, HSTR("aliases"), aliases);
+ heim_release(aliases);
+ free(s);
+ }
+
+ krb5_kt_free_entry(context, &entry);
+ heim_release(d);
+ }
+
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ krb5_kt_close(context, keytab);
+ return ret;
+}
+
+static int
+do_list_json(struct list_options *opt, const char *keytab_str)
+{
+ krb5_error_code ret = 0;
+ heim_json_flags_t flags =
+ (HEIM_JSON_F_STRICT | HEIM_JSON_F_INDENT2 | HEIM_JSON_F_NO_DATA_DICT) &
+ ~HEIM_JSON_F_NO_DATA;
+ heim_array_t a = heim_array_create();
+ heim_string_t s;
+
+ /*
+ * Special-case the ANY: keytab type. What do we get from this? We get to
+ * include the actual keytab name for each entry in its JSON
+ * representation. Otherwise there would be no point because the ANY:
+ * keytab type iterates all the keytabs it joins.
+ *
+ * Why strncasecmp() though? Because do_list() uses it, though it arguably
+ * never should have.
+ */
+ if (strncasecmp(keytab_str, "ANY:", 4) == 0) {
+ char buf[1024];
+
+ keytab_str += 4;
+ ret = 0;
+ while (strsep_copy((const char**)&keytab_str, ",",
+ buf, sizeof(buf)) != -1) {
+ if (do_list1_json(opt, buf, a))
+ ret = 1;
+ }
+ } else {
+ ret = do_list1_json(opt, keytab_str, a);
+ }
+
+ s = heim_json_copy_serialize(a, flags, NULL);
+ printf("%s", heim_string_get_utf8(s));
+ heim_release(a);
+ heim_release(s);
+ return ret;
+}
+
int
kt_list(struct list_options *opt, int argc, char **argv)
{
@@ -168,5 +301,7 @@ kt_list(struct list_options *opt, int argc, char **argv)
}
keytab_string = kt;
}
+ if (opt->json_flag)
+ return do_list_json(opt, keytab_string) != 0;
return do_list(opt, keytab_string) != 0;
}