diff options
author | Andrew Bartlett <abartlet@samba.org> | 2009-06-18 11:08:46 +1000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2009-06-18 13:49:30 +1000 |
commit | 19413c52495877d54c90c60229568d0077fda30b (patch) | |
tree | c148e96ba2ff28933f2d5f3714b8fc7e60957dec /source4/kdc | |
parent | 2afc6df9b49a246129acdd7c8c24448c8cf3b6ef (diff) | |
download | samba-19413c52495877d54c90c60229568d0077fda30b.tar.gz samba-19413c52495877d54c90c60229568d0077fda30b.tar.bz2 samba-19413c52495877d54c90c60229568d0077fda30b.zip |
s4:kdc Allow a password change when the password is expired
This requires a rework on Heimdal's windc plugin layer, as we want
full control over what tickets Heimdal will issue. (In particular, in
case our requirements become more complex in future).
The original problem was that Heimdal's check would permit the ticket,
but Samba would then deny it, not knowing it was for kadmin/changepw
Also (in hdb-samba4) be a bit more careful on what entries we will
make the 'change_pw' service mark that this depends on.
Andrew Bartlett
Diffstat (limited to 'source4/kdc')
-rw-r--r-- | source4/kdc/hdb-samba4.c | 13 | ||||
-rw-r--r-- | source4/kdc/kdc.h | 2 | ||||
-rw-r--r-- | source4/kdc/pac-glue.c | 75 |
3 files changed, 54 insertions, 36 deletions
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c index c0fa5132d1..eda7867bb5 100644 --- a/source4/kdc/hdb-samba4.c +++ b/source4/kdc/hdb-samba4.c @@ -627,7 +627,18 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, entry_ex->entry.flags.invalid = 0; entry_ex->entry.flags.server = 1; - entry_ex->entry.flags.change_pw = 1; + + /* Don't mark all requests for the krbtgt/realm as + * 'change password', as otherwise we could get into + * trouble, and not enforce the password expirty. + * Instead, only do it when request is for the kpasswd service */ + if (ent_type == HDB_SAMBA4_ENT_TYPE_SERVER + && principal->name.name_string.len == 2 + && (strcmp(principal->name.name_string.val[0], "kadmin") == 0) + && (strcmp(principal->name.name_string.val[1], "changepw") == 0) + && lp_is_my_domain_or_realm(lp_ctx, principal->realm)) { + entry_ex->entry.flags.change_pw = 1; + } entry_ex->entry.flags.client = 0; entry_ex->entry.flags.forwardable = 1; entry_ex->entry.flags.ok_as_delegate = 1; diff --git a/source4/kdc/kdc.h b/source4/kdc/kdc.h index a281e1d9c9..d37a32ebbf 100644 --- a/source4/kdc/kdc.h +++ b/source4/kdc/kdc.h @@ -22,8 +22,8 @@ #include "system/kerberos.h" #include "auth/kerberos/kerberos.h" -#include <kdc.h> #include <hdb.h> +#include <kdc.h> #include <krb5/windc_plugin.h> #include "kdc/pac_glue.h" diff --git a/source4/kdc/pac-glue.c b/source4/kdc/pac-glue.c index 411e752c04..5bd4cb10c7 100644 --- a/source4/kdc/pac-glue.c +++ b/source4/kdc/pac-glue.c @@ -231,28 +231,29 @@ static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data, krb5_error_code samba_kdc_check_client_access(void *priv, - krb5_context context, hdb_entry_ex *entry_ex, + krb5_context context, + krb5_kdc_configuration *config, + hdb_entry_ex *client_ex, const char *client_name, + hdb_entry_ex *server_ex, const char *server_name, KDC_REQ *req, krb5_data *e_data) { krb5_error_code ret; NTSTATUS nt_status; - TALLOC_CTX *tmp_ctx = talloc_new(entry_ex->ctx); - struct hdb_ldb_private *p = talloc_get_type(entry_ex->ctx, struct hdb_ldb_private); - char *name, *workstation = NULL; + TALLOC_CTX *tmp_ctx; + struct hdb_ldb_private *p; + char *workstation = NULL; HostAddresses *addresses = req->req_body.addresses; int i; + bool password_change; + + tmp_ctx = talloc_new(client_ex->ctx); + p = talloc_get_type(client_ex->ctx, struct hdb_ldb_private); if (!tmp_ctx) { return ENOMEM; } - ret = krb5_unparse_name(context, entry_ex->entry.principal, &name); - if (ret != 0) { - talloc_free(tmp_ctx); - return ret; - } - if (addresses) { for (i=0; i < addresses->len; i++) { if (addresses->val->addr_type == KRB5_ADDRESS_NETBIOS) { @@ -272,6 +273,8 @@ krb5_error_code samba_kdc_check_client_access(void *priv, } } + password_change = (server_ex && server_ex->entry.flags.change_pw); + /* we allow all kinds of trusts here */ nt_status = authsam_account_ok(tmp_ctx, p->samdb, @@ -279,30 +282,34 @@ krb5_error_code samba_kdc_check_client_access(void *priv, p->realm_dn, p->msg, workstation, - name, true); - free(name); - - if (NT_STATUS_IS_OK(nt_status)) - return 0; - - if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) - ret = KRB5KDC_ERR_KEY_EXPIRED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) - ret = KRB5KDC_ERR_KEY_EXPIRED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) - ret = KRB5KDC_ERR_CLIENT_REVOKED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) - ret = KRB5KDC_ERR_CLIENT_REVOKED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) - ret = KRB5KDC_ERR_CLIENT_REVOKED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) - ret = KRB5KDC_ERR_CLIENT_REVOKED; - else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) - ret = KRB5KDC_ERR_POLICY; - else - ret = KRB5KDC_ERR_POLICY; - - samba_kdc_build_edata_reply(tmp_ctx, e_data, nt_status); + client_name, true, password_change); + + if (NT_STATUS_IS_OK(nt_status)) { + /* Now do the standard Heimdal check */ + ret = kdc_check_flags(context, config, + client_ex, client_name, + server_ex, server_name, + req->msg_type == krb_as_req); + } else { + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) + ret = KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) + ret = KRB5KDC_ERR_KEY_EXPIRED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) + ret = KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) + ret = KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) + ret = KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) + ret = KRB5KDC_ERR_CLIENT_REVOKED; + else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) + ret = KRB5KDC_ERR_POLICY; + else + ret = KRB5KDC_ERR_POLICY; + + samba_kdc_build_edata_reply(tmp_ctx, e_data, nt_status); + } return ret; } |