The Samba-Bugzilla – Attachment 4289 Details for
Bug 6471
Unable to change a password that has expired with kpasswd
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to fix the problem properly
password-change-when-expired.patch (text/plain), 15.51 KB, created by
Andrew Bartlett
on 2009-06-15 09:02:59 UTC
(
hide
)
Description:
Patch to fix the problem properly
Filename:
MIME Type:
Creator:
Andrew Bartlett
Created:
2009-06-15 09:02:59 UTC
Size:
15.51 KB
patch
obsolete
>diff --git a/source4/auth/auth.h b/source4/auth/auth.h >index f6d7393..6bad017 100644 >--- a/source4/auth/auth.h >+++ b/source4/auth/auth.h >@@ -232,7 +232,8 @@ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, > struct ldb_message *msg, > const char *logon_workstation, > const char *name_for_logs, >- bool allow_domain_trust); >+ bool allow_domain_trust, >+ bool password_change); > struct auth_session_info *system_session(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx); > NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, > const char *netbios_name, >diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c >index b04abfc..09bdec5 100644 >--- a/source4/auth/gensec/gensec_krb5.c >+++ b/source4/auth/gensec/gensec_krb5.c >@@ -609,7 +609,9 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security > ret, mem_ctx))); > if (gensec_security->auth_context && > !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) { >- DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s")); >+ DEBUG(1, ("Unable to find PAC for %s, resorting to local user lookup: %s", >+ principal_string, smb_get_krb5_error_message(context, >+ ret, mem_ctx))); > nt_status = gensec_security->auth_context->get_server_info_principal(mem_ctx, > gensec_security->auth_context, > principal_string, >diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c >index 0bb79e2..253ddf2 100644 >--- a/source4/auth/ntlm/auth_sam.c >+++ b/source4/auth/ntlm/auth_sam.c >@@ -175,7 +175,7 @@ static NTSTATUS authsam_authenticate(struct auth_context *auth_context, > msg, > user_info->workstation_name, > user_info->mapped.account_name, >- false); >+ false, false); > > return nt_status; > } >diff --git a/source4/auth/sam.c b/source4/auth/sam.c >index 68eaacf..acbd50c 100644 >--- a/source4/auth/sam.c >+++ b/source4/auth/sam.c >@@ -147,7 +147,8 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, > struct ldb_message *msg, > const char *logon_workstation, > const char *name_for_logs, >- bool allow_domain_trust) >+ bool allow_domain_trust, >+ bool password_change) > { > uint16_t acct_flags; > const char *workstation_list; >@@ -189,15 +190,15 @@ _PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx, > return NT_STATUS_ACCOUNT_EXPIRED; > } > >- /* check for immediate expiry "must change at next logon" */ >- if (must_change_time == 0) { >+ /* check for immediate expiry "must change at next logon" (but not if this is a password change request) */ >+ if ((must_change_time == 0) && !password_change) { > DEBUG(1,("sam_account_ok: Account for user '%s' password must change!.\n", > name_for_logs)); > return NT_STATUS_PASSWORD_MUST_CHANGE; > } > >- /* check for expired password */ >- if (must_change_time < now) { >+ /* check for expired password (but not if this is a password change request) */ >+ if ((must_change_time < now) && !password_change) { > DEBUG(1,("sam_account_ok: Account for user '%s' password expired!.\n", > name_for_logs)); > DEBUG(1,("sam_account_ok: Password expired at '%s' unix time.\n", >diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h >index 2240336..b9a8288 100644 >--- a/source4/heimdal/kdc/headers.h >+++ b/source4/heimdal/kdc/headers.h >@@ -104,6 +104,7 @@ > #ifndef NO_NTLM > #include <heimntlm.h> > #endif >+#include <kdc.h> > #include <windc_plugin.h> > > #undef ALLOC >diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h >index 9b291ac..daf1558 100644 >--- a/source4/heimdal/kdc/kdc_locl.h >+++ b/source4/heimdal/kdc/kdc_locl.h >@@ -39,7 +39,6 @@ > #define __KDC_LOCL_H__ > > #include "headers.h" >-#include "kdc.h" > > typedef struct pk_client_params pk_client_params; > struct DigestREQ; >diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c >index 941a2e0..ac495b1 100644 >--- a/source4/heimdal/kdc/kerberos5.c >+++ b/source4/heimdal/kdc/kerberos5.c >@@ -668,11 +668,11 @@ log_as_req(krb5_context context, > */ > > krb5_error_code >-_kdc_check_flags(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, >- krb5_boolean is_as_req) >+kdc_check_flags(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, >+ krb5_boolean is_as_req) > { > if(client_ex != NULL) { > hdb_entry *client = &client_ex->entry; >@@ -921,7 +921,6 @@ _kdc_as_rep(krb5_context context, > "AS-REQ malformed server name from %s", from); > goto out; > } >- > if(b->cname == NULL){ > ret = KRB5KRB_ERR_GENERIC; > e_text = "No client in request"; >@@ -1345,14 +1344,9 @@ _kdc_as_rep(krb5_context context, > * with in a preauth mech. > */ > >- ret = _kdc_check_flags(context, config, >- client, client_name, >- server, server_name, >- TRUE); >- if(ret) >- goto out; >- >- ret = _kdc_windc_client_access(context, client, req, &e_data); >+ ret = _kdc_check_access(context, config, client, client_name, >+ server, server_name, >+ req, &e_data); > if(ret) > goto out; > >diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c >index 3abdb18..59104da 100644 >--- a/source4/heimdal/kdc/krb5tgs.c >+++ b/source4/heimdal/kdc/krb5tgs.c >@@ -1860,10 +1860,10 @@ server_lookup: > * Check flags > */ > >- ret = _kdc_check_flags(context, config, >- client, cpn, >- server, spn, >- FALSE); >+ ret = kdc_check_flags(context, config, >+ client, cpn, >+ server, spn, >+ FALSE); > if(ret) > goto out; > >diff --git a/source4/heimdal/kdc/windc.c b/source4/heimdal/kdc/windc.c >index fe3cd99..9d7fa52 100644 >--- a/source4/heimdal/kdc/windc.c >+++ b/source4/heimdal/kdc/windc.c >@@ -99,12 +99,22 @@ _kdc_pac_verify(krb5_context context, > } > > krb5_error_code >-_kdc_windc_client_access(krb5_context context, >- struct hdb_entry_ex *client, >- KDC_REQ *req, >- krb5_data *e_data) >+_kdc_check_access(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) > { > if (windcft == NULL) >- return 0; >- return (windcft->client_access)(windcctx, context, client, req, e_data); >+ return kdc_check_flags(context, config, >+ client_ex, client_name, >+ server_ex, server_name, >+ req->msg_type == krb_as_req); >+ >+ return (windcft->client_access)(windcctx, >+ context, config, >+ client_ex, client_name, >+ server_ex, server_name, >+ req, e_data); > } >diff --git a/source4/heimdal/kdc/windc_plugin.h b/source4/heimdal/kdc/windc_plugin.h >index 3401669..c7efb7b 100644 >--- a/source4/heimdal/kdc/windc_plugin.h >+++ b/source4/heimdal/kdc/windc_plugin.h >@@ -64,10 +64,14 @@ typedef krb5_error_code > > typedef krb5_error_code > (*krb5plugin_windc_client_access)( >- void *, krb5_context, struct hdb_entry_ex *, KDC_REQ *, krb5_data *); >+ void *, krb5_context, >+ krb5_kdc_configuration *config, >+ hdb_entry_ex *, const char *, >+ hdb_entry_ex *, const char *, >+ KDC_REQ *, krb5_data *); > > >-#define KRB5_WINDC_PLUGING_MINOR 3 >+#define KRB5_WINDC_PLUGING_MINOR 4 > > typedef struct krb5plugin_windc_ftable { > int minor_version; >diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c >index c0fa513..eda7867 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 a281e1d..d37a32e 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 411e752..5bd4cb1 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; > } >diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py >index 454a9d1..8ca4f65 100644 >--- a/source4/scripting/python/samba/samdb.py >+++ b/source4/scripting/python/samba/samdb.py >@@ -152,7 +152,7 @@ userAccountControl: %u > raise > self.transaction_commit() > >- def setpassword(self, filter, password): >+ def setpassword(self, filter, password, must_change_at_next_login=False): > """Set a password on a user record > > :param filter: LDAP filter to find the user (eg samccountname=name) >@@ -184,6 +184,15 @@ userPassword:: %s > > self.modify_ldif(setpw) > >+ if must_change_at_next_login: >+ mod = """ >+dn: %s >+changetype: modify >+replace: pwdLastSet >+pwdLastSet: 0 >+""" % (user_dn) >+ self.modify_ldif(mod) >+ > # modify the userAccountControl to remove the disabled bit > self.enable_account(user_dn) > except: >@@ -212,7 +221,7 @@ userPassword:: %s > glue.dsdb_set_ntds_invocation_id(self, invocation_id) > > def setexpiry(self, user, expiry_seconds, noexpiry): >- """Set the password expiry for a user >+ """Set the account expiry for a user > > :param expiry_seconds: expiry time from now in seconds > :param noexpiry: if set, then don't expire password >@@ -246,3 +255,4 @@ accountExpires: %u > self.transaction_cancel() > raise > self.transaction_commit(); >+ >diff --git a/source4/setup/setpassword b/source4/setup/setpassword >index 90a217f..d44f143 100755 >--- a/source4/setup/setpassword >+++ b/source4/setup/setpassword >@@ -41,6 +41,7 @@ credopts = options.CredentialsOptions(parser) > parser.add_option_group(credopts) > parser.add_option("--filter", help="LDAP Filter to set password on", type=str) > parser.add_option("--newpassword", help="Set password", type=str) >+parser.add_option("--must-change-at-next-login", help="Force password to be changed on next login", action="store_true") > > opts, args = parser.parse_args() > >@@ -74,4 +75,5 @@ creds = credopts.get_credentials(lp) > > samdb = SamDB(url=lp.get("sam database"), session_info=system_session(), > credentials=creds, lp=lp) >-samdb.setpassword(filter, password) >+samdb.setpassword(filter, password, must_change_at_next_login=opts.must_change_at_next_login) >+ >diff --git a/source4/setup/tests/blackbox_setpassword.sh b/source4/setup/tests/blackbox_setpassword.sh >index 89f1aa5..70061f6 100755 >--- a/source4/setup/tests/blackbox_setpassword.sh >+++ b/source4/setup/tests/blackbox_setpassword.sh >@@ -18,4 +18,6 @@ testit "newuser" $PYTHON ./setup/newuser --configfile=$PREFIX/simple-dc/etc/smb. > > testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass > >+testit "setpassword" $PYTHON ./setup/setpassword --configfile=$PREFIX/simple-dc/etc/smb.conf testuser --newpassword=testpass --must-change-at-next-login >+ > exit $failed
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 6471
:
4283
| 4289