hdb: Move virtual principals into HDB layer
This is a large commit that adds several features: - Revamps and moves virtual host-based service principal functionality from kdc/ to lib/hdb/ so that it may be automatically visible to lib/kadm5/, as well as kadmin(1)/kadmind(8) and ktutil(1). The changes are backwards-incompatible. - Completes support for documenting a service principal's supported enctypes in its HDB entry independently of its long-term keys. This will reduce HDB bloat by not requiring that service principals have more long-term keys than they need just to document the service's supported enctypes. - Adds support for storing krb5.conf content in principals' HDB entries. This may eventually be used for causing Heimdal KDC services to reconfigure primary/secondary roles automatically by discovering the configured primary in an HDB entry for the realm. For now this will be used to help reduce the amount of configuration needed by clients of an upcoming HTTP binding of the kadmin service.
This commit is contained in:
209
kadmin/ank.c
209
kadmin/ank.c
@@ -34,6 +34,9 @@
|
||||
#include "kadmin_locl.h"
|
||||
#include "kadmin-commands.h"
|
||||
|
||||
/* No useful password policies for namespaces */
|
||||
#define NSPOLICY "default"
|
||||
|
||||
/*
|
||||
* fetch the default principal corresponding to `princ'
|
||||
*/
|
||||
@@ -308,3 +311,209 @@ add_new_key(struct add_options *opt, int argc, char **argv)
|
||||
free(kstuple);
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
kstuple2etypes(kadm5_principal_ent_rec *rec,
|
||||
int *maskp,
|
||||
size_t nkstuple,
|
||||
krb5_key_salt_tuple *kstuple)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
HDB_EncTypeList etypes;
|
||||
krb5_data buf;
|
||||
size_t len, i;
|
||||
|
||||
etypes.len = 0;
|
||||
if ((etypes.val = calloc(nkstuple, sizeof(etypes.val[0]))) == NULL)
|
||||
return krb5_enomem(context);
|
||||
for (i = 0; i < nkstuple; i++)
|
||||
etypes.val[i] = kstuple[i].ks_enctype;
|
||||
ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length,
|
||||
&etypes, &len, ret);
|
||||
if (ret == 0)
|
||||
add_tl(rec, KRB5_TL_ETYPES, &buf);
|
||||
free(etypes.val);
|
||||
if (ret == 0)
|
||||
(*maskp) |= KADM5_TL_DATA;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the namespace `name' to the database.
|
||||
* Prompt for all data not given by the input parameters.
|
||||
*/
|
||||
static krb5_error_code
|
||||
add_one_namespace(const char *name,
|
||||
size_t nkstuple,
|
||||
krb5_key_salt_tuple *kstuple,
|
||||
const char *max_ticket_life,
|
||||
const char *max_renewable_life,
|
||||
const char *key_rotation_epoch,
|
||||
const char *key_rotation_period,
|
||||
const char *attributes)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
kadm5_principal_ent_rec princ;
|
||||
kadm5_principal_ent_rec *default_ent = NULL;
|
||||
krb5_principal princ_ent = NULL;
|
||||
int mask = 0;
|
||||
int default_mask = 0;
|
||||
HDB_extension ext;
|
||||
krb5_data buf;
|
||||
const char *comp0;
|
||||
const char *comp1;
|
||||
time_t kre;
|
||||
char pwbuf[1024];
|
||||
krb5_deltat krp;
|
||||
|
||||
if (!key_rotation_epoch) {
|
||||
krb5_warnx(context, "key rotation epoch defaulted to \"now\"");
|
||||
key_rotation_epoch = "now";
|
||||
}
|
||||
if (!key_rotation_period) {
|
||||
krb5_warnx(context, "key rotation period defaulted to \"5d\"");
|
||||
key_rotation_period = "5d";
|
||||
}
|
||||
if ((ret = str2time_t(key_rotation_epoch, &kre)) != 0) {
|
||||
krb5_warn(context, ret, "invalid rotation epoch: %s",
|
||||
key_rotation_epoch);
|
||||
return ret;
|
||||
}
|
||||
if (ret == 0 && (ret = str2deltat(key_rotation_period, &krp)) != 0) {
|
||||
krb5_warn(context, ret, "invalid rotation period: %s",
|
||||
key_rotation_period);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
memset(&princ, 0, sizeof(princ));
|
||||
princ.kvno = 1;
|
||||
ret = krb5_parse_name(context, name, &princ_ent);
|
||||
if (ret)
|
||||
krb5_warn(context, ret, "krb5_parse_name");
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check that namespace has exactly one component, and prepend
|
||||
* WELLKNOWN/HOSTBASED-NAMESPACE
|
||||
*/
|
||||
if (krb5_principal_get_num_comp(context, princ_ent) != 2
|
||||
|| (comp0 = krb5_principal_get_comp_string(context, princ_ent, 0)) == 0
|
||||
|| (comp1 = krb5_principal_get_comp_string(context, princ_ent, 1)) == 0
|
||||
|| *comp0 == 0 || *comp1 == 0
|
||||
|| strcmp(comp0, "krbtgt") == 0)
|
||||
krb5_warn(context, ret = EINVAL,
|
||||
"namespaces must have exactly two non-empty components "
|
||||
"like host-base principal names");
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, princ_ent, 2, comp0);
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, princ_ent, 3, comp1);
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, princ_ent, 0,
|
||||
"WELLKNOWN");
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, princ_ent, 1,
|
||||
HDB_WK_NAMESPACE);
|
||||
|
||||
/* Set up initial key rotation extension */
|
||||
if (ret == 0) {
|
||||
KeyRotation kr;
|
||||
size_t size;
|
||||
|
||||
/* Setup key rotation metadata in a convenient way */
|
||||
kr.flags = int2KeyRotationFlags(0);
|
||||
kr.base_key_kvno = 1;
|
||||
/*
|
||||
* Avoid kvnos 0/1/2 which don't normally appear in fully created
|
||||
* principals.
|
||||
*/
|
||||
kr.base_kvno = 3;
|
||||
|
||||
/* XXX: Sanity check */
|
||||
kr.epoch = kre;
|
||||
kr.period = krp;
|
||||
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
ext.mandatory = FALSE;
|
||||
ext.data.element = choice_HDB_extension_data_key_rotation;
|
||||
ext.data.u.key_rotation.len = 1;
|
||||
ext.data.u.key_rotation.val = &kr;
|
||||
|
||||
ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
|
||||
&ext, &size, ret);
|
||||
add_tl(&princ, KRB5_TL_EXTENSION, &buf);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
princ.principal = princ_ent;
|
||||
mask |= KADM5_PRINCIPAL | KADM5_KVNO;
|
||||
|
||||
ret = set_entry(context, &princ, &mask,
|
||||
max_ticket_life, max_renewable_life,
|
||||
"never", "never", attributes, NSPOLICY);
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = edit_entry(&princ, &mask, default_ent, default_mask);
|
||||
|
||||
if (ret == 0)
|
||||
ret = kstuple2etypes(&princ, &mask, nkstuple, kstuple);
|
||||
|
||||
/* XXX Shouldn't need a password for this */
|
||||
random_password(pwbuf, sizeof(pwbuf));
|
||||
ret = kadm5_create_principal_3(kadm_handle, &princ, mask,
|
||||
nkstuple, kstuple, pwbuf);
|
||||
if (ret)
|
||||
krb5_warn(context, ret, "kadm5_create_principal_3");
|
||||
|
||||
kadm5_free_principal_ent(kadm_handle, &princ); /* frees princ_ent */
|
||||
if (default_ent)
|
||||
kadm5_free_principal_ent(kadm_handle, default_ent);
|
||||
memset(pwbuf, 0, sizeof(pwbuf));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
add_new_namespace(struct add_namespace_options *opt, int argc, char **argv)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
krb5_key_salt_tuple *kstuple = NULL;
|
||||
const char *enctypes;
|
||||
size_t i, nkstuple;
|
||||
|
||||
if (argc < 1) {
|
||||
fprintf(stderr, "at least one namespace name required\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
enctypes = opt->enctypes_string;
|
||||
if (enctypes == NULL || enctypes[0] == '\0')
|
||||
enctypes = krb5_config_get_string(context, NULL, "libdefaults",
|
||||
"supported_enctypes", NULL);
|
||||
if (enctypes == NULL || enctypes[0] == '\0')
|
||||
enctypes = "aes128-cts-hmac-sha1-96";
|
||||
ret = krb5_string_to_keysalts2(context, enctypes, &nkstuple, &kstuple);
|
||||
if (ret) {
|
||||
fprintf(stderr, "enctype(s) unknown\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
ret = add_one_namespace(argv[i], nkstuple, kstuple,
|
||||
opt->max_ticket_life_string,
|
||||
opt->max_renewable_life_string,
|
||||
opt->key_rotation_epoch_string,
|
||||
opt->key_rotation_period_string,
|
||||
opt->attributes_string);
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "adding namespace %s", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(kstuple);
|
||||
return ret != 0;
|
||||
}
|
||||
|
44
kadmin/del.c
44
kadmin/del.c
@@ -53,3 +53,47 @@ del_entry(void *opt, int argc, char **argv)
|
||||
}
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_del_ns_entry(krb5_principal nsp, void *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_principal p = NULL;
|
||||
const char *comp0 = krb5_principal_get_comp_string(context, nsp, 0);
|
||||
const char *comp1 = krb5_principal_get_comp_string(context, nsp, 1);
|
||||
char *unsp = NULL;
|
||||
|
||||
if (krb5_principal_get_num_comp(context, nsp) != 2) {
|
||||
(void) krb5_unparse_name(context, nsp, &unsp);
|
||||
krb5_warn(context, ret = EINVAL, "Not a valid namespace name %s",
|
||||
unsp ? unsp : "<Out of memory>");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ret = krb5_make_principal(context, &p,
|
||||
krb5_principal_get_realm(context, nsp),
|
||||
"WELLKNOWN", HDB_WK_NAMESPACE, NULL);
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, p, 2, comp0);
|
||||
if (ret == 0)
|
||||
ret = krb5_principal_set_comp_string(context, p, 3, comp1);
|
||||
if (ret == 0)
|
||||
ret = kadm5_delete_principal(kadm_handle, p);
|
||||
krb5_free_principal(context, p);
|
||||
free(unsp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
del_namespace(void *opt, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
krb5_error_code ret = 0;
|
||||
|
||||
for(i = 0; i < argc; i++) {
|
||||
ret = foreach_principal(argv[i], do_del_ns_entry, "del_ns", NULL);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret != 0;
|
||||
}
|
||||
|
114
kadmin/get.c
114
kadmin/get.c
@@ -61,6 +61,7 @@ static struct field_name {
|
||||
{ "fail_auth_count", KADM5_FAIL_AUTH_COUNT, 0, 0, "Fail count", "Failed login count", RTBL_ALIGN_RIGHT },
|
||||
{ "policy", KADM5_POLICY, 0, 0, "Policy", "Policy", 0 },
|
||||
{ "keytypes", KADM5_KEY_DATA, 0, KADM5_PRINCIPAL | KADM5_KVNO, "Keytypes", "Keytypes", 0 },
|
||||
{ "server-keytypes", KADM5_TL_DATA, KRB5_TL_ETYPES, 0, "Server keytypes", "Supported keytypes (servers)", 0 },
|
||||
{ "password", KADM5_TL_DATA, KRB5_TL_PASSWORD, KADM5_KEY_DATA, "Password", "Password", 0 },
|
||||
{ "pkinit-acl", KADM5_TL_DATA, KRB5_TL_PKINIT_ACL, 0, "PK-INIT ACL", "PK-INIT ACL", 0 },
|
||||
{ "aliases", KADM5_TL_DATA, KRB5_TL_ALIASES, 0, "Aliases", "Aliases", 0 },
|
||||
@@ -81,6 +82,8 @@ struct get_entry_data {
|
||||
uint32_t mask;
|
||||
uint32_t extra_mask;
|
||||
struct field_info *chead, **ctail;
|
||||
const char *krb5_config_fname;
|
||||
uint32_t n;
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -174,9 +177,59 @@ format_keytype(krb5_key_data *k, krb5_salt *def_salt, char *buf, size_t buf_len)
|
||||
free(s);
|
||||
}
|
||||
|
||||
static int
|
||||
is_special_file(const char *fname)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (strcasecmp(fname, "con") == 0 || strcasecmp(fname, "nul") == 0 ||
|
||||
strcasecmp(fname, "aux") == 0 || strcasecmp(fname, "prn") == 0)
|
||||
return 1;
|
||||
if ((strncasecmp(fname, "com", sizeof("com") - 1) == 0 ||
|
||||
strncasecmp(fname, "lpt", sizeof("lpt") - 1) == 0) &&
|
||||
fname[sizeof("lpt")] >= '0' && fname[sizeof("lpt")] <= '9' &&
|
||||
fname[sizeof("lpt") + 1] == '\0')
|
||||
return 1;
|
||||
#else
|
||||
if (strncmp(fname, "/dev/", sizeof("/dev/") - 1) == 0)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *
|
||||
write_krb5_config(krb5_tl_data *tl,
|
||||
const char *fn,
|
||||
uint32_t i)
|
||||
{
|
||||
char *s = NULL;
|
||||
FILE *f = NULL;
|
||||
|
||||
if (fn == NULL)
|
||||
return NULL;
|
||||
if (i == 0 || is_special_file(fn))
|
||||
s = strdup(fn);
|
||||
else if (asprintf(&s, "%s-%u", fn, i) == -1)
|
||||
s = NULL;
|
||||
if (s == NULL)
|
||||
krb5_err(context, 1, errno, "Out of memory");
|
||||
|
||||
/* rk_dumpdata() doesn't allow error checking :( */
|
||||
if ((f = fopen(s, "w")) &&
|
||||
fwrite(tl->tl_data_contents, tl->tl_data_length, 1, f) != 1)
|
||||
krb5_warn(context, errno, "Could not write to %s", fn);
|
||||
if (f && fclose(f))
|
||||
krb5_warn(context, errno, "Could not write to %s", fn);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
format_field(kadm5_principal_ent_t princ, unsigned int field,
|
||||
unsigned int subfield, char *buf, size_t buf_len, int condensed)
|
||||
format_field(struct get_entry_data *data,
|
||||
kadm5_principal_ent_t princ,
|
||||
unsigned int field,
|
||||
unsigned int subfield,
|
||||
char *buf,
|
||||
size_t buf_len,
|
||||
int condensed)
|
||||
{
|
||||
switch(field) {
|
||||
case KADM5_PRINCIPAL:
|
||||
@@ -276,6 +329,31 @@ format_field(kadm5_principal_ent_t princ, unsigned int field,
|
||||
(int)tl->tl_data_length,
|
||||
(const char *)tl->tl_data_contents);
|
||||
break;
|
||||
case KRB5_TL_ETYPES: {
|
||||
HDB_EncTypeList etypes;
|
||||
size_t i, size;
|
||||
char *str;
|
||||
int ret;
|
||||
|
||||
ret = decode_HDB_EncTypeList(tl->tl_data_contents,
|
||||
tl->tl_data_length,
|
||||
&etypes, &size);
|
||||
if (ret) {
|
||||
snprintf(buf, buf_len, "failed to decode server etypes");
|
||||
break;
|
||||
}
|
||||
buf[0] = '\0';
|
||||
for (i = 0; i < etypes.len; i++) {
|
||||
ret = krb5_enctype_to_string(context, etypes.val[i], &str);
|
||||
if (ret == 0) {
|
||||
if (i)
|
||||
strlcat(buf, ",", buf_len);
|
||||
strlcat(buf, str, buf_len);
|
||||
}
|
||||
}
|
||||
free_HDB_EncTypeList(&etypes);
|
||||
break;
|
||||
}
|
||||
case KRB5_TL_PKINIT_ACL: {
|
||||
HDB_Ext_PKINIT_acl acl;
|
||||
size_t size;
|
||||
@@ -309,6 +387,16 @@ format_field(kadm5_principal_ent_t princ, unsigned int field,
|
||||
free_HDB_Ext_PKINIT_acl(&acl);
|
||||
break;
|
||||
}
|
||||
case KRB5_TL_KRB5_CONFIG: {
|
||||
char *fname;
|
||||
|
||||
fname = write_krb5_config(tl, data->krb5_config_fname, data->n);
|
||||
if (fname) {
|
||||
strlcat(buf, fname, buf_len);
|
||||
free(fname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KRB5_TL_ALIASES: {
|
||||
HDB_Ext_Aliases alias;
|
||||
size_t size;
|
||||
@@ -356,7 +444,8 @@ print_entry_short(struct get_entry_data *data, kadm5_principal_ent_t princ)
|
||||
struct field_info *f;
|
||||
|
||||
for(f = data->chead; f != NULL; f = f->next) {
|
||||
format_field(princ, f->ff->fieldvalue, f->ff->subvalue, buf, sizeof(buf), 1);
|
||||
format_field(data, princ, f->ff->fieldvalue, f->ff->subvalue, buf,
|
||||
sizeof(buf), 1);
|
||||
rtbl_add_column_entry_by_id(data->table, f->ff->fieldvalue, buf);
|
||||
}
|
||||
}
|
||||
@@ -374,7 +463,8 @@ print_entry_long(struct get_entry_data *data, kadm5_principal_ent_t princ)
|
||||
width = w;
|
||||
}
|
||||
for(f = data->chead; f != NULL; f = f->next) {
|
||||
format_field(princ, f->ff->fieldvalue, f->ff->subvalue, buf, sizeof(buf), 0);
|
||||
format_field(data, princ, f->ff->fieldvalue, f->ff->subvalue, buf,
|
||||
sizeof(buf), 0);
|
||||
printf("%*s: %s\n", width, f->header ? f->header : f->ff->def_longheader, buf);
|
||||
}
|
||||
printf("\n");
|
||||
@@ -391,13 +481,13 @@ do_get_entry(krb5_principal principal, void *data)
|
||||
ret = kadm5_get_principal(kadm_handle, principal,
|
||||
&princ,
|
||||
e->mask | e->extra_mask);
|
||||
if(ret)
|
||||
return ret;
|
||||
else {
|
||||
(e->format)(e, &princ);
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
if (ret == 0) {
|
||||
(e->format)(e, &princ);
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
}
|
||||
return 0;
|
||||
|
||||
e->n++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -467,7 +557,7 @@ listit(const char *funcname, int argc, char **argv)
|
||||
}
|
||||
|
||||
#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,keytypes,pkinit-acl,aliases"
|
||||
#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,server-keytypes,keytypes,pkinit-acl,aliases"
|
||||
|
||||
static int
|
||||
getit(struct get_options *opt, const char *name, int argc, char **argv)
|
||||
@@ -493,6 +583,8 @@ getit(struct get_options *opt, const char *name, int argc, char **argv)
|
||||
data.ctail = &data.chead;
|
||||
data.mask = 0;
|
||||
data.extra_mask = 0;
|
||||
data.krb5_config_fname = opt->krb5_config_file_string;
|
||||
data.n = 0;
|
||||
|
||||
if(opt->short_flag) {
|
||||
data.table = rtbl_create();
|
||||
|
@@ -215,6 +215,128 @@ command = {
|
||||
min_args = "1"
|
||||
help = "Adds a principal to the database."
|
||||
}
|
||||
command = {
|
||||
name = "add_namespace"
|
||||
name = "add_ns"
|
||||
function = "add_new_namespace"
|
||||
option = {
|
||||
long = "enctypes"
|
||||
short = "e"
|
||||
type = "string"
|
||||
help = "encryption type(s)"
|
||||
}
|
||||
option = {
|
||||
long = "max-ticket-life"
|
||||
type = "string"
|
||||
argument ="lifetime"
|
||||
help = "max ticket lifetime"
|
||||
}
|
||||
option = {
|
||||
long = "max-renewable-life"
|
||||
type = "string"
|
||||
argument = "lifetime"
|
||||
help = "max renewable life"
|
||||
}
|
||||
option = {
|
||||
long = "key-rotation-epoch"
|
||||
type = "string"
|
||||
argument = "time"
|
||||
help = "absolute start time (or +timespec for relative to now with default unit of month)"
|
||||
}
|
||||
option = {
|
||||
long = "key-rotation-period"
|
||||
type = "string"
|
||||
argument = "time"
|
||||
help = "automatic key rotation period"
|
||||
}
|
||||
option = {
|
||||
long = "attributes"
|
||||
type = "string"
|
||||
argument = "attributes"
|
||||
help = "principal attributes"
|
||||
}
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
help = "Adds a namespace of virtual principals with derived keys to the database."
|
||||
}
|
||||
command = {
|
||||
name = "modify_namespace"
|
||||
name = "mod_ns"
|
||||
function = "modify_namespace"
|
||||
option = {
|
||||
long = "enctypes"
|
||||
short = "e"
|
||||
type = "strings"
|
||||
help = "encryption type(s)"
|
||||
}
|
||||
option = {
|
||||
long = "max-ticket-life"
|
||||
type = "string"
|
||||
argument ="lifetime"
|
||||
help = "max ticket lifetime"
|
||||
}
|
||||
option = {
|
||||
long = "max-renewable-life"
|
||||
type = "string"
|
||||
argument = "lifetime"
|
||||
help = "max renewable life"
|
||||
}
|
||||
option = {
|
||||
long = "attributes"
|
||||
type = "string"
|
||||
argument = "attributes"
|
||||
help = "principal attributes"
|
||||
}
|
||||
option = {
|
||||
long = "krb5-config-file"
|
||||
short = "C"
|
||||
type = "string"
|
||||
help = "filename to save the principal's krb5.confg in"
|
||||
}
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
help = "Modifies a namespace of virtual principals with derived keys to the database."
|
||||
}
|
||||
command = {
|
||||
name = "modify_namespace_key_rotation"
|
||||
name = "mod_ns_kr"
|
||||
function = "modify_ns_kr"
|
||||
option = {
|
||||
long = "force"
|
||||
short = "f"
|
||||
type = "flag"
|
||||
help = "change schedule even if it would revoke some extant tickets"
|
||||
}
|
||||
option = {
|
||||
long = "keep-base-key"
|
||||
short = "k"
|
||||
type = "flag"
|
||||
help = "keep current base key for new key rotation schedule"
|
||||
}
|
||||
option = {
|
||||
long = "revoke-old"
|
||||
short = "r"
|
||||
type = "string"
|
||||
argument = "time"
|
||||
help = "delete base keys older than this to revoke old tickets"
|
||||
}
|
||||
option = {
|
||||
long = "new-key-rotation-epoch"
|
||||
type = "string"
|
||||
argument = "time"
|
||||
help = "new start time relative to now"
|
||||
}
|
||||
option = {
|
||||
long = "new-key-rotation-period"
|
||||
type = "string"
|
||||
argument = "time"
|
||||
help = "new automatic key rotation period"
|
||||
}
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
max_args = "1"
|
||||
help = "Adds or changes new key rotation schedule for the given namespace."
|
||||
}
|
||||
command = {
|
||||
name = "passwd"
|
||||
name = "cpw"
|
||||
@@ -276,6 +398,14 @@ command = {
|
||||
min_args = "1"
|
||||
help = "Deletes all principals matching the expressions."
|
||||
}
|
||||
command = {
|
||||
name = "delete_namespace"
|
||||
name = "del_ns"
|
||||
function = "del_namespace"
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
help = "Deletes the given virtual principal namespaces"
|
||||
}
|
||||
command = {
|
||||
name = "del_enctype"
|
||||
argument = "principal enctype..."
|
||||
@@ -364,6 +494,12 @@ command = {
|
||||
type = "string"
|
||||
help = "columns to print for short output"
|
||||
}
|
||||
option = {
|
||||
long = "krb5-config-file"
|
||||
short = "C"
|
||||
type = "string"
|
||||
help = "filename to save the principal's krb5.confg in"
|
||||
}
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
help = "Shows information about principals matching the expressions."
|
||||
@@ -378,6 +514,7 @@ command = {
|
||||
}
|
||||
command = {
|
||||
name = "modify"
|
||||
name = "mod"
|
||||
function = "mod_entry"
|
||||
option = {
|
||||
long = "max-ticket-life"
|
||||
@@ -440,6 +577,13 @@ command = {
|
||||
argument = "policy"
|
||||
help = "policy name"
|
||||
}
|
||||
option = {
|
||||
long = "service-enctypes"
|
||||
short = "e"
|
||||
type = "strings"
|
||||
argument = "enctype"
|
||||
help = "set enctypes supported by service"
|
||||
}
|
||||
option = {
|
||||
long = "hist-kvno-diff-clnt"
|
||||
type = "integer"
|
||||
@@ -454,6 +598,12 @@ command = {
|
||||
help = "historic keys allowed for service"
|
||||
default = "-1"
|
||||
}
|
||||
option = {
|
||||
long = "krb5-config-file"
|
||||
short = "C"
|
||||
type = "string"
|
||||
help = "krb5.conf to save in principal record"
|
||||
}
|
||||
argument = "principal"
|
||||
min_args = "1"
|
||||
max_args = "1"
|
||||
@@ -507,6 +657,10 @@ command = {
|
||||
type = "string"
|
||||
help = "columns to print for short output"
|
||||
}
|
||||
option = {
|
||||
long = "krb5-config-file"
|
||||
type = "string"
|
||||
}
|
||||
argument = "principal..."
|
||||
min_args = "1"
|
||||
help = "Lists principals in a terse format. Equivalent to \"get -t\"."
|
||||
|
@@ -140,6 +140,55 @@ The only policy supported by Heimdal servers is
|
||||
.Ql default .
|
||||
.Ed
|
||||
.Pp
|
||||
.Nm add_namespace
|
||||
.Ar Fl Fl key-rotation-epoch= Ns Ar time
|
||||
.Ar Fl Fl key-rotation-period= Ns Ar time
|
||||
.Op Fl Fl enctypes= Ns Ar string
|
||||
.Op Fl Fl max-ticket-life= Ns Ar lifetime
|
||||
.Op Fl Fl max-renewable-life= Ns Ar lifetime
|
||||
.Op Fl Fl attributes= Ns Ar attributes
|
||||
.Ar principal...
|
||||
.Bd -ragged -offset indent
|
||||
Adds a new namespace of virtual host-based or domain-based
|
||||
principals to the database, whose keys will be automatically
|
||||
derived from base keys stored in the namespace record, and which
|
||||
keys will be rotated automatically.
|
||||
The namespace names should look like
|
||||
.Ar hostname@REALM
|
||||
and these will match all host-based or domain-based service names
|
||||
where hostname component of such a principal ends in the labels
|
||||
of the hostname in the namespace name.
|
||||
.Pp
|
||||
For example,
|
||||
.Ar bar.baz.example@BAZ.EXAMPLE
|
||||
will match
|
||||
.Ar host/foo.bar.baz.example@BAZ.EXAMPLE
|
||||
but not
|
||||
.Ar host/foobar.baz.example@BAZ.EXAMPLE .
|
||||
.Pp
|
||||
Note well that services are expected to
|
||||
.Ar ext_keytab
|
||||
or otherwise re-fetch their keytabs at least as often as one
|
||||
quarter of the key rotation period, otherwise they risk not
|
||||
having keys they need to decrypt tickets with.
|
||||
.Pp
|
||||
The epoch must be given as either an absolute time,
|
||||
.Ar "now",
|
||||
or as
|
||||
.Ar "+<N>[<unit>]"
|
||||
where
|
||||
.Ar N
|
||||
is a natural and
|
||||
.Ar unit
|
||||
is one "s", "m", "h", "day", "week", "month", defaulting to
|
||||
"month".
|
||||
The default key rotation period is
|
||||
.Ar 7d .
|
||||
The default enctypes is as for the
|
||||
.Nm add
|
||||
command.
|
||||
.Ed
|
||||
.Pp
|
||||
.Nm add_enctype
|
||||
.Op Fl r | Fl Fl random-key
|
||||
.Ar principal enctypes...
|
||||
@@ -213,6 +262,7 @@ behavior is the default if none of these are given.
|
||||
.Op Fl s | Fl Fl short
|
||||
.Op Fl t | Fl Fl terse
|
||||
.Op Fl o Ar string | Fl Fl column-info= Ns Ar string
|
||||
.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path
|
||||
.Ar principal...
|
||||
.Bd -ragged -offset indent
|
||||
Lists the matching principals, short prints the result as a table,
|
||||
@@ -229,6 +279,16 @@ The default terse output format is similar to
|
||||
.Fl s o Ar principal= ,
|
||||
just printing the names of matched principals.
|
||||
.Pp
|
||||
If
|
||||
.Fl C
|
||||
or
|
||||
.Fl Fl krb5-config-file
|
||||
is given and the principal has krb5 config file contents saved
|
||||
in its HDB entry, then that will be saved in the given file.
|
||||
Note that if multiple principals are requested, then the second,
|
||||
third, and so on will have -1, -2, and so on appended to the
|
||||
given filename unless the given filename is a device name.
|
||||
.Pp
|
||||
Possible column names include:
|
||||
.Li principal ,
|
||||
.Li princ_expire_time ,
|
||||
@@ -260,15 +320,18 @@ and
|
||||
.Op Fl Fl pw-expiration-time= Ns Ar time
|
||||
.Op Fl Fl kvno= Ns Ar number
|
||||
.Op Fl Fl policy= Ns Ar policy-name
|
||||
.Op Fl C Ar path | Fl Fl krb5-config-file= Ns Ar path
|
||||
.Ar principal...
|
||||
.Bd -ragged -offset indent
|
||||
Modifies certain attributes of a principal. If run without command
|
||||
line options, you will be prompted. With command line options, it will
|
||||
only change the ones specified.
|
||||
.Pp
|
||||
Only policy supported by Heimdal is
|
||||
The only policy supported by Heimdal is
|
||||
.Ql default .
|
||||
.Pp
|
||||
If a krb5 config file is given, it will be saved in the entry.
|
||||
.Pp
|
||||
Possible attributes are:
|
||||
.Li new-princ ,
|
||||
.Li support-desmd5 ,
|
||||
|
@@ -156,5 +156,9 @@ kadmind_loop (krb5_context, krb5_keytab, int);
|
||||
int
|
||||
handle_mit(krb5_context, void *, size_t, int);
|
||||
|
||||
/* mod.c */
|
||||
|
||||
void
|
||||
add_tl(kadm5_principal_ent_rec *, int, krb5_data *);
|
||||
|
||||
#endif /* __ADMIN_LOCL_H__ */
|
||||
|
355
kadmin/mod.c
355
kadmin/mod.c
@@ -34,7 +34,7 @@
|
||||
#include "kadmin_locl.h"
|
||||
#include "kadmin-commands.h"
|
||||
|
||||
static void
|
||||
void
|
||||
add_tl(kadm5_principal_ent_rec *princ, int type, krb5_data *data)
|
||||
{
|
||||
krb5_tl_data *tl, **ptl;
|
||||
@@ -185,6 +185,43 @@ add_pkinit_acl(krb5_context contextp, kadm5_principal_ent_rec *princ,
|
||||
add_tl(princ, KRB5_TL_EXTENSION, &buf);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
add_etypes(krb5_context contextp,
|
||||
kadm5_principal_ent_rec *princ,
|
||||
struct getarg_strings *strings)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
HDB_EncTypeList etypes;
|
||||
krb5_data buf;
|
||||
size_t i, size;
|
||||
|
||||
etypes.len = strings->num_strings;
|
||||
if ((etypes.val = calloc(strings->num_strings,
|
||||
sizeof(etypes.val[0]))) == NULL)
|
||||
krb5_err(contextp, 1, ret, "Out of memory");
|
||||
|
||||
for (i = 0; i < strings->num_strings; i++) {
|
||||
krb5_enctype etype;
|
||||
|
||||
ret = krb5_string_to_enctype(contextp, strings->strings[i], &etype);
|
||||
if (ret) {
|
||||
krb5_warn(contextp, ret, "Could not parse enctype %s",
|
||||
strings->strings[i]);
|
||||
return ret;
|
||||
}
|
||||
etypes.val[i] = etype;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
ASN1_MALLOC_ENCODE(HDB_EncTypeList, buf.data, buf.length,
|
||||
&etypes, &size, ret);
|
||||
}
|
||||
if (ret || buf.length != size)
|
||||
abort();
|
||||
add_tl(princ, KRB5_TL_ETYPES, &buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
add_kvno_diff(krb5_context contextp, kadm5_principal_ent_rec *princ,
|
||||
int is_svc_diff, krb5_kvno kvno_diff)
|
||||
@@ -216,6 +253,35 @@ add_kvno_diff(krb5_context contextp, kadm5_principal_ent_rec *princ,
|
||||
add_tl(princ, KRB5_TL_EXTENSION, &buf);
|
||||
}
|
||||
|
||||
static void
|
||||
add_krb5_config(kadm5_principal_ent_rec *princ, const char *fname)
|
||||
{
|
||||
HDB_extension ext;
|
||||
krb5_data buf;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
memset(&ext, 0, sizeof(ext));
|
||||
ext.mandatory = FALSE;
|
||||
ext.data.element = choice_HDB_extension_data_krb5_config;
|
||||
|
||||
if ((ret = rk_undumpdata(fname,
|
||||
&ext.data.u.krb5_config.data,
|
||||
&ext.data.u.krb5_config.length))) {
|
||||
krb5_warn(context, ret, "Could not read %s", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
ASN1_MALLOC_ENCODE(HDB_extension, buf.data, buf.length,
|
||||
&ext, &size, ret);
|
||||
free_HDB_extension(&ext);
|
||||
if (ret)
|
||||
abort();
|
||||
if (buf.length != size)
|
||||
abort();
|
||||
add_tl(princ, KRB5_TL_EXTENSION, &buf);
|
||||
}
|
||||
|
||||
static int
|
||||
do_mod_entry(krb5_principal principal, void *data)
|
||||
{
|
||||
@@ -240,9 +306,11 @@ do_mod_entry(krb5_principal principal, void *data)
|
||||
e->attributes_string ||
|
||||
e->policy_string ||
|
||||
e->kvno_integer != -1 ||
|
||||
e->service_enctypes_strings.num_strings ||
|
||||
e->constrained_delegation_strings.num_strings ||
|
||||
e->alias_strings.num_strings ||
|
||||
e->pkinit_acl_strings.num_strings ||
|
||||
e->krb5_config_file_string ||
|
||||
e->hist_kvno_diff_clnt_integer != -1 ||
|
||||
e->hist_kvno_diff_svc_integer != -1) {
|
||||
ret = set_entry(context, &princ, &mask,
|
||||
@@ -269,6 +337,10 @@ do_mod_entry(krb5_principal principal, void *data)
|
||||
add_pkinit_acl(context, &princ, &e->pkinit_acl_strings);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
if (e->service_enctypes_strings.num_strings) {
|
||||
ret = add_etypes(context, &princ, &e->service_enctypes_strings);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
if (e->hist_kvno_diff_clnt_integer != -1) {
|
||||
add_kvno_diff(context, &princ, 0, e->hist_kvno_diff_clnt_integer);
|
||||
mask |= KADM5_TL_DATA;
|
||||
@@ -277,6 +349,10 @@ do_mod_entry(krb5_principal principal, void *data)
|
||||
add_kvno_diff(context, &princ, 1, e->hist_kvno_diff_svc_integer);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
if (e->krb5_config_file_string) {
|
||||
add_krb5_config(&princ, e->krb5_config_file_string);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
} else
|
||||
ret = edit_entry(&princ, &mask, NULL, 0);
|
||||
if(ret == 0) {
|
||||
@@ -303,3 +379,280 @@ mod_entry(struct modify_options *opt, int argc, char **argv)
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_mod_ns_entry(krb5_principal principal, void *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
kadm5_principal_ent_rec princ;
|
||||
int mask = 0;
|
||||
struct modify_namespace_options *e = data;
|
||||
|
||||
memset (&princ, 0, sizeof(princ));
|
||||
ret = kadm5_get_principal(kadm_handle, principal, &princ,
|
||||
KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
|
||||
KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
|
||||
KADM5_PRINC_EXPIRE_TIME |
|
||||
KADM5_PW_EXPIRATION);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
if(e->max_ticket_life_string ||
|
||||
e->max_renewable_life_string ||
|
||||
e->attributes_string ||
|
||||
e->enctypes_strings.num_strings ||
|
||||
e->krb5_config_file_string) {
|
||||
ret = set_entry(context, &princ, &mask, e->max_ticket_life_string,
|
||||
e->max_renewable_life_string, NULL, NULL,
|
||||
e->attributes_string, NULL);
|
||||
if (e->enctypes_strings.num_strings) {
|
||||
ret = add_etypes(context, &princ, &e->enctypes_strings);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
if (e->krb5_config_file_string) {
|
||||
add_krb5_config(&princ, e->krb5_config_file_string);
|
||||
mask |= KADM5_TL_DATA;
|
||||
}
|
||||
} else
|
||||
ret = edit_entry(&princ, &mask, NULL, 0);
|
||||
if(ret == 0) {
|
||||
ret = kadm5_modify_principal(kadm_handle, &princ, mask);
|
||||
if(ret)
|
||||
krb5_warn(context, ret, "kadm5_modify_principal");
|
||||
}
|
||||
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
modify_namespace(struct modify_namespace_options *opt, int argc, char **argv)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < argc; i++) {
|
||||
ret = foreach_principal(argv[i], do_mod_ns_entry, "mod_ns", opt);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct modify_namespace_key_rotation_options {
|
||||
int force_flag;
|
||||
int keep_base_key_flag;
|
||||
char* revoke_old_string;
|
||||
char* new_key_rotation_epoch_string;
|
||||
char* new_key_rotation_period_string;
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
princ2kstuple(kadm5_principal_ent_rec *princ,
|
||||
unsigned int kvno,
|
||||
krb5_key_salt_tuple **kstuple,
|
||||
size_t *nkstuple)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
HDB_EncTypeList etypes;
|
||||
krb5_tl_data *tl;
|
||||
size_t i;
|
||||
|
||||
*kstuple = 0;
|
||||
*nkstuple = 0;
|
||||
etypes.len = 0;
|
||||
etypes.val = 0;
|
||||
for (tl = princ->tl_data; tl; tl = tl->tl_data_next) {
|
||||
if (tl->tl_data_type != KRB5_TL_ETYPES || tl->tl_data_length < 0)
|
||||
continue;
|
||||
ret = decode_HDB_EncTypeList(tl->tl_data_contents, tl->tl_data_length,
|
||||
&etypes, NULL);
|
||||
if (ret)
|
||||
break;
|
||||
*nkstuple = etypes.len;
|
||||
*kstuple = ecalloc(etypes.len, sizeof(kstuple[0][0]));
|
||||
for (i = 0; i < etypes.len; i++) {
|
||||
(*kstuple)[i].ks_enctype = etypes.val[i];
|
||||
(*kstuple)[i].ks_salttype = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (princ->n_key_data > 0) {
|
||||
*kstuple = ecalloc(1, sizeof(kstuple[0][0]));
|
||||
*nkstuple = 1;
|
||||
for (i = 0; i < princ->n_key_data; i++) {
|
||||
if (princ->key_data->key_data_kvno == kvno) {
|
||||
(*kstuple)[0].ks_enctype = princ->key_data->key_data_type[0];
|
||||
(*kstuple)[0].ks_salttype = princ->key_data->key_data_type[1];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
krb5_warnx(context, "Could not determine what enctypes to generate "
|
||||
"keys for; recreate namespace?");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
randkey_kr(kadm5_principal_ent_rec *princ,
|
||||
unsigned int old_kvno,
|
||||
unsigned int kvno)
|
||||
{
|
||||
krb5_key_salt_tuple *kstuple = 0;
|
||||
krb5_error_code ret = 0;
|
||||
size_t nkstuple = 0;
|
||||
|
||||
/*
|
||||
* We might be using kadm5clnt, so we'll use kadm5_randkey_principal_3(),
|
||||
* which will generate new keys on the server side. This allows a race,
|
||||
* but it will be detected by the key rotation update checks in lib/kadm5
|
||||
* and lib/hdb.
|
||||
*/
|
||||
ret = princ2kstuple(princ, old_kvno, &kstuple, &nkstuple);
|
||||
if (ret == 0)
|
||||
ret = kadm5_randkey_principal_3(kadm_handle, princ->principal, 1,
|
||||
nkstuple, kstuple, NULL, NULL);
|
||||
free(kstuple);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
do_mod_ns_kr(krb5_principal principal, void *data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
kadm5_principal_ent_rec princ;
|
||||
struct modify_namespace_key_rotation_options *e = data;
|
||||
HDB_Ext_KeyRotation existing;
|
||||
HDB_Ext_KeyRotation new_kr;
|
||||
HDB_extension ext;
|
||||
KeyRotation new_krs[3];
|
||||
krb5_tl_data *tl;
|
||||
krb5_data d;
|
||||
time_t now = time(NULL);
|
||||
size_t size;
|
||||
int freeit = 0;
|
||||
|
||||
d.data = 0;
|
||||
d.length = 0;
|
||||
new_kr.len = 0;
|
||||
new_kr.val = new_krs;
|
||||
ext.mandatory = 0;
|
||||
ext.data.element = choice_HDB_extension_data_key_rotation;
|
||||
ext.data.u.key_rotation.len = 0;
|
||||
ext.data.u.key_rotation.val = 0;
|
||||
existing.len = 0;
|
||||
existing.val = 0;
|
||||
memset(&new_krs, 0, sizeof(new_krs));
|
||||
memset(&princ, 0, sizeof(princ));
|
||||
|
||||
if (e->force_flag || e->revoke_old_string) {
|
||||
krb5_warnx(context, "--force and --revoke-old not implemented yet");
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
ret = kadm5_get_principal(kadm_handle, principal, &princ,
|
||||
KADM5_PRINCIPAL | KADM5_KVNO |
|
||||
KADM5_KEY_DATA | KADM5_TL_DATA);
|
||||
if (ret == 0) {
|
||||
freeit = 1;
|
||||
for (tl = princ.tl_data; tl; tl = tl->tl_data_next) {
|
||||
if (tl->tl_data_type != KRB5_TL_KRB5_CONFIG)
|
||||
continue;
|
||||
ret = decode_HDB_Ext_KeyRotation(tl->tl_data_contents,
|
||||
tl->tl_data_length, &existing, NULL);
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "unable to decode existing key "
|
||||
"rotation schedule");
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (!existing.len) {
|
||||
krb5_warnx(context, "no key rotation schedule; "
|
||||
"re-create namespace?");
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "No such namespace");
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (existing.len > 1)
|
||||
new_kr.val[1] = existing.val[0];
|
||||
if (existing.len > 2)
|
||||
new_kr.val[2] = existing.val[1];
|
||||
new_kr.val[0].flags = existing.val[0].flags;
|
||||
new_kr.val[0].base_kvno = princ.kvno + 2; /* XXX Compute better */
|
||||
new_kr.val[0].base_key_kvno = existing.val[0].base_key_kvno + 1;
|
||||
if (e->new_key_rotation_epoch_string) {
|
||||
if ((ret = str2time_t(e->new_key_rotation_epoch_string,
|
||||
&new_kr.val[0].epoch)))
|
||||
krb5_warn(context, ret, "Invalid epoch specification: %s",
|
||||
e->new_key_rotation_epoch_string);
|
||||
} else {
|
||||
new_kr.val[0].epoch = existing.val[0].epoch +
|
||||
existing.val[0].period * (princ.kvno - new_kr.val[0].base_kvno);
|
||||
}
|
||||
if (ret == 0 && e->new_key_rotation_period_string) {
|
||||
time_t t;
|
||||
|
||||
if ((ret = str2time_t(e->new_key_rotation_period_string, &t)))
|
||||
krb5_warn(context, ret, "Invalid period specification: %s",
|
||||
e->new_key_rotation_period_string);
|
||||
else
|
||||
new_kr.val[0].period = t;
|
||||
} else {
|
||||
new_kr.val[0].period = existing.val[0].period +
|
||||
existing.val[0].period * (princ.kvno - new_kr.val[0].base_kvno);
|
||||
}
|
||||
if (new_kr.val[0].epoch < now) {
|
||||
krb5_warnx(context, "New epoch cannot be in the past");
|
||||
ret = EINVAL;
|
||||
}
|
||||
if (new_kr.val[0].epoch < 30) {
|
||||
krb5_warnx(context, "New period cannot be less than 30s");
|
||||
ret = EINVAL;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = randkey_kr(&princ, princ.kvno, new_kr.val[0].base_key_kvno);
|
||||
ext.data.u.key_rotation = new_kr;
|
||||
if (ret == 0)
|
||||
ASN1_MALLOC_ENCODE(HDB_extension, d.data, d.length,
|
||||
&ext, &size, ret);
|
||||
if (ret == 0)
|
||||
add_tl(&princ, KRB5_TL_EXTENSION, &d);
|
||||
if (ret == 0) {
|
||||
ret = kadm5_modify_principal(kadm_handle, &princ,
|
||||
KADM5_PRINCIPAL | KADM5_TL_DATA);
|
||||
if (ret)
|
||||
krb5_warn(context, ret, "Could not update namespace");
|
||||
}
|
||||
|
||||
krb5_data_free(&d);
|
||||
free_HDB_Ext_KeyRotation(&existing);
|
||||
if (freeit)
|
||||
kadm5_free_principal_ent(kadm_handle, &princ);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
modify_ns_kr(struct modify_namespace_key_rotation_options *opt,
|
||||
int argc,
|
||||
char **argv)
|
||||
{
|
||||
krb5_error_code ret = 0;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < argc; i++) {
|
||||
ret = foreach_principal(argv[i], do_mod_ns_kr, "mod_ns", opt);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
return ret != 0;
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user