ktutil: Add list --json option

This commit is contained in:
Nicolas Williams
2022-10-01 11:53:23 -05:00
parent 6297b76362
commit 69dc89b39a
4 changed files with 151 additions and 10 deletions

View File

@@ -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)

View File

@@ -226,6 +226,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."

View File

@@ -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,12 +82,12 @@ 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 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 \
.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 keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
Oo Fl Fl enctypes= Ns Ar enctype Oc Oo Fl r Ar realm Oc \
@@ -103,9 +103,9 @@ 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 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 \
.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,12 +113,12 @@ 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
.It Nm rename Ar from-principal Ar to-principal
Renames all entries in the keytab that match the
.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

View File

@@ -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;
}