]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3: Sync machine account password in secrets_{prepare,finish}_password_change
authorPavel Filipenský <pfilipensky@samba.org>
Thu, 21 Dec 2023 12:57:38 +0000 (13:57 +0100)
committerPavel Filipensky <pfilipensky@samba.org>
Fri, 26 Jul 2024 17:12:36 +0000 (17:12 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=6750

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/include/secrets.h
source3/libads/trusts_util.c
source3/libads/util.c
source3/passdb/machine_account_secrets.c
source3/utils/net.c

index 47cf40432f0c34d2052726eaa4bc9fde21a80306..a454c8bb8ffe8d6228cccf73db9d7d5f3931445e 100644 (file)
@@ -129,7 +129,8 @@ NTSTATUS secrets_prepare_password_change(const char *domain, const char *dcname,
                                         const char *cleartext_unix,
                                         TALLOC_CTX *mem_ctx,
                                         struct secrets_domain_info1 **pinfo,
-                                        struct secrets_domain_info1_change **pprev);
+                                        struct secrets_domain_info1_change **pprev,
+                                        NTSTATUS (*sync_pw2keytabs_fn)(void));
 NTSTATUS secrets_failed_password_change(const char *change_server,
                                        NTSTATUS local_status,
                                        NTSTATUS remote_status,
@@ -140,7 +141,8 @@ NTSTATUS secrets_defer_password_change(const char *change_server,
                                       const struct secrets_domain_info1 *info);
 NTSTATUS secrets_finish_password_change(const char *change_server,
                                        NTTIME change_time,
-                                       const struct secrets_domain_info1 *info);
+                                       const struct secrets_domain_info1 *info,
+                                       NTSTATUS (*sync_pw2keytabs_fn)(void));
 bool secrets_delete_machine_password_ex(const char *domain, const char *realm);
 bool secrets_delete_domain_sid(const char *domain);
 char *secrets_fetch_prev_machine_password(const char *domain);
index c40eb7918025b503a9fd98224b4a7c5cd82d004a..6f805f2365e4da8bb5b5984e1aa3e72cf01071a1 100644 (file)
@@ -26,6 +26,7 @@
 #include "../librpc/gen_ndr/ndr_netlogon.h"
 #include "librpc/gen_ndr/secrets.h"
 #include "secrets.h"
+#include "ads.h"
 #include "passdb.h"
 #include "libsmb/libsmb.h"
 #include "source3/include/messages.h"
@@ -317,9 +318,17 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 
        case SEC_CHAN_WKSTA:
        case SEC_CHAN_BDC:
-               status = secrets_prepare_password_change(domain, dcname,
+               status = secrets_prepare_password_change(domain,
+                                                        dcname,
                                                         new_trust_pw_str,
-                                                        frame, &info, &prev);
+                                                        frame,
+                                                        &info,
+                                                        &prev,
+#ifdef HAVE_ADS
+                                                        sync_pw2keytabs);
+#else
+                                                        NULL);
+#endif
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
                                  domain));
@@ -415,9 +424,15 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
                         current_timestring(talloc_tos(), false),
                         __func__, domain, context_name));
 
-               status = secrets_finish_password_change(prev->password->change_server,
-                                                       prev->password->change_time,
-                                                       info);
+               status = secrets_finish_password_change(
+                       prev->password->change_server,
+                       prev->password->change_time,
+                       info,
+#ifdef HAVE_ADS
+                       sync_pw2keytabs);
+#else
+                       NULL);
+#endif
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("secrets_prepare_password_change() failed for domain %s!\n",
                                  domain));
@@ -559,9 +574,14 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
        case SEC_CHAN_WKSTA:
        case SEC_CHAN_BDC:
                status = secrets_finish_password_change(
-                                       info->next_change->change_server,
-                                       info->next_change->change_time,
-                                       info);
+                       info->next_change->change_server,
+                       info->next_change->change_time,
+                       info,
+#ifdef HAVE_ADS
+                       sync_pw2keytabs);
+#else
+                       NULL);
+#endif
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("secrets_finish_password_change() failed for domain %s!\n",
                                  domain));
index 0938db5ea641bf48f278996a9a93453287b17a4b..243dd09f3d05ad5ddc282bcd820f0fb9bb0df0c4 100644 (file)
@@ -56,7 +56,13 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
                                                 ads->auth.kdc_server,
                                                 new_password,
                                                 talloc_tos(),
-                                                &info, &prev);
+                                                &info,
+                                                &prev,
+#ifdef HAVE_ADS
+                                                sync_pw2keytabs);
+#else
+                                                NULL);
+#endif
        if (!NT_STATUS_IS_OK(status)) {
                return ADS_ERROR_NT(status);
        }
