1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-02 09:47:23 +03:00

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)
This commit is contained in:
Jeremy Allison 2006-11-29 23:20:22 +00:00 committed by Gerald (Jerry) Carter
parent 5893c0215d
commit ed34ffb147
4 changed files with 248 additions and 2 deletions

View File

@ -36,4 +36,6 @@
#define SIGNAL_CAST (RETSIGTYPE (*)(int))
#endif
#include <setjmp.h>
#endif

View File

@ -1182,7 +1182,7 @@ enum {
OPT_GROUP_INFO,
};
int main(int argc, char **argv)
int main(int argc, char **argv, char **envp)
{
int opt;

View File

@ -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);

View File

@ -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,