svn commit: samba r19957 - in branches/SAMBA_3_0/source: lib/replace/system nsswitch

jra at samba.org jra at samba.org
Wed Nov 29 23:20:24 GMT 2006


Author: jra
Date: 2006-11-29 23:20:22 +0000 (Wed, 29 Nov 2006)
New Revision: 19957

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=19957

Log:
Initial framework to make winbindd robust
against tdb corruption. Needs fleshing out
(and I forgot one record type) and needs helpful
suggestion from Volker to validate freelist,
but should give an idea of how this will look.
Jeremy.

Modified:
   branches/SAMBA_3_0/source/lib/replace/system/wait.h
   branches/SAMBA_3_0/source/nsswitch/wbinfo.c
   branches/SAMBA_3_0/source/nsswitch/winbindd.c
   branches/SAMBA_3_0/source/nsswitch/winbindd_cache.c


Changeset:
Modified: branches/SAMBA_3_0/source/lib/replace/system/wait.h
===================================================================
--- branches/SAMBA_3_0/source/lib/replace/system/wait.h	2006-11-29 22:10:15 UTC (rev 19956)
+++ branches/SAMBA_3_0/source/lib/replace/system/wait.h	2006-11-29 23:20:22 UTC (rev 19957)
@@ -36,4 +36,6 @@
 #define SIGNAL_CAST (RETSIGTYPE (*)(int))
 #endif
 
+#include <setjmp.h>
+
 #endif