@@ -128,7 +134,14 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip
                return ret;
        }
 
-       status = secrets_finish_password_change(ads->auth.kdc_server, now, info);
+       status = secrets_finish_password_change(ads->auth.kdc_server,
+                                               now,
+                                               info,
+#ifdef HAVE_ADS
+                                               sync_pw2keytabs);
+#else
+                                               NULL);
+#endif
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1,("Failed to save machine password\n"));
                return ADS_ERROR_NT(status);
index c97b35e7e5239f7dc38ab6e859d4bf50a82a5388..215713490042c2eb1d436be0ec8456b51379d802 100644 (file)
@@ -1673,7 +1673,8 @@ NTSTATUS secrets_prepare_password_change(const char *domain, const char *dcname,
                                         const char *cleartext_unix,
                                         TALLOC_CTX *mem_ctx,
                                         struct secrets_domain_info1 **pinfo,
-                                        struct secrets_domain_info1_change **pprev)
+                                        struct secrets_domain_info1_change **pprev,
+                                        NTSTATUS (*sync_pw2keytabs_fn)(void))
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct db_context *db = NULL;
@@ -1768,6 +1769,16 @@ NTSTATUS secrets_prepare_password_change(const char *domain, const char *dcname,
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
+       if (prev == NULL && sync_pw2keytabs_fn != NULL) {
+               status = sync_pw2keytabs_fn();
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_ERR("Sync of machine password failed.\n");
+                       dbwrap_transaction_cancel(db);
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+       }
+
        *pinfo = talloc_move(mem_ctx, &info);
        if (prev != NULL) {
                *pprev = talloc_move(mem_ctx, &prev);
@@ -2011,7 +2022,8 @@ NTSTATUS secrets_defer_password_change(const char *change_server,
 
 NTSTATUS secrets_finish_password_change(const char *change_server,
                                        NTTIME change_time,
-                                       const struct secrets_domain_info1 *cookie)
+                                       const struct secrets_domain_info1 *cookie,
+                                       NTSTATUS (*sync_pw2keytabs_fn)(void))
 {
        const char *domain = cookie->domain_info.name.string;
        TALLOC_CTX *frame = talloc_stackframe();
@@ -2067,6 +2079,20 @@ NTSTATUS secrets_finish_password_change(const char *change_server,
                return status;
        }
 
+       /*
+        * For the clustered samba, it is important to have following order:
+        * 1. dbwrap_transaction_commit()
+        * 2. sync_pw2keytabs()
+        * Only this order ensures a correct behavior of
+        * the 'sync machine password script' that does:
+        * 'onnode all net ads keytab create'
+        *
+        * If we would call sync_pw2keytabs() before committing the changes to
+        * the secrets.tdb, it will not be updated on other nodes, so triggering
+        * 'net ads keytab create' will not see the new password yet.
+        *
+        * This applies also to secrets_prepare_password_change().
+        */
        ret = dbwrap_transaction_commit(db);
        if (ret != 0) {
                DBG_ERR("dbwrap_transaction_commit() failed for %s\n",
@@ -2075,6 +2101,15 @@ NTSTATUS secrets_finish_password_change(const char *change_server,
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
+       if (sync_pw2keytabs_fn != NULL) {
+               status = sync_pw2keytabs_fn();
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_ERR("Sync of machine password failed.\n");
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+       }
+
        TALLOC_FREE(frame);
        return NT_STATUS_OK;
 }
index 9c070372600c09459ec700aeab76408f7c7eb386..7b40d2bee95a6f2500a4615812f125a4a67f9699 100644 (file)
@@ -224,7 +224,13 @@ static int net_changesecretpw(struct net_context *c, int argc,
                                                         "localhost",
                                                         trust_pw,
                                                         talloc_tos(),
-                                                        &info, &prev);
+                                                        &info,
+                                                        &prev,
+#ifdef HAVE_ADS
+                                                        sync_pw2keytabs);
+#else
+                                                        NULL);
+#endif
                if (!NT_STATUS_IS_OK(status)) {
                        d_fprintf(stderr,
                                _("Unable to write the machine account password in the secrets database"));
@@ -243,7 +249,14 @@ static int net_changesecretpw(struct net_context *c, int argc,
                        }
                        return 1;
                }
-               status = secrets_finish_password_change("localhost", now, info);
+               status = secrets_finish_password_change("localhost",
+                                                       now,
+                                                       info,
+#ifdef HAVE_ADS
+                                                       sync_pw2keytabs);
+#else
+                                                       NULL);
+#endif
                if (!NT_STATUS_IS_OK(status)) {
                        d_fprintf(stderr,
                                _("Unable to write the machine account password in the secrets database"));