ktutil: Add list --json option
This commit is contained in:
		@@ -37,6 +37,7 @@ LDADD = \
 | 
				
			|||||||
	$(LIB_hcrypto) \
 | 
						$(LIB_hcrypto) \
 | 
				
			||||||
	$(top_builddir)/lib/asn1/libasn1.la \
 | 
						$(top_builddir)/lib/asn1/libasn1.la \
 | 
				
			||||||
	$(top_builddir)/lib/sl/libsl.la \
 | 
						$(top_builddir)/lib/sl/libsl.la \
 | 
				
			||||||
 | 
						$(LIB_heimbase) \
 | 
				
			||||||
	$(LIB_readline) \
 | 
						$(LIB_readline) \
 | 
				
			||||||
	$(LIB_roken)
 | 
						$(LIB_roken)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -226,6 +226,11 @@ command = {
 | 
				
			|||||||
		type = "flag"
 | 
							type = "flag"
 | 
				
			||||||
		help = "show timestamps"
 | 
							help = "show timestamps"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						option = {
 | 
				
			||||||
 | 
							long = "json"
 | 
				
			||||||
 | 
							type = "flag"
 | 
				
			||||||
 | 
							help = "output JSON representation"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	max_args = "0"
 | 
						max_args = "0"
 | 
				
			||||||
	function = "kt_list"
 | 
						function = "kt_list"
 | 
				
			||||||
	help = "Show contents of keytab."
 | 
						help = "Show contents of keytab."
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,7 +60,7 @@ Verbose output.
 | 
				
			|||||||
.Ar command
 | 
					.Ar command
 | 
				
			||||||
can be one of the following:
 | 
					can be one of the following:
 | 
				
			||||||
.Bl -tag -width srvconvert
 | 
					.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 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 keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
 | 
				
			||||||
Oo Fl Fl enctype= Ns Ar enctype Oc Oo Fl w Ar password 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
 | 
					the keytab, you should consider the
 | 
				
			||||||
.Ar get
 | 
					.Ar get
 | 
				
			||||||
command, which talks to the kadmin server.
 | 
					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 keepold | Fl Fl keepallold | Fl Fl pruneall Oc \
 | 
				
			||||||
Oo Fl Fl enctype= Ns Ar enctype 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 \
 | 
					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.
 | 
					values specified by the options.
 | 
				
			||||||
.Pp
 | 
					.Pp
 | 
				
			||||||
If no principals are given, all the ones in the keytab are updated.
 | 
					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
 | 
					Copies all the entries from
 | 
				
			||||||
.Ar keytab-src
 | 
					.Ar keytab-src
 | 
				
			||||||
to
 | 
					to
 | 
				
			||||||
.Ar keytab-dest .
 | 
					.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 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 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 enctypes= Ns Ar enctype Oc Oo Fl r Ar realm Oc \
 | 
				
			||||||
@@ -103,9 +103,9 @@ If no
 | 
				
			|||||||
.Ar realm
 | 
					.Ar realm
 | 
				
			||||||
is specified, the realm to operate on is taken from the first
 | 
					is specified, the realm to operate on is taken from the first
 | 
				
			||||||
principal.
 | 
					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.
 | 
					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 V kvno Oc Oo Fl Fl kvno= Ns Ar kvno Oc Oo Fl e enctype Oc \
 | 
				
			||||||
Oo Fl Fl enctype= Ns Ar enctype Oc
 | 
					Oo Fl Fl enctype= Ns Ar enctype Oc
 | 
				
			||||||
Removes the specified key or keys. Not specifying a
 | 
					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
 | 
					removes keys with any version number. Not specifying an
 | 
				
			||||||
.Ar enctype
 | 
					.Ar enctype
 | 
				
			||||||
removes keys of any type.
 | 
					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
 | 
					Renames all entries in the keytab that match the
 | 
				
			||||||
.Ar from-principal
 | 
					.Ar from-principal
 | 
				
			||||||
to
 | 
					to
 | 
				
			||||||
.Ar to-principal .
 | 
					.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
 | 
					Removes all old versions of a key for which there is a newer version
 | 
				
			||||||
that is at least
 | 
					that is at least
 | 
				
			||||||
.Ar age
 | 
					.Ar age
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										139
									
								
								admin/list.c
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								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).
 | 
					 * (Royal Institute of Technology, Stockholm, Sweden).
 | 
				
			||||||
 * All rights reserved.
 | 
					 * All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -32,6 +32,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ktutil_locl.h"
 | 
					#include "ktutil_locl.h"
 | 
				
			||||||
 | 
					#include <heimbase.h>
 | 
				
			||||||
#include <rtbl.h>
 | 
					#include <rtbl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RCSID("$Id$");
 | 
					RCSID("$Id$");
 | 
				
			||||||
@@ -131,7 +132,8 @@ do_list(struct list_options *opt, const char *keytab_str)
 | 
				
			|||||||
	    struct rk_strpool *p = NULL;
 | 
						    struct rk_strpool *p = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	    for (i = 0; i< entry.aliases->len; i++) {
 | 
						    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,
 | 
							p = rk_strpoolprintf(p, "%s%s", buf,
 | 
				
			||||||
                                     i + 1 < entry.aliases->len ? ", " : "");
 | 
					                                     i + 1 < entry.aliases->len ? ", " : "");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -152,6 +154,137 @@ out:
 | 
				
			|||||||
    return ret;
 | 
					    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
 | 
					int
 | 
				
			||||||
kt_list(struct list_options *opt, int argc, char **argv)
 | 
					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;
 | 
						keytab_string = kt;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (opt->json_flag)
 | 
				
			||||||
 | 
					        return do_list_json(opt, keytab_string) != 0;
 | 
				
			||||||
    return do_list(opt, keytab_string) != 0;
 | 
					    return do_list(opt, keytab_string) != 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user