diff options
author | Jeremy Allison <jra@samba.org> | 2006-11-29 23:20:22 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:16:15 -0500 |
commit | ed34ffb14792cc47ca1af5ffeb076f3c2d7f28dc (patch) | |
tree | f2cdb0d12e201655161b5a3973331cae1edaca17 /source3/nsswitch/winbindd_cache.c | |
parent | 5893c0215d1c72ea9063b5e609d1c880dea0f1e8 (diff) | |
download | samba-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/winbindd_cache.c')
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 230 |
1 files changed, 230 insertions, 0 deletions
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, |