[SCM] Samba Shared Repository - branch v3-5-test updated

Volker Lendecke vlendec at samba.org
Thu Nov 19 11:04:06 MST 2009


The branch, v3-5-test has been updated
       via  25605fb... s3: Avoid races to change the machine password in winbind
       via  a7f742c... s3: Protect against flooding the DC with pwchange requests
       via  e6eee6c... s3: Re-check the timeout in machine_password_change_handler()
       via  de8ff3e... s3: Add some debugs to the winbind machine pwchange machinery
       via  9bbec24... s3: Factor timeval_string out of current_timestring()
       via  f488e98... s3: Do not kill the whole smb session if a machine pwchange failed
      from  5caad32... s3:load_interfaces(): use function gfree_interfaces() that we have.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-5-test


- Log -----------------------------------------------------------------
commit 25605fbd2b35b97515526d7c7708f73daa448544
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 a7f742c754e9e658908d113a77241463d8e15d17
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 e6eee6c54ec39dc9ba55e397165be9e5f08b22f4
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 de8ff3e050405b2c384ef78c1dcb23db90d912a6
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 9bbec24c67949ed00b24e36b8a3a16bba8c5f5c6
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 f488e98136b09d1bd50421ec529ca7b51d53d199
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 ff0156d..2fa5998 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