implement output column selection, similar to ps -o

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@14002 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Johan Danielsson
2004-06-27 15:13:36 +00:00
parent fd5ddd5f3c
commit 74c605506c

View File

@@ -34,78 +34,67 @@
#include "kadmin_locl.h"
#include "kadmin-commands.h"
#include <parse_units.h>
#include <rtbl.h>
RCSID("$Id$");
struct get_entry_data {
void (*header)(void);
void (*format)(kadm5_principal_ent_t);
static struct field_name {
const char *fieldname;
unsigned int fieldvalue;
const char *default_header;
const char *def_longheader;
unsigned int flags;
} field_names[] = {
{ "principal", KADM5_PRINCIPAL, "Principal", "Principal", 0 },
{ "princ_expire_time", KADM5_PRINC_EXPIRE_TIME, "Expiration", "Principal expires", 0 },
{ "pw_expiration", KADM5_PW_EXPIRATION, "PW-exp", "Password expires", 0 },
{ "last_pwd_change", KADM5_LAST_PWD_CHANGE, "PW-change", "Last password change", 0 },
{ "max_life", KADM5_MAX_LIFE, "Max life", "Max ticket life", 0 },
{ "max_rlife", KADM5_MAX_RLIFE, "Max renew", "Max renewable life", 0 },
{ "mod_time", KADM5_MOD_TIME, "Mod time", "Last modified", 0 },
{ "mod_name", KADM5_MOD_NAME, "Modifier", "Modifier", 0 },
{ "attributes", KADM5_ATTRIBUTES, "Attributes", "Attributes", 0 },
{ "kvno", KADM5_KVNO, "Kvno", "Kvno", RTBL_ALIGN_RIGHT },
{ "mkvno", KADM5_MKVNO, "Mkvno", "Mkvno", RTBL_ALIGN_RIGHT },
{ "last_success", KADM5_LAST_SUCCESS, "Last login", "Last successful login", 0 },
{ "last_failed", KADM5_LAST_FAILED, "Last fail", "Last failed login", 0 },
{ "fail_auth_count", KADM5_FAIL_AUTH_COUNT, "Fail count", "Failed login count", RTBL_ALIGN_RIGHT },
{ "policy", KADM5_POLICY, "Policy", "Policy", 0 },
{ "keytypes", KADM5_KEY_DATA, "Keytypes", "Keytypes(salttype[(salt-value)])", 0 },
{ NULL }
};
static void
print_entry_terse(kadm5_principal_ent_t princ)
struct field_info {
struct field_name *ff;
char *header;
struct field_info *next;
};
struct get_entry_data {
void (*format)(struct get_entry_data*, kadm5_principal_ent_t);
rtbl_t table;
u_int32_t mask;
struct field_info *chead, **ctail;
};
static int
add_column(struct get_entry_data *data, struct field_name *ff, const char *header)
{
krb5_error_code ret;
char *p;
ret = krb5_unparse_name(context, princ->principal, &p);
if (ret)
p = "<error unparsing name>";
printf(" %s\n", p);
if (ret == 0)
free(p);
}
static void
print_header_short(void)
{
printf("%-20s ", "Principal");
printf("%-10s ", "Expires");
printf("%-10s ", "PW-exp");
printf("%-10s ", "PW-change");
printf("%-9s ", "Max life");
printf("%-9s ", "Max renew");
printf("\n");
}
static void
print_entry_short(kadm5_principal_ent_t princ)
{
char buf[1024];
krb5_unparse_name_fixed_short(context, princ->principal, buf, sizeof(buf));
printf("%-20s ", buf);
time_t2str(princ->princ_expire_time, buf, sizeof(buf), 0);
printf("%-10s ", buf);
time_t2str(princ->pw_expiration, buf, sizeof(buf), 0);
printf("%-10s ", buf);
time_t2str(princ->last_pwd_change, buf, sizeof(buf), 0);
printf("%-10s ", buf);
deltat2str(princ->max_life, buf, sizeof(buf));
printf("%-9s ", buf);
deltat2str(princ->max_renewable_life, buf, sizeof(buf));
printf("%-9s ", buf);
#if 0
time_t2str(princ->mod_date, buf, sizeof(buf), 0);
printf("%-10s ", buf);
krb5_unparse_name_fixed(context, princ->mod_name, buf, sizeof(buf));
printf("%-24s", buf);
#endif
printf("\n");
struct field_info *f = malloc(sizeof(*f));
f->ff = ff;
if(header)
f->header = strdup(header);
else
f->header = NULL;
f->next = NULL;
*data->ctail = f;
data->ctail = &f->next;
data->mask |= ff->fieldvalue;
if(data->table != NULL)
rtbl_add_column_by_id(data->table, ff->fieldvalue,
header ? header : ff->default_header, ff->flags);
return 0;
}
/*
@@ -124,83 +113,160 @@ cmp_salt (const krb5_salt *salt, const krb5_key_data *k)
}
static void
print_entry_long(kadm5_principal_ent_t princ)
format_keytype(krb5_key_data *k, krb5_salt *def_salt, char *buf, size_t buf_len)
{
krb5_error_code ret;
char *s;
ret = krb5_enctype_to_string (context,
k->key_data_type[0],
&s);
if (ret)
asprintf (&s, "unknown(%d)", k->key_data_type[0]);
strlcpy(buf, s, buf_len);
free(s);
strlcat(buf, "(", buf_len);
ret = krb5_salttype_to_string (context,
k->key_data_type[0],
k->key_data_type[1],
&s);
if (ret)
asprintf (&s, "unknown(%d)", k->key_data_type[1]);
strlcat(buf, s, buf_len);
free(s);
if (cmp_salt(def_salt, k) == 0)
s = strdup("");
else if(k->key_data_length[1] == 0)
s = strdup("()");
else
asprintf (&s, "(%.*s)", k->key_data_length[1],
(char *)k->key_data_contents[1]);
strlcat(buf, s, buf_len);
free(s);
strlcat(buf, ")", buf_len);
}
static void
format_field(kadm5_principal_ent_t princ, unsigned int field,
char *buf, size_t buf_len, int condensed)
{
switch(field) {
case KADM5_PRINCIPAL:
if(condensed)
krb5_unparse_name_fixed_short(context, princ->principal, buf, buf_len);
else
krb5_unparse_name_fixed(context, princ->principal, buf, buf_len);
break;
case KADM5_PRINC_EXPIRE_TIME:
time_t2str(princ->princ_expire_time, buf, buf_len, !condensed);
break;
case KADM5_PW_EXPIRATION:
time_t2str(princ->pw_expiration, buf, buf_len, !condensed);
break;
case KADM5_LAST_PWD_CHANGE:
time_t2str(princ->last_pwd_change, buf, buf_len, !condensed);
break;
case KADM5_MAX_LIFE:
deltat2str(princ->max_life, buf, buf_len);
break;
case KADM5_MAX_RLIFE:
deltat2str(princ->max_renewable_life, buf, buf_len);
break;
case KADM5_MOD_TIME:
time_t2str(princ->mod_date, buf, buf_len, !condensed);
break;
case KADM5_MOD_NAME:
if(condensed)
krb5_unparse_name_fixed_short(context, princ->mod_name, buf, buf_len);
else
krb5_unparse_name_fixed(context, princ->mod_name, buf, buf_len);
break;
case KADM5_ATTRIBUTES:
attributes2str (princ->attributes, buf, buf_len);
break;
case KADM5_KVNO:
snprintf(buf, buf_len, "%d", princ->kvno);
break;
case KADM5_MKVNO:
snprintf(buf, buf_len, "%d", princ->mkvno);
break;
case KADM5_LAST_SUCCESS:
time_t2str(princ->last_success, buf, buf_len, !condensed);
break;
case KADM5_LAST_FAILED:
time_t2str(princ->last_failed, buf, buf_len, !condensed);
break;
case KADM5_FAIL_AUTH_COUNT:
snprintf(buf, buf_len, "%d", princ->fail_auth_count);
break;
case KADM5_POLICY:
if(princ->policy != NULL)
strlcpy(buf, princ->policy, buf_len);
else
strlcpy(buf, "none", buf_len);
break;
case KADM5_KEY_DATA:{
krb5_salt def_salt;
int i;
char buf2[1024];
krb5_get_pw_salt (context, princ->principal, &def_salt);
*buf = '\0';
for (i = 0; i < princ->n_key_data; ++i) {
format_keytype(&princ->key_data[i], &def_salt, buf2, sizeof(buf2));
if(i > 0)
strlcat(buf, ", ", buf_len);
strlcat(buf, buf2, buf_len);
}
krb5_free_salt (context, def_salt);
break;
}
default:
strlcpy(buf, "<unknown>", buf_len);
break;
}
}
static void
print_entry_short(struct get_entry_data *data, kadm5_principal_ent_t princ)
{
char buf[1024];
int i;
krb5_salt def_salt;
struct field_info *f;
krb5_unparse_name_fixed(context, princ->principal, buf, sizeof(buf));
printf("%24s: %s\n", "Principal", buf);
time_t2str(princ->princ_expire_time, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Principal expires", buf);
time_t2str(princ->pw_expiration, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Password expires", buf);
time_t2str(princ->last_pwd_change, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Last password change", buf);
deltat2str(princ->max_life, buf, sizeof(buf));
printf("%24s: %s\n", "Max ticket life", buf);
deltat2str(princ->max_renewable_life, buf, sizeof(buf));
printf("%24s: %s\n", "Max renewable life", buf);
printf("%24s: %d\n", "Kvno", princ->kvno);
printf("%24s: %d\n", "Mkvno", princ->mkvno);
printf("%24s: %s\n", "Policy", princ->policy ? princ->policy : "none");
time_t2str(princ->last_success, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Last successful login", buf);
time_t2str(princ->last_failed, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Last failed login", buf);
printf("%24s: %d\n", "Failed login count", princ->fail_auth_count);
time_t2str(princ->mod_date, buf, sizeof(buf), 1);
printf("%24s: %s\n", "Last modified", buf);
if(princ->mod_name != NULL) {
krb5_unparse_name_fixed(context, princ->mod_name, buf, sizeof(buf));
printf("%24s: %s\n", "Modifier", buf);
for(f = data->chead; f != NULL; f = f->next) {
format_field(princ, f->ff->fieldvalue, buf, sizeof(buf), 1);
rtbl_add_column_entry_by_id(data->table, f->ff->fieldvalue, buf);
}
attributes2str (princ->attributes, buf, sizeof(buf));
printf("%24s: %s\n", "Attributes", buf);
}
printf("%24s: ", "Keytypes(salttype[(salt-value)])");
krb5_get_pw_salt (context, princ->principal, &def_salt);
for (i = 0; i < princ->n_key_data; ++i) {
krb5_key_data *k = &princ->key_data[i];
krb5_error_code ret;
char *e_string, *s_string, *salt;
ret = krb5_enctype_to_string (context,
k->key_data_type[0],
&e_string);
if (ret)
asprintf (&e_string, "unknown(%d)", k->key_data_type[0]);
ret = krb5_salttype_to_string (context,
k->key_data_type[0],
k->key_data_type[1],
&s_string);
if (ret)
asprintf (&s_string, "unknown(%d)", k->key_data_type[1]);
if (cmp_salt(&def_salt, k) == 0)
salt = strdup("");
else if(k->key_data_length[1] == 0)
salt = strdup("()");
else
asprintf (&salt, "(%.*s)", k->key_data_length[1],
(char *)k->key_data_contents[1]);
printf ("%s%s(%s%s)", (i != 0) ? ", " : "", e_string, s_string, salt);
free (e_string);
free (s_string);
free (salt);
static void
print_entry_long(struct get_entry_data *data, kadm5_principal_ent_t princ)
{
char buf[1024];
struct field_info *f;
int width = 0;
for(f = data->chead; f != NULL; f = f->next) {
int w = strlen(f->header ? f->header : f->ff->def_longheader);
if(w > width)
width = w;
}
krb5_free_salt (context, def_salt);
printf("\n\n");
for(f = data->chead; f != NULL; f = f->next) {
format_field(princ, f->ff->fieldvalue, buf, sizeof(buf), 0);
printf("%*s: %s\n", width, f->header ? f->header : f->ff->def_longheader, buf);
}
printf("\n");
}
static int
@@ -213,23 +279,61 @@ do_get_entry(krb5_principal principal, void *data)
memset(&princ, 0, sizeof(princ));
ret = kadm5_get_principal(kadm_handle, principal,
&princ,
KADM5_PRINCIPAL_NORMAL_MASK|KADM5_KEY_DATA);
e->mask);
if(ret)
return ret;
else {
if(e->header) {
(*e->header)();
e->header = NULL; /* XXX only once */
}
(e->format)(&princ);
(e->format)(e, &princ);
kadm5_free_principal_ent(kadm_handle, &princ);
}
return 0;
}
static void
free_columns(struct get_entry_data *data)
{
struct field_info *f, *next;
for(f = data->chead; f != NULL; f = next) {
free(f->header);
next = f->next;
free(f);
}
data->chead = NULL;
data->ctail = &data->chead;
}
static int
getit(struct get_options *opt, const char *name,
int terse_flag, int argc, char **argv)
setup_columns(struct get_entry_data *data, const char *column_info)
{
char buf[1024], *q;
char *field, *header;
struct field_name *f;
while(strsep_copy(&column_info, ",", buf, sizeof(buf)) != -1) {
q = buf;
field = strsep(&q, "=");
header = strsep(&q, "=");
for(f = field_names; f->fieldname != NULL; f++) {
if(strcasecmp(field, f->fieldname) == 0) {
add_column(data, f, header);
break;
}
}
if(f->fieldname == NULL) {
krb5_warnx(context, "unknown field name \"%s\"", field);
free_columns(data);
return -1;
}
}
return 0;
}
#define DEFAULT_COLUMNS_SHORT "principal,princ_expire_time,pw_expiration,last_pwd_change,max_life,max_rlife"
#define DEFAULT_COLUMNS_LONG "principal,princ_expire_time,pw_expiration,last_pwd_change,max_life,max_rlife,kvno,mkvno,last_success,last_failed,fail_auth_count,mod_time,mod_name,attributes"
#define DEFAULT_COLUMNS_TERSE "principal="
static int
getit(struct get_options *opt, const char *name, int argc, char **argv)
{
int i;
krb5_error_code ret;
@@ -249,30 +353,57 @@ getit(struct get_options *opt, const char *name,
if(opt->long_flag == 0 && opt->short_flag == 0 && opt->terse_flag == 0)
opt->short_flag = 1;
if(opt->long_flag) {
data.format = print_entry_long;
data.header = NULL;
} else if(opt->short_flag){
data.format = print_entry_short;
data.header = print_header_short;
} else if(opt->terse_flag) {
data.format = print_entry_terse;
data.header = NULL;
}
data.table = NULL;
data.chead = NULL;
data.ctail = &data.chead;
if(opt->short_flag || opt->terse_flag) {
data.table = rtbl_create();
rtbl_set_separator(data.table, " ");
data.format = print_entry_short;
} else
data.format = print_entry_long;
if(opt->column_info_string == NULL) {
if(opt->long_flag)
ret = setup_columns(&data, DEFAULT_COLUMNS_LONG);
else if(opt->short_flag)
ret = setup_columns(&data, DEFAULT_COLUMNS_SHORT);
else {
ret = setup_columns(&data, DEFAULT_COLUMNS_TERSE);
rtbl_set_flags(data.table, RTBL_HEADER_STYLE_NONE);
}
} else
ret = setup_columns(&data, opt->column_info_string);
if(ret != 0) {
if(data.table != NULL)
rtbl_destroy(data.table);
return 0;
}
for(i = 0; i < argc; i++)
ret = foreach_principal(argv[i], do_get_entry, "get", &data);
if(data.table != NULL) {
rtbl_format(data.table, stdout);
rtbl_destroy(data.table);
free_columns(&data);
}
return 0;
}
int
get_entry(struct get_options *opt, int argc, char **argv)
{
return getit(opt, "get", 0, argc, argv);
return getit(opt, "get", argc, argv);
}
int
list_princs(struct list_options *opt, int argc, char **argv)
{
return getit((struct get_options*)opt, "list", 1, argc, argv);
if(sizeof(struct get_options) != sizeof(struct list_options)) {
krb5_warnx(context, "programmer error: sizeof(struct get_options) != sizeof(struct list_options)");
return 0;
}
return getit((struct get_options*)opt, "list", argc, argv);
}