[SCM] Samba Shared Repository - branch master updated

Volker Lendecke vlendec at samba.org
Thu Nov 19 11:03:46 MST 2009


The branch, master has been updated
       via  c4c984d... s3: Avoid races to change the machine password in winbind
       via  882350b... s3: Protect against flooding the DC with pwchange requests
       via  4d0ebc9... s3: Re-check the timeout in machine_password_change_handler()
       via  d0ef9fb... s3: Add some debugs to the winbind machine pwchange machinery
       via  d3d37ac... s3: Factor timeval_string out of current_timestring()
       via  d4312e7... s3: Do not kill the whole smb session if a machine pwchange failed
      from  5575353... s3:pdb_ldap: fix a comment typo

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit c4c984d97d45964e91625f69d7216cc68444ba3f
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 17:22:27 2009 +0100

    s3: Avoid races to change the machine password in winbind
    
    The machine password handler has code to deal with every node in the cluster
    trying to change the machine password at the same time. However, it is not very
    nice to the DC if everyone tries this simultaneously. This adds a random 0-255
    second offset to our timed event. When this fires a bit later than strictly
    calculated, someone else might have stepped in and have already changed it. The
    timed event handler will handle this gracefully, it won't even try to do it
    again.

commit 882350b0abe87ca7b3542996acfabc6d4bff5509
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 17:20:47 2009 +0100

    s3: Protect against flooding the DC with pwchange requests
    
    When there is a temporary problem changing passwords we flooded the DC with
    pwchange requests. This gives the DC a 60-second break to recover.

commit 4d0ebc90dce05a66736c070d97d01c4167265a9a
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 17:14:40 2009 +0100

    s3: Re-check the timeout in machine_password_change_handler()
    
    Someone else might have come in between and changed the password since we
    created that timed request

commit d0ef9fbce63472411a20f26c0804322a07b28919
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 17:11:32 2009 +0100

    s3: Add some debugs to the winbind machine pwchange machinery

commit d3d37acb998672dc9d2f36927151cce8393b6d44
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 11:50:13 2009 +0100

    s3: Factor timeval_string out of current_timestring()

commit d4312e776b70e63554dd31ec7da242dfcc62c137
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Nov 19 17:56:46 2009 +0100

    s3: Do not kill the whole smb session if a machine pwchange failed

-----------------------------------------------------------------------

Summary of changes:
 source3/include/proto.h          |    1 +
 source3/lib/time.c               |   25 ++++++------
 source3/winbindd/winbindd_dual.c |   78 +++++++++++++++++++++++++++++++-------
 3 files changed, 78 insertions(+), 26 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 9450140..cad8651 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1025,6 +1025,7 @@ bool nt_time_is_zero(const NTTIME *nt);
 time_t generalized_to_unix_time(const char *str);
 int get_server_zone_offset(void);
 int set_server_zone_offset(time_t t);
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires);
 char *current_timestring(TALLOC_CTX *ctx, bool hires);
 void srv_put_dos_date(char *buf,int offset,time_t unixdate);
 void srv_put_dos_date2(char *buf,int offset, time_t unixdate);
diff --git a/source3/lib/time.c b/source3/lib/time.c
index 1d2fae3..a418c42 100644
--- a/source3/lib/time.c
+++ b/source3/lib/time.c
@@ -188,27 +188,21 @@ int set_server_zone_offset(time_t t)
  Return the date and time as a string
 ****************************************************************************/
 
-char *current_timestring(TALLOC_CTX *ctx, bool hires)
+char *timeval_string(TALLOC_CTX *ctx, const struct timeval *tp, bool hires)
 {
 	fstring TimeBuf;
-	struct timeval tp;
 	time_t t;
 	struct tm *tm;
 
-	if (hires) {
-		GetTimeOfDay(&tp);
-		t = (time_t)tp.tv_sec;
-	} else {
-		t = time(NULL);
-	}
+	t = (time_t)tp->tv_sec;
 	tm = localtime(&t);
 	if (!tm) {
 		if (hires) {
 			slprintf(TimeBuf,
 				 sizeof(TimeBuf)-1,
 				 "%ld.%06ld seconds since the Epoch",
-				 (long)tp.tv_sec, 
-				 (long)tp.tv_usec);
+				 (long)tp->tv_sec,
+				 (long)tp->tv_usec);
 		} else {
 			slprintf(TimeBuf,
 				 sizeof(TimeBuf)-1,
@@ -222,7 +216,7 @@ char *current_timestring(TALLOC_CTX *ctx, bool hires)
 			slprintf(TimeBuf+strlen(TimeBuf),
 				 sizeof(TimeBuf)-1 - strlen(TimeBuf), 
 				 ".%06ld", 
-				 (long)tp.tv_usec);
+				 (long)tp->tv_usec);
 		} else {
 			strftime(TimeBuf,sizeof(TimeBuf)-1,"%Y/%m/%d %H:%M:%S",tm);
 		}
@@ -233,7 +227,7 @@ char *current_timestring(TALLOC_CTX *ctx, bool hires)
 				 sizeof(TimeBuf)-1, 
 				 "%s.%06ld", 
 				 asct ? asct : "unknown", 
-				 (long)tp.tv_usec);
+				 (long)tp->tv_usec);
 		} else {
 			const char *asct = asctime(tm);
 			fstrcpy(TimeBuf, asct ? asct : "unknown");
@@ -243,6 +237,13 @@ char *current_timestring(TALLOC_CTX *ctx, bool hires)
 	return talloc_strdup(ctx, TimeBuf);
 }
 
