summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/include/secrets.h1
-rw-r--r--source3/libads/kerberos_verify.c95
-rw-r--r--source3/passdb/machine_account_secrets.c81
4 files changed, 137 insertions, 41 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index cb6856734e..6ccefe1a39 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -4645,6 +4645,7 @@ bool secrets_delete_machine_password(const char *domain);
bool secrets_delete_machine_password_ex(const char *domain);
bool secrets_delete_domain_sid(const char *domain);
bool secrets_store_machine_password(const char *pass, const char *domain, enum netr_SchannelType sec_channel);
+char *secrets_fetch_prev_machine_password(const char *domain);
char *secrets_fetch_machine_password(const char *domain,
time_t *pass_last_set_time,
enum netr_SchannelType *channel);
diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index b51fd22bfa..624b1465bb 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -25,6 +25,7 @@
*/
#define SECRETS_MACHINE_ACCT_PASS "SECRETS/$MACHINE.ACC"
#define SECRETS_MACHINE_PASSWORD "SECRETS/MACHINE_PASSWORD"
+#define SECRETS_MACHINE_PASSWORD_PREV "SECRETS/MACHINE_PASSWORD.PREV"
#define SECRETS_MACHINE_LAST_CHANGE_TIME "SECRETS/MACHINE_LAST_CHANGE_TIME"
#define SECRETS_MACHINE_SEC_CHANNEL_TYPE "SECRETS/MACHINE_SEC_CHANNEL_TYPE"
#define SECRETS_MACHINE_TRUST_ACCOUNT_NAME "SECRETS/SECRETS_MACHINE_TRUST_ACCOUNT_NAME"
diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c
index 4d7bb8d20b..c07259394b 100644
--- a/source3/libads/kerberos_verify.c
+++ b/source3/libads/kerberos_verify.c
@@ -307,8 +307,10 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
{
krb5_error_code ret = 0;
bool auth_ok = False;
+ bool cont = true;
char *password_s = NULL;
- krb5_data password;
+ /* Let's make some room for 2 password (old and new)*/
+ krb5_data passwords[2];
krb5_enctype enctypes[] = {
#if defined(ENCTYPE_ARCFOUR_HMAC)
ENCTYPE_ARCFOUR_HMAC,
@@ -318,12 +320,13 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
ENCTYPE_NULL
};
krb5_data packet;
- int i;
+ int i, j;
*pp_tkt = NULL;
*keyblock = NULL;
*perr = 0;
+ ZERO_STRUCT(passwords);
if (!secrets_init()) {
DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n"));
@@ -338,8 +341,15 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
return False;
}
- password.data = password_s;
- password.length = strlen(password_s);
+ passwords[0].data = password_s;
+ passwords[0].length = strlen(password_s);
+
+ password_s = secrets_fetch_prev_machine_password(lp_workgroup());
+ if (password_s) {
+ DEBUG(10,("ads_secrets_verify_ticket: found previous password\n"));
+ passwords[1].data = password_s;
+ passwords[1].length = strlen(password_s);
+ }
/* CIFS doesn't use addresses in tickets. This would break NAT. JRA */
@@ -347,50 +357,61 @@ static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
packet.data = (char *)ticket->data;
/* We need to setup a auth context with each possible encoding type in turn. */
- for (i=0;enctypes[i];i++) {
- krb5_keyblock *key = NULL;
+ for (j=0; j<2 && passwords[j].length; j++) {
- if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
- ret = ENOMEM;
- goto out;
- }
-
- if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i], false)) {
- SAFE_FREE(key);
- continue;
- }
+ for (i=0;enctypes[i];i++) {
+ krb5_keyblock *key = NULL;
- krb5_auth_con_setuseruserkey(context, auth_context, key);
+ if (!(key = SMB_MALLOC_P(krb5_keyblock))) {
+ ret = ENOMEM;
+ goto out;
+ }
- if (!(ret = krb5_rd_req(context, &auth_context, &packet,
- NULL,
- NULL, NULL, pp_tkt))) {
- DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
- (unsigned int)enctypes[i] ));
- auth_ok = True;
- krb5_copy_keyblock(context, key, keyblock);
- krb5_free_keyblock(context, key);
- break;
- }
+ if (create_kerberos_key_from_string(context, host_princ, &passwords[j], key, enctypes[i], false)) {
+ SAFE_FREE(key);
+ continue;
+ }
+
+ krb5_auth_con_setuseruserkey(context, auth_context, key);
+
+ if (!(ret = krb5_rd_req(context, &auth_context, &packet,
+ NULL,
+ NULL, NULL, pp_tkt))) {
+ DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n",
+ (unsigned int)enctypes[i] ));
+ auth_ok = True;
+ cont = false;
+ krb5_copy_keyblock(context, key, keyblock);
+ krb5_free_keyblock(context, key);
+ break;
+ }
- DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
- ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
- (unsigned int)enctypes[i], error_message(ret)));
+ DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10,
+ ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n",
+ (unsigned int)enctypes[i], error_message(ret)));
+
+ /* successfully decrypted but ticket is just not valid at the moment */
+ if (ret == KRB5KRB_AP_ERR_TKT_NYV ||
+ ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
+ ret == KRB5KRB_AP_ERR_SKEW) {
+ krb5_free_keyblock(context, key);
+ cont = false;
+ break;
+ }
- /* successfully decrypted but ticket is just not valid at the moment */
- if (ret == KRB5KRB_AP_ERR_TKT_NYV ||
- ret == KRB5KRB_AP_ERR_TKT_EXPIRED ||
- ret == KRB5KRB_AP_ERR_SKEW) {
krb5_free_keyblock(context, key);
+ }
+ if (!cont) {
+ /* If we found a valid pass then no need to try
+ * the next one or we have invalid ticket so no need
+ * to try next password*/
break;
}
-
- krb5_free_keyblock(context, key);
-
}
out:
- SAFE_FREE(password_s);
+ SAFE_FREE(passwords[0].data);
+ SAFE_FREE(passwords[1].data);
*perr = ret;
return auth_ok;
}
diff --git a/source3/passdb/machine_account_secrets.c b/source3/passdb/machine_account_secrets.c
index 4a1c3faa87..db99d010ec 100644
--- a/source3/passdb/machine_account_secrets.c
+++ b/source3/passdb/machine_account_secrets.c
@@ -161,6 +161,23 @@ static const char *machine_last_change_time_keystr(const char *domain)
/**
+ * Form a key for fetching the machine previous trust account password
+ *
+ * @param domain domain name
+ *
+ * @return keystring
+ **/
+static const char *machine_prev_password_keystr(const char *domain)
+{
+ char *keystr;
+
+ keystr = talloc_asprintf_strupper_m(talloc_tos(), "%s/%s",
+ SECRETS_MACHINE_PASSWORD_PREV, domain);
+ SMB_ASSERT(keystr != NULL);
+ return keystr;
+}
+
+/**
* Form a key for fetching the machine trust account password
*
* @param domain domain name
@@ -300,21 +317,42 @@ bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16],
}
/************************************************************************
- Routine to delete the plaintext machine account password
+ Routine to delete the old plaintext machine account password if any
+************************************************************************/
+
+static bool secrets_delete_prev_machine_password(const char *domain)
+{
+ char *oldpass = (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
+ if (oldpass == NULL) {
+ return true;
+ }
+ SAFE_FREE(oldpass);
+ return secrets_delete(machine_prev_password_keystr(domain));
+}
+
+/************************************************************************
+ Routine to delete the plaintext machine account password and old
+ password if any
************************************************************************/
bool secrets_delete_machine_password(const char *domain)
{
+ if (!secrets_delete_prev_machine_password(domain)) {
+ return false;
+ }
return secrets_delete(machine_password_keystr(domain));
}
/************************************************************************
- Routine to delete the plaintext machine account password, sec channel type and
- last change time from secrets database
+ Routine to delete the plaintext machine account password, old password,
+ sec channel type and last change time from secrets database
************************************************************************/
bool secrets_delete_machine_password_ex(const char *domain)
{
+ if (!secrets_delete_prev_machine_password(domain)) {
+ return false;
+ }
if (!secrets_delete(machine_password_keystr(domain))) {
return false;
}
@@ -334,8 +372,28 @@ bool secrets_delete_domain_sid(const char *domain)
}
/************************************************************************
+ Routine to store the previous machine password (by storing the current password
+ as the old)
+************************************************************************/
+
+static bool secrets_store_prev_machine_password(const char *domain)
+{
+ char *oldpass;
+ bool ret;
+
+ oldpass = (char *)secrets_fetch(machine_password_keystr(domain), NULL);
+ if (oldpass == NULL) {
+ return true;
+ }
+ ret = secrets_store(machine_prev_password_keystr(domain), oldpass, strlen(oldpass)+1);
+ SAFE_FREE(oldpass);
+ return ret;
+}
+
+/************************************************************************
Routine to set the plaintext machine account password for a realm
-the password is assumed to be a null terminated ascii string
+ the password is assumed to be a null terminated ascii string.
+ Before storing
************************************************************************/
bool secrets_store_machine_password(const char *pass, const char *domain,
@@ -345,6 +403,10 @@ bool secrets_store_machine_password(const char *pass, const char *domain,
uint32 last_change_time;
uint32 sec_channel_type;
+ if (!secrets_store_prev_machine_password(domain)) {
+ return false;
+ }
+
ret = secrets_store(machine_password_keystr(domain), pass, strlen(pass)+1);
if (!ret)
return ret;
@@ -358,6 +420,17 @@ bool secrets_store_machine_password(const char *pass, const char *domain,
return ret;
}
+
+/************************************************************************
+ Routine to fetch the previous plaintext machine account password for a realm
+ the password is assumed to be a null terminated ascii string.
+************************************************************************/
+
+char *secrets_fetch_prev_machine_password(const char *domain)
+{
+ return (char *)secrets_fetch(machine_prev_password_keystr(domain), NULL);
+}
+
/************************************************************************
Routine to fetch the plaintext machine account password for a realm
the password is assumed to be a null terminated ascii string.