diff --git a/doc/setup.texi b/doc/setup.texi index f0e298784..f2fb07ec3 100644 --- a/doc/setup.texi +++ b/doc/setup.texi @@ -472,12 +472,14 @@ number, special characters. @item enforce_on_admin_set -The enforce_on_admin_set check validates that administrative password changes -via kpasswdd or kadmind are also subject to the password policy. Note that -@command{kadmin} in local mode can still bypass these. An administrative -password change is one where the identity of the authenticating principal -differs from the subject of the password change. Default value if not given is -true. +The enforce_on_admin_set check subjects administrative password updates to the +password policy. An administrative password update is a create principal or +change password request via @command{kadmind}, or a set password request via +@command{kpasswdd}. (A set password request is one where the authenticating +principal differs from the principal whose password is being changed.) Password +policies are always ignored if the authenticating principal is the kadmin +service itself, for example when running @command{kadmin} in local mode. The +default value for enforce_on_admin_set if not given is true. @end itemize diff --git a/kadmin/server.c b/kadmin/server.c index 03605e504..f8478deda 100644 --- a/kadmin/server.c +++ b/kadmin/server.c @@ -38,9 +38,6 @@ 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) @@ -181,24 +178,6 @@ 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); @@ -354,30 +333,6 @@ kadmind_dispatch(void *kadm_handlep, krb5_boolean initial, } } - /* - * 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; - - pwd_data.data = password; - pwd_data.length = strlen(password); - - pwd_reason = kadm5_check_password_quality (contextp->context, - princ, &pwd_data); - if (pwd_reason != NULL) - ret = KADM5_PASS_Q_DICT; - else - ret = 0; - 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); @@ -874,10 +829,3 @@ 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); -} diff --git a/kpasswd/kpasswdd.c b/kpasswd/kpasswdd.c index f7bb4474b..cc617dd71 100644 --- a/kpasswd/kpasswdd.c +++ b/kpasswd/kpasswdd.c @@ -40,6 +40,7 @@ RCSID("$Id$"); #endif #include #include +#include static krb5_context context; static krb5_log_facility *log_facility; @@ -246,14 +247,12 @@ change (krb5_auth_context auth_context, { krb5_error_code ret; char *client = NULL, *admin = NULL; - const char *pwd_reason; kadm5_config_params conf; void *kadm5_handle = NULL; krb5_principal principal = NULL; krb5_data *pwd_data = NULL; char *tmp; ChangePasswdDataMS chpw; - krb5_boolean enforce_pwqual_on_admin_set; memset (&conf, 0, sizeof(conf)); memset(&chpw, 0, sizeof(chpw)); @@ -383,29 +382,6 @@ change (krb5_auth_context auth_context, krb5_warnx (context, "Changing password for %s", client); } - /* - * 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). - */ - enforce_pwqual_on_admin_set = - krb5_config_get_bool_default(context, NULL, TRUE, - "password_quality", - "enforce_on_admin_set", NULL); - if (krb5_principal_compare(context, admin_principal, principal) == TRUE || - enforce_pwqual_on_admin_set == TRUE) { - pwd_reason = kadm5_check_password_quality (context, principal, - pwd_data); - if (pwd_reason != NULL ) { - krb5_warnx (context, - "%s didn't pass password quality check with error: %s", - client, pwd_reason); - reply_priv (auth_context, s, sa, sa_size, - KRB5_KPASSWD_SOFTERROR, pwd_reason); - goto out; - } - } - ret = krb5_data_realloc(pwd_data, pwd_data->length + 1); if (ret) { krb5_warn (context, ret, "malloc: out of memory"); @@ -421,7 +397,14 @@ change (krb5_auth_context auth_context, pwd_data = NULL; if (ret) { const char *str = krb5_get_error_message(context, ret); - krb5_warnx(context, "kadm5_s_chpass_principal_cond: %s", str); + + if (ret == KADM5_PASS_Q_DICT) { + krb5_warnx(context, + "%s didn't pass password quality check with error: %s", + client, str); + } else { + krb5_warnx(context, "kadm5_s_chpass_principal_cond: %s", str); + } reply_priv (auth_context, s, sa, sa_size, KRB5_KPASSWD_SOFTERROR, str ? str : "Internal error"); krb5_free_error_message(context, str); diff --git a/lib/kadm5/acl.c b/lib/kadm5/acl.c index fdee715f9..5f0b3290d 100644 --- a/lib/kadm5/acl.c +++ b/lib/kadm5/acl.c @@ -141,6 +141,21 @@ fetch_acl (kadm5_server_context *context, return ret; } +krb5_boolean +_kadm5_is_kadmin_service_p(kadm5_server_context *context) +{ + krb5_boolean ret; + krb5_principal princ; + + if (krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ) != 0) + return FALSE; + + ret = krb5_principal_compare(context->context, context->caller, princ); + krb5_free_principal(context->context, princ); + + return ret; +} + /* * set global acl flags in `context' for the current caller. * return 0 on success or an error @@ -149,15 +164,7 @@ fetch_acl (kadm5_server_context *context, kadm5_ret_t _kadm5_acl_init(kadm5_server_context *context) { - krb5_principal princ; - krb5_error_code ret; - - ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ); - if (ret) - return ret; - ret = krb5_principal_compare(context->context, context->caller, princ); - krb5_free_principal(context->context, princ); - if(ret != 0) { + if (_kadm5_is_kadmin_service_p(context)) { context->acl_flags = KADM5_PRIV_ALL; return 0; } diff --git a/lib/kadm5/chpass_s.c b/lib/kadm5/chpass_s.c index 726ab5f0a..0a76e0575 100644 --- a/lib/kadm5/chpass_s.c +++ b/lib/kadm5/chpass_s.c @@ -88,6 +88,23 @@ change(void *server_handle, uint32_t hook_flags = 0; memset(&ent, 0, sizeof(ent)); + + if (krb5_principal_compare(context->context, princ, context->caller) || + _kadm5_enforce_pwqual_on_admin_set_p(context)) { + krb5_data pwd_data; + const char *pwd_reason; + + pwd_data.data = rk_UNCONST(password); + pwd_data.length = strlen(password); + + pwd_reason = kadm5_check_password_quality(context->context, + princ, &pwd_data); + if (pwd_reason != NULL) { + krb5_set_error_message(context->context, KADM5_PASS_Q_DICT, "%s", pwd_reason); + return KADM5_PASS_Q_DICT; + } + } + if (!context->keep_open) { ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0); if(ret) @@ -324,3 +341,18 @@ kadm5_s_chpass_principal_with_key(void *server_handle, } return _kadm5_error_code(ret); } + +/* + * Returns TRUE if password quality should be checked when passwords are + * being set or changed by administrators. This includes principal creation. + */ +krb5_boolean +_kadm5_enforce_pwqual_on_admin_set_p(kadm5_server_context *contextp) +{ + if (_kadm5_is_kadmin_service_p(contextp)) + return FALSE; + + return krb5_config_get_bool_default(contextp->context, NULL, TRUE, + "password_quality", + "enforce_on_admin_set", NULL); +} diff --git a/lib/kadm5/create_s.c b/lib/kadm5/create_s.c index b1fe35d9c..0340dc144 100644 --- a/lib/kadm5/create_s.c +++ b/lib/kadm5/create_s.c @@ -212,6 +212,21 @@ kadm5_s_create_principal(void *server_handle, hdb_entry_ex ent; kadm5_server_context *context = server_handle; + if (_kadm5_enforce_pwqual_on_admin_set_p(context)) { + krb5_data pwd_data; + const char *pwd_reason; + + pwd_data.data = rk_UNCONST(password); + pwd_data.length = strlen(password); + + pwd_reason = kadm5_check_password_quality(context->context, + princ->principal, &pwd_data); + if (pwd_reason != NULL) { + krb5_set_error_message(context->context, KADM5_PASS_Q_DICT, "%s", pwd_reason); + return KADM5_PASS_Q_DICT; + } + } + if ((mask & KADM5_KVNO) == 0) { /* create_principal() through _kadm5_setup_entry(), will need this */ princ->kvno = 1;