diff --git a/kadmin/check.c b/kadmin/check.c index ad14ed224..a8782ca43 100644 --- a/kadmin/check.c +++ b/kadmin/check.c @@ -73,7 +73,7 @@ do_check_entry(krb5_principal principal, void *data) return 1; memset (&princ, 0, sizeof(princ)); - ret = kadm5_get_principal(kadm_handle, principal, &princ, + ret = kadm5_get_principal(data, principal, &princ, KADM5_PRINCIPAL | KADM5_KEY_DATA); if(ret) { krb5_warn(context, ret, "Failed to get principal: %s", name); @@ -95,7 +95,7 @@ do_check_entry(krb5_principal principal, void *data) } free(name); - kadm5_free_principal_ent(kadm_handle, &princ); + kadm5_free_principal_ent(data, &princ); return 0; } @@ -106,6 +106,7 @@ check(void *opt, int argc, char **argv) kadm5_principal_ent_rec ent; krb5_error_code ret; char *realm = NULL, *p, *p2; + void *inner_kadm_handle = NULL; int found; if (argc == 0) { @@ -254,7 +255,15 @@ check(void *opt, int argc, char **argv) } } - foreach_principal("*", do_check_entry, "check", NULL); + ret = kadm5_dup_context(kadm_handle, &inner_kadm_handle); + if (ret == 0) + ret = foreach_principal("*", do_check_entry, "check", inner_kadm_handle); + if (inner_kadm_handle) + kadm5_destroy(inner_kadm_handle); + if (ret) { + krb5_warn(context, ret, "Could not iterate principals in realm"); + goto fail; + } free(realm); return 0; diff --git a/kadmin/get.c b/kadmin/get.c index a884e11e9..38c1b7494 100644 --- a/kadmin/get.c +++ b/kadmin/get.c @@ -84,6 +84,7 @@ struct get_entry_data { struct field_info *chead, **ctail; const char *krb5_config_fname; uint32_t n; + int upto; }; static int @@ -478,6 +479,11 @@ do_get_entry(krb5_principal principal, void *data) krb5_error_code ret; struct get_entry_data *e = data; + if (e->upto == 0) + return EINTR; + if (e->upto > 0) + e->upto--; + memset(&princ, 0, sizeof(princ)); ret = kadm5_get_principal(kadm_handle, principal, &princ, @@ -534,8 +540,14 @@ static int do_list_entry(krb5_principal principal, void *data) { char buf[1024]; + int *upto = data; krb5_error_code ret; + if (*upto == 0) + return EINTR; + if (*upto > 0) + (*upto)--; + ret = krb5_unparse_name_fixed_short(context, principal, buf, sizeof(buf)); if (ret != 0) return ret; @@ -544,13 +556,13 @@ do_list_entry(krb5_principal principal, void *data) } static int -listit(const char *funcname, int argc, char **argv) +listit(const char *funcname, int upto, int argc, char **argv) { int i; krb5_error_code ret, saved_ret = 0; for (i = 0; i < argc; i++) { - ret = foreach_principal(argv[i], do_list_entry, funcname, NULL); + ret = foreach_principal(argv[i], do_list_entry, funcname, &upto); if (saved_ret == 0 && ret != 0) saved_ret = ret; } @@ -577,7 +589,7 @@ getit(struct get_options *opt, const char *name, int argc, char **argv) opt->short_flag = 1; if (opt->terse_flag) - return listit(name, argc, argv); + return listit(name, opt->upto_integer, argc, argv); data.table = NULL; data.chead = NULL; @@ -585,6 +597,7 @@ getit(struct get_options *opt, const char *name, int argc, char **argv) data.mask = 0; data.extra_mask = 0; data.krb5_config_fname = opt->krb5_config_file_string; + data.upto = opt->upto_integer; data.n = 0; if(opt->short_flag) { @@ -638,5 +651,6 @@ list_princs(struct list_options *opt, int argc, char **argv) get_opt.short_flag = opt->short_flag; get_opt.terse_flag = opt->terse_flag; get_opt.column_info_string = opt->column_info_string; + get_opt.upto_integer = opt->upto_integer; return getit(&get_opt, "list", argc, argv); } diff --git a/kadmin/kadmin-commands.in b/kadmin/kadmin-commands.in index e8a1e8a08..db9c4415e 100644 --- a/kadmin/kadmin-commands.in +++ b/kadmin/kadmin-commands.in @@ -500,6 +500,12 @@ command = { type = "string" help = "filename to save the principal's krb5.confg in" } + option = { + long = "upto" + type = "integer" + default = "-1" + help = "maximum number of principals to get/list" + } argument = "principal..." min_args = "1" help = "Shows information about principals matching the expressions." @@ -674,6 +680,13 @@ command = { option = { long = "krb5-config-file" type = "string" + help = "only use this option with the get command" + } + option = { + long = "upto" + type = "integer" + default = "-1" + help = "maximum number of principals to get/list" } argument = "principal..." min_args = "1" diff --git a/kadmin/util.c b/kadmin/util.c index 9d79eb4eb..a1ef89565 100644 --- a/kadmin/util.c +++ b/kadmin/util.c @@ -605,6 +605,34 @@ is_expression(const char *string) return 0; } +struct foreach_principal_data { + krb5_error_code ret; + const char *funcname; + int (*func)(krb5_principal, void *); + void *data; +}; + +static int +foreach_principal_cb(void *data, const char *p) +{ + struct foreach_principal_data *d = data; + krb5_principal princ; + krb5_error_code ret; + + ret = krb5_parse_name(context, p, &princ); + if (ret) + return ret; + + d->ret = d->func(princ, d->data); + krb5_free_principal(context, princ); + if (d->ret) { + krb5_warn(context, d->ret, "%s %s", d->funcname, p); + krb5_clear_error_message(context); + ret = d->ret ? d->ret : ret; + } + return ret; +} + /* * Loop over all principals matching exp. If any of calls to `func' * failes, the first error is returned when all principals are @@ -616,52 +644,67 @@ foreach_principal(const char *exp_str, const char *funcname, void *data) { - char **princs = NULL; - int num_princs = 0; - int i; - krb5_error_code saved_ret = 0, ret = 0; - krb5_principal princ_ent; + struct foreach_principal_data d; + krb5_error_code ret; + krb5_principal p; int is_expr; + int go_slow = + secure_getenv("KADMIN_USE_GET_PRINCIPALS") != NULL && + *secure_getenv("KADMIN_USE_GET_PRINCIPALS") != '\0'; /* if this isn't an expression, there is no point in wading through the whole database looking for matches */ is_expr = is_expression(exp_str); - if(is_expr) - ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &num_princs); - if(!is_expr || ret == KADM5_AUTH_LIST) { - /* we might be able to perform the requested opreration even - if we're not allowed to list principals */ - num_princs = 1; - princs = malloc(sizeof(*princs)); - if(princs == NULL) - return ENOMEM; - princs[0] = strdup(exp_str); - if(princs[0] == NULL){ - free(princs); - return ENOMEM; - } - } else if(ret) { - krb5_warn(context, ret, "kadm5_get_principals"); - return ret; + + d.funcname = funcname; + d.func = func; + d.data = data; + d.ret = 0; + + if (is_expr && !go_slow) { + ret = kadm5_iter_principals(kadm_handle, exp_str, + foreach_principal_cb, &d); + if (ret == 0) + return 0; + if (ret != KADM5_AUTH_LIST) { + krb5_warn(context, ret, "kadm5_iter_principals"); + return d.ret; + } + } else if (is_expr) { + char **princs = NULL; + int count = 0; + + /* + * This is just for testing, and maybe in case there are HDB backends + * that are not re-entrant (LDAP?). + */ + ret = kadm5_get_principals(kadm_handle, exp_str, &princs, &count); + if (ret == 0 && count > 0) { + int i; + + for (i = 0; ret == 0 && i < count; i++) + ret = foreach_principal_cb(&d, princs[i]); + kadm5_free_name_list(kadm_handle, princs, &count); + return ret; + } + if (ret != KADM5_AUTH_LIST) { + krb5_warn(context, ret, "kadm5_iter_principals"); + return d.ret; + } } - for(i = 0; i < num_princs; i++) { - ret = krb5_parse_name(context, princs[i], &princ_ent); - if(ret){ - krb5_warn(context, ret, "krb5_parse_name(%s)", princs[i]); - continue; - } - ret = (*func)(princ_ent, data); - if(ret) { - krb5_warn(context, ret, "%s %s", funcname, princs[i]); - krb5_clear_error_message(context); - if (saved_ret == 0) - saved_ret = ret; - } - krb5_free_principal(context, princ_ent); + /* we might be able to perform the requested opreration even + if we're not allowed to list principals */ + ret = krb5_parse_name(context, exp_str, &p); + if (ret) { + krb5_warn(context, ret, "krb5_parse_name(%s)", exp_str); + return ret; } - if (ret == 0 && saved_ret != 0) - ret = saved_ret; - kadm5_free_name_list(kadm_handle, princs, &num_princs); + ret = (*func)(p, data); + if (ret) { + krb5_warn(context, ret, "%s %s", funcname, exp_str); + krb5_clear_error_message(context); + } + krb5_free_principal(context, p); return ret; }