mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +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 commit is contained in:
parent
b6bf2e4267
commit
8eb53f74e4
@ -36,4 +36,6 @@
|
||||
#define SIGNAL_CAST (RETSIGTYPE (*)(int))
|
||||
#endif
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#endif
|
||||
|
@ -1182,7 +1182,7 @@ enum {
|
||||
OPT_GROUP_INFO,
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int opt;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user