kadmin: allow enforcing password quality on admin password change

This patch adds the "enforce_on_admin_set" configuration knob in the
[password_quality] section. When this is enabled, administrative password
changes via the kadmin or kpasswd protocols will be subject to password quality
checks. (An administrative password change is one where the authenticating
principal is different to the principal whose password is being changed.)

Note that kadmin running in local mode (-l) is unaffected by this patch.
This commit is contained in:
Luke Howard
2018-12-24 15:28:32 +11:00
parent 6ce1aa84c5
commit c89d3f3b8c
6 changed files with 103 additions and 40 deletions

View File

@@ -38,6 +38,9 @@ static kadm5_ret_t check_aliases(kadm5_server_context *,
kadm5_principal_ent_rec *,
kadm5_principal_ent_rec *);
static krb5_boolean
enforce_pwqual_on_admin_set_p(kadm5_server_context *contextp);
static kadm5_ret_t
kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
krb5_data *in, krb5_data *out)
@@ -178,6 +181,24 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
}
krb5_unparse_name_fixed(contextp->context, ent.principal,
name, sizeof(name));
if (enforce_pwqual_on_admin_set_p(contextp)) {
krb5_data pwd_data;
const char *pwd_reason;
pwd_data.data = password;
pwd_data.length = strlen(password);
pwd_reason = kadm5_check_password_quality (contextp->context,
ent.principal, &pwd_data);
if (pwd_reason != NULL)
ret = KADM5_PASS_Q_DICT;
else
ret = 0;
if (ret) {
kadm5_free_principal_ent(kadm_handlep, &ent);
goto fail;
}
}
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD,
ent.principal);
@@ -296,6 +317,8 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
break;
}
case kadm_chpass:{
krb5_boolean is_self_cpw, allow_self_cpw;
op = "CHPASS";
ret = krb5_ret_principal(sp, &princ);
if (ret)
@@ -314,21 +337,29 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
/*
* The change is allowed if at least one of:
*
* a) allowed by sysadmin
* b) it's for the principal him/herself and this was an
* initial ticket, but then, check with the password quality
* function.
* c) the user is on the CPW ACL.
* Change password requests are subject to ACLs unless the principal is
* changing their own password and the initial ticket flag is set, and
* the allow_self_change_password configuration option is TRUE.
*/
is_self_cpw =
krb5_principal_compare(contextp->context, contextp->caller, princ);
allow_self_cpw =
krb5_config_get_bool_default(contextp->context, NULL, TRUE,
"kadmin", "allow_self_change_password", NULL);
if (!(is_self_cpw && initial && allow_self_cpw)) {
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
if (ret) {
krb5_free_principal(contextp->context, princ);
goto fail;
}
}
if (krb5_config_get_bool_default(contextp->context, NULL, TRUE,
"kadmin", "allow_self_change_password", NULL)
&& initial
&& krb5_principal_compare (contextp->context, contextp->caller,
princ))
{
/*
* Change password requests are subject to password quality checks if
* the principal is changing their own password, or the enforce_on_admin_set
* configuration option is TRUE (the default).
*/
if (is_self_cpw || enforce_pwqual_on_admin_set_p(contextp)) {
krb5_data pwd_data;
const char *pwd_reason;
@@ -341,13 +372,12 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
ret = KADM5_PASS_Q_DICT;
else
ret = 0;
} else
ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
if(ret) {
krb5_free_principal(contextp->context, princ);
goto fail;
if (ret) {
krb5_free_principal(contextp->context, princ);
goto fail;
}
}
ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL,
password);
krb5_free_principal(contextp->context, princ);
@@ -843,3 +873,11 @@ kadmind_loop(krb5_context contextp,
return 0;
}
static krb5_boolean
enforce_pwqual_on_admin_set_p(kadm5_server_context *contextp)
{
return krb5_config_get_bool_default(contextp->context, NULL, TRUE,
"password_quality",
"enforce_on_admin_set", NULL);
}