Modified: branches/SAMBA_3_0/source/nsswitch/wbinfo.c
===================================================================
--- branches/SAMBA_3_0/source/nsswitch/wbinfo.c	2006-11-29 22:10:15 UTC (rev 19956)
+++ branches/SAMBA_3_0/source/nsswitch/wbinfo.c	2006-11-29 23:20:22 UTC (rev 19957)
@@ -1182,7 +1182,7 @@
 	OPT_GROUP_INFO,
 };
 
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
 {
 	int opt;
 

Modified: branches/SAMBA_3_0/source/nsswitch/winbindd.c
===================================================================
--- branches/SAMBA_3_0/source/nsswitch/winbindd.c	2006-11-29 22:10:15 UTC (rev 19956)
+++ branches/SAMBA_3_0/source/nsswitch/winbindd.c	2006-11-29 23:20:22 UTC (rev 19957)
@@ -879,7 +879,7 @@
 
 struct winbindd_state server_state;   /* Server state information */
 
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
 {
 	pstring logfile;
 	static BOOL Fork = True;
@@ -1022,6 +1022,17 @@
 
 	pidfile_create("winbindd");
 
+	if (winbindd_validate_cache()) {
+		/* We have a bad cache, but luckily we
+		   just deleted it. Restart ourselves */
+		int i;
+		/* Ensure we have no open low fd's. */
+		for (i = 3; i < 100; i++) {
+			close(i);
+		}
+		return execve(argv[0], argv, envp);
+	}
+
 #if HAVE_SETPGID
 	/*
 	 * If we're interactive we want to set our own process group for
@@ -1040,6 +1051,9 @@
 		exit(1);
 	}
 	
+	/* Ensure all cache and idmap caches are consistent
+	   before we startup. */
+
 	/* React on 'smbcontrol winbindd reload-config' in the same way
 	   as to SIGHUP signal */
 	message_register(MSG_SMB_CONF_UPDATED, msg_reload_services);

Modified: branches/SAMBA_3_0/source/nsswitch/winbindd_cache.c
===================================================================
--- branches/SAMBA_3_0/source/nsswitch/winbindd_cache.c	2006-11-29 22:10:15 UTC (rev 19956)
+++ branches/SAMBA_3_0/source/nsswitch/winbindd_cache.c	2006-11-29 23:20:22 UTC (rev 19957)
@@ -2594,6 +2594,236 @@
 	return global_winbindd_offline_state;
 }
 
+/***********************************************************************
+ Validate functions for all possible cache tdb keys.
+***********************************************************************/
+
+static int validate_seqnum(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_ns(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_sn(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_u(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_loc_pol(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_pwd_pol(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_cred(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_ul(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_gl(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_ug(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_ua(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_gm(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+static int validate_trustdoms(TDB_DATA kbuf, TDB_DATA dbuf)
+{
+	return 0;
+}
+
+/***********************************************************************
+ A list of all possible cache tdb keys with associated validation
+ functions.
+***********************************************************************/
+
+struct key_val_struct {
+	const char *keyname;
+	int (*validate_data_fn)(TDB_DATA kbuf, TDB_DATA dbuf);
+} key_val[] = {
+	{"SEQNUM/", validate_seqnum},
+	{"NS/", validate_ns},
+	{"SN/", validate_sn},
+	{"U/", validate_u},
+	{"LOC_POL/", validate_loc_pol},
+	{"PWD_POL/", validate_pwd_pol},
+	{"CRED/", validate_cred},
+	{"UL/", validate_ul},
+	{"GL/", validate_gl},
+	{"UG/", validate_ug},
+	{"UA", validate_ua},
+	{"GM/", validate_gm},
+	{"TRUSTDOMS/", validate_trustdoms},
+	{NULL, NULL}
+};
+
+/***********************************************************************
+ Function to look at every entry in the tdb and validate it as far as
+ possible.
+***********************************************************************/
+
+static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
+{
+	int i;
+
+	/* Ensure key is valid. */
+	if (kbuf.dsize < 3) {
+		return 1; /* terminate. */
+	}
+	/* Ensure key is a string. */
+	if (kbuf.dptr[kbuf.dsize] != '\0') {
+		return 1; /* terminate. */
+	}
+
+	for (i = 0; key_val[i].keyname; i++) {
+		if (strncmp(key_val[i].keyname, kbuf.dptr, strlen(key_val[i].keyname)) == 0) {
+			if (key_val[i].validate_data_fn(kbuf, dbuf)) {
+				return 1; /* terminate. */
+			}
+		}
+	}
+	return 0;
+}
+
+/* Handle any signals generated when validating a possibly
+   bad cache tdb. */
+
+static jmp_buf jmpbuf;
+
+#ifdef SIGSEGV
+static void sig_segv(int sig)
+{
+	longjmp(jmpbuf, SIGSEGV);
+}
+#endif
+
+#ifdef SIGBUS
+static void sig_bus(int sig)
+{
+	longjmp(jmpbuf, SIGBUS);
+}
+#endif
+
+#ifdef SIGABRT
+static void sig_abrt(int sig)
+{
+	longjmp(jmpbuf, SIGABRT);
+}
+#endif
+
+/***********************************************************************
+ Try and validate every entry in the winbindd cache. If we fail here,
+ delete the cache tdb and return non-zero - the caller (main winbindd
+ function) will restart us as we don't know if we crashed or not.
+***********************************************************************/
+
+int winbindd_validate_cache(void)
+{
+	BOOL ret = -1;
+	int fd = -1;
+	TDB_CONTEXT *tdb = NULL;
+	const char *cache_path = lock_path("winbindd_cache.tdb");
+
+#ifdef SIGSEGV
+	void (*old_segv_handler)(int) = CatchSignal(SIGSEGV,SIGNAL_CAST sig_segv);
+#endif
+#ifdef SIGBUS
+	void (*old_bus_handler)(int) = CatchSignal(SIGBUS,SIGNAL_CAST sig_bus);
+#endif
+#ifdef SIGABRT
+	void (*old_abrt_handler)(int) = CatchSignal(SIGABRT,SIGNAL_CAST sig_abrt);
+#endif
+
+	switch((ret = setjmp(jmpbuf))) {
+		case 0:
+			ret = -1;
+			break;
+		case SIGSEGV:
+		case SIGBUS:
+		case SIGABRT:
+		default:
+			goto out;
+	}
+
+	tdb = tdb_open_log(cache_path,
+			WINBINDD_CACHE_TDB_DEFAULT_HASH_SIZE,
+			lp_winbind_offline_logon() ? TDB_DEFAULT : (TDB_DEFAULT | TDB_CLEAR_IF_FIRST),
+			O_RDWR|O_CREAT, 0600);
+	if (!tdb) {
+		goto out;
+	}
+
+	fd = tdb_fd(tdb);
+
+	/* Now traverse the cache to validate it. */
+	if (tdb_traverse(tdb, cache_traverse_validate_fn, NULL)) {
+		goto out;
+	}
+
+	DEBUG(10,("winbindd_validate_cache: cache %s is good\n", cache_path));
+	ret = 0; /* Cache is good. */
+
+  out:
+
+	/* Ensure if we segv on exit we use the original
+	   handlers to avoid a loop. */
+
+#ifdef SIGSEGV
+	CatchSignal(SIGSEGV,SIGNAL_CAST old_segv_handler);
+#endif
+#ifdef SIGBUS
+	CatchSignal(SIGBUS,SIGNAL_CAST old_bus_handler);
+#endif
+#ifdef SIGABRT
+	CatchSignal(SIGABRT,SIGNAL_CAST old_abrt_handler);
+#endif
+
+	if (tdb) {
+		if (ret == 0) {
+			tdb_close(tdb);
+		} else if (fd != -1) {
+			close(fd);
+		}
+	}
+
+	if (ret) {
+		unlink(cache_path);
+	}
+
+	return ret;
+}
+
 /* the cache backend methods are exposed via this structure */
 struct winbindd_methods cache_methods = {
 	True,



More information about the samba-cvs mailing list