summaryrefslogtreecommitdiff
path: root/source3/nsswitch
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2006-11-29 23:20:22 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:16:15 -0500
commited34ffb14792cc47ca1af5ffeb076f3c2d7f28dc (patch)
treef2cdb0d12e201655161b5a3973331cae1edaca17 /source3/nsswitch
parent5893c0215d1c72ea9063b5e609d1c880dea0f1e8 (diff)
downloadsamba-ed34ffb14792cc47ca1af5ffeb076f3c2d7f28dc.tar.gz
samba-ed34ffb14792cc47ca1af5ffeb076f3c2d7f28dc.tar.bz2
samba-ed34ffb14792cc47ca1af5ffeb076f3c2d7f28dc.zip
r19957: 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. (This used to be commit 8eb53f74e414483afde7b1e38ea2a3f56ae3ec66)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r--source3/nsswitch/wbinfo.c2
-rw-r--r--source3/nsswitch/winbindd.c16
-rw-r--r--source3/nsswitch/winbindd_cache.c230
3 files changed, 246 insertions, 2 deletions
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c
index ffca4121fa..cabf995042 100644
--- a/source3/nsswitch/wbinfo.c
+++ b/source3/nsswitch/wbinfo.c
@@ -1182,7 +1182,7 @@ enum {
OPT_GROUP_INFO,
};
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
{
int opt;
diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c
index e9e51449d6..41662900ce 100644
--- a/source3/nsswitch/winbindd.c
+++ b/source3/nsswitch/winbindd.c
@@ -879,7 +879,7 @@ static void process_loop(void)
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 @@ int main(int argc, char **argv)
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 @@ int main(int argc, char **argv)
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);
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c
index baaa5826bb..e9b0d2e8f9 100644
--- a/source3/nsswitch/winbindd_cache.c
+++ b/source3/nsswitch/winbindd_cache.c
@@ -2594,6 +2594,236 @@ BOOL get_global_winbindd_state_offline(void)
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,