+char *current_timestring(TALLOC_CTX *ctx, bool hires)
+{
+	struct timeval tv;
+
+	GetTimeOfDay(&tv);
+	return timeval_string(ctx, &tv, hires);
+}
 
 /*******************************************************************
  Put a dos date into a buffer (time/date format).
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index a832451..376d7c7 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -1019,6 +1019,7 @@ static bool calculate_next_machine_pwd_change(const char *domain,
 	time_t pass_last_set_time;
 	time_t timeout;
 	time_t next_change;
+	struct timeval tv;
 	char *pw;
 
 	pw = secrets_fetch_machine_password(domain,
@@ -1038,11 +1039,36 @@ static bool calculate_next_machine_pwd_change(const char *domain,
 		return false;
 	}
 
+	tv.tv_sec = pass_last_set_time;
+	DEBUG(10, ("password last changed %s\n",
+		   timeval_string(talloc_tos(), &tv, false)));
+	tv.tv_sec += timeout;
+	DEBUGADD(10, ("password valid until %s\n",
+		      timeval_string(talloc_tos(), &tv, false)));
+
 	if (time(NULL) < (pass_last_set_time + timeout)) {
 		next_change = pass_last_set_time + timeout;
 		DEBUG(10,("machine password still valid until: %s\n",
 			http_timestring(talloc_tos(), next_change)));
 		*t = timeval_set(next_change, 0);
+
+		if (lp_clustering()) {
+			uint8_t randbuf;
+			/*
+			 * When having a cluster, we have several
+			 * winbinds racing for the password change. In
+			 * the machine_password_change_handler()
+			 * function we check if someone else was
+			 * faster when the event triggers. We add a
+			 * 255-second random delay here, so that we
+			 * don't run to change the password at the
+			 * exact same moment.
+			 */
+			generate_random_buffer(&randbuf, sizeof(randbuf));
+			DEBUG(10, ("adding %d seconds randomness\n",
+				   (int)randbuf));
+			t->tv_sec += randbuf;
+		}
 		return true;
 	}
 
@@ -1071,9 +1097,18 @@ static void machine_password_change_handler(struct event_context *ctx,
 
 	if (!calculate_next_machine_pwd_change(child->domain->name,
 					       &next_change)) {
+		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
 		return;
 	}
 
+	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
+		   timeval_string(talloc_tos(), &next_change, false)));
+
+	if (!timeval_expired(&next_change)) {
+		DEBUG(10, ("Someone else has already changed the pw\n"));
+		goto done;
+	}
+
 	if (!winbindd_can_contact_domain(child->domain)) {
 		DEBUG(10,("machine_password_change_handler: Removing myself since I "
 			  "do not have an incoming trust to domain %s\n",
@@ -1096,23 +1131,38 @@ static void machine_password_change_handler(struct event_context *ctx,
 						   child->domain->name);
 	TALLOC_FREE(frame);
 
+	DEBUG(10, ("machine_password_change_handler: "
+		   "trust_pw_find_change_and_store_it returned %s\n",
+		   nt_errstr(result)));
+
+	if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
+		DEBUG(3,("machine_password_change_handler: password set returned "
+			 "ACCESS_DENIED.  Maybe the trust account "
+			 "password was changed and we didn't know it. "
+			 "Killing connections to domain %s\n",
+			 child->domain->name));
+		TALLOC_FREE(child->domain->conn.netlogon_pipe);
+	}
+
+	if (!calculate_next_machine_pwd_change(child->domain->name,
+					       &next_change)) {
+		DEBUG(10, ("calculate_next_machine_pwd_change failed\n"));
+		return;
+	}
+
+	DEBUG(10, ("calculate_next_machine_pwd_change returned %s\n",
+		   timeval_string(talloc_tos(), &next_change, false)));
+
 	if (!NT_STATUS_IS_OK(result)) {
-		DEBUG(10,("machine_password_change_handler: "
-			"failed to change machine password: %s\n",
-			 nt_errstr(result)));
-		if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) ) {
-			DEBUG(3,("machine_password_change_handler: password set returned "
-				"ACCESS_DENIED.  Maybe the trust account "
-				"password was changed and we didn't know it. "
-				"Killing connections to domain %s\n",
-				child->domain->name));
-			invalidate_cm_connection(&child->domain->conn);
-		}
-	} else {
-		DEBUG(10,("machine_password_change_handler: "
-			"successfully changed machine password\n"));
+		struct timeval tmp;
+		/*
+		 * In case of failure, give the DC a minute to recover
+		 */
+		tmp = timeval_current_ofs(60, 0);
+		next_change = timeval_max(&next_change, &tmp);
 	}
 
+done:
 	child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL,
 							      next_change,
 							      machine_password_change_handler,


-- 
Samba Shared Repository


More information about the samba-cvs mailing list