mirror of
https://github.com/samba-team/samba.git
synced 2025-02-02 09:47:23 +03:00
r23600: First step in abstracting the winbindd cache validation
code into a generic tdb validation code. In lib/util_tdb.c for a start. Michael (This used to be commit 527edfa0cbcb233218ebabc395666d1d7228ee37)
This commit is contained in:
parent
386267447b
commit
133472ac66
@ -41,6 +41,16 @@ struct tdb_wrap {
|
|||||||
struct tdb_wrap *next, *prev;
|
struct tdb_wrap *next, *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tdb_validation_status {
|
||||||
|
BOOL tdb_error;
|
||||||
|
BOOL bad_freelist;
|
||||||
|
BOOL bad_entry;
|
||||||
|
BOOL unknown_key;
|
||||||
|
BOOL success;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*tdb_validate_data_func)(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state);
|
||||||
|
|
||||||
TDB_LIST_NODE *tdb_search_keys(struct tdb_context*, const char*);
|
TDB_LIST_NODE *tdb_search_keys(struct tdb_context*, const char*);
|
||||||
void tdb_search_list_free(TDB_LIST_NODE*);
|
void tdb_search_list_free(TDB_LIST_NODE*);
|
||||||
int32 tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32 *oldval, int32 change_val);
|
int32 tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32 *oldval, int32 change_val);
|
||||||
|
@ -980,3 +980,206 @@ NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
|
|||||||
|
|
||||||
return NT_STATUS_INTERNAL_ERROR;
|
return NT_STATUS_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* the following is a generic validation mechanism for tdbs.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* internal validation function, executed by the child.
|
||||||
|
*/
|
||||||
|
static int tdb_validate_child(const char *tdb_path,
|
||||||
|
tdb_validate_data_func validate_fn,
|
||||||
|
int pfd)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
int tfd = -1;
|
||||||
|
int num_entries = 0;
|
||||||
|
TDB_CONTEXT *tdb = NULL;
|
||||||
|
struct tdb_validation_status v_status;
|
||||||
|
|
||||||
|
v_status.tdb_error = False;
|
||||||
|
v_status.bad_freelist = False;
|
||||||
|
v_status.bad_entry = False;
|
||||||
|
v_status.unknown_key = False;
|
||||||
|
v_status.success = True;
|
||||||
|
|
||||||
|
tdb = tdb_open_log(tdb_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) {
|
||||||
|
v_status.tdb_error = True;
|
||||||
|
v_status.success = False;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
tfd = tdb_fd(tdb);
|
||||||
|
|
||||||
|
/* Check the cache freelist is good. */
|
||||||
|
if (tdb_validate_freelist(tdb, &num_entries) == -1) {
|
||||||
|
DEBUG(0,("tdb_validate_child: bad freelist in cache %s\n",
|
||||||
|
tdb_path));
|
||||||
|
v_status.bad_freelist = True;
|
||||||
|
v_status.success = False;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10,("tdb_validate_child: cache %s freelist has %d entries\n",
|
||||||
|
tdb_path, num_entries));
|
||||||
|
|
||||||
|
/* Now traverse the cache to validate it. */
|
||||||
|
num_entries = tdb_traverse(tdb, validate_fn, (void *)&v_status);
|
||||||
|
if (num_entries == -1 || !(v_status.success)) {
|
||||||
|
DEBUG(0,("tdb_validate_child: cache %s traverse failed\n",
|
||||||
|
tdb_path));
|
||||||
|
if (!(v_status.success)) {
|
||||||
|
if (v_status.bad_entry) {
|
||||||
|
DEBUGADD(0, (" -> bad entry found\n"));
|
||||||
|
}
|
||||||
|
if (v_status.unknown_key) {
|
||||||
|
DEBUGADD(0, (" -> unknown key encountered\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10,("tdb_validate_child: cache %s is good "
|
||||||
|
"with %d entries\n", tdb_path, num_entries));
|
||||||
|
ret = 0; /* Cache is good. */
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (tdb) {
|
||||||
|
if (ret == 0) {
|
||||||
|
tdb_close(tdb);
|
||||||
|
}
|
||||||
|
else if (tfd != -1) {
|
||||||
|
close(tfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate_child: writing status to pipe\n"));
|
||||||
|
write (pfd, (const char *)&v_status, sizeof(v_status));
|
||||||
|
close(pfd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdb_validate(const char *tdb_path, tdb_validate_data_func validate_fn)
|
||||||
|
{
|
||||||
|
pid_t child_pid = -1;
|
||||||
|
int child_status = 0;
|
||||||
|
int wait_pid = 0;
|
||||||
|
int ret = -1;
|
||||||
|
int pipe_fds[2];
|
||||||
|
struct tdb_validation_status v_status;
|
||||||
|
int bytes_read = 0;
|
||||||
|
|
||||||
|
/* fork and let the child do the validation.
|
||||||
|
* benefit: no need to twist signal handlers and panic functions.
|
||||||
|
* just let the child panic. we catch the signal.
|
||||||
|
* communicate the extended status struct over a pipe. */
|
||||||
|
|
||||||
|
if (pipe(pipe_fds) != 0) {
|
||||||
|
DEBUG(0, ("tdb_validate: unable to create pipe, "
|
||||||
|
"error %s", strerror(errno)));
|
||||||
|
smb_panic("winbind_validate_cache: unable to create pipe.");
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate: forking to let child do validation.\n"));
|
||||||
|
child_pid = sys_fork();
|
||||||
|
if (child_pid == 0) {
|
||||||
|
DEBUG(10, ("tdb_validate (validation child): created\n"));
|
||||||
|
close(pipe_fds[0]); /* close reading fd */
|
||||||
|
DEBUG(10, ("tdb_validate (validation child): "
|
||||||
|
"calling tdb_validate_child\n"));
|
||||||
|
exit(tdb_validate_child(tdb_path, validate_fn, pipe_fds[1]));
|
||||||
|
}
|
||||||
|
else if (child_pid < 0) {
|
||||||
|
smb_panic("tdb_validate: fork for validation failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parent */
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate: fork succeeded, child PID = %d\n",
|
||||||
|
child_pid));
|
||||||
|
close(pipe_fds[1]); /* close writing fd */
|
||||||
|
|
||||||
|
v_status.success = True;
|
||||||
|
v_status.bad_entry = False;
|
||||||
|
v_status.unknown_key = False;
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate: reading from pipe.\n"));
|
||||||
|
bytes_read = read(pipe_fds[0], (void *)&v_status, sizeof(v_status));
|
||||||
|
close(pipe_fds[0]);
|
||||||
|
|
||||||
|
if (bytes_read != sizeof(v_status)) {
|
||||||
|
DEBUG(10, ("tdb_validate: read %d bytes from pipe "
|
||||||
|
"but expected %d", bytes_read, (int)sizeof(v_status)));
|
||||||
|
DEBUGADD(10, (" -> assuming child crashed\n"));
|
||||||
|
v_status.success = False;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG(10, ("tdb_validate: read status from child\n"));
|
||||||
|
DEBUGADD(10, (" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
|
||||||
|
DEBUGADD(10, (" * bad freelist: %s\n", v_status.bad_freelist ? "yes" : "no"));
|
||||||
|
DEBUGADD(10, (" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
|
||||||
|
DEBUGADD(10, (" * unknown key: %s\n", v_status.unknown_key ? "yes" : "no"));
|
||||||
|
DEBUGADD(10, (" => overall success: %s\n", v_status.success ? "yes" : "no"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!v_status.success) {
|
||||||
|
DEBUG(10, ("tdb_validate: validation not successful.\n"));
|
||||||
|
DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
|
||||||
|
unlink(tdb_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate: waiting for child to finish...\n"));
|
||||||
|
while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
DEBUG(10, ("tdb_validate: got signal during "
|
||||||
|
"waitpid, retrying\n"));
|
||||||
|
errno = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DEBUG(0, ("tdb_validate: waitpid failed with "
|
||||||
|
"errno %s\n", strerror(errno)));
|
||||||
|
smb_panic("tdb_validate: waitpid failed.");
|
||||||
|
}
|
||||||
|
if (wait_pid != child_pid) {
|
||||||
|
DEBUG(0, ("tdb_validate: waitpid returned pid %d, "
|
||||||
|
"but %d was expexted\n", wait_pid, child_pid));
|
||||||
|
smb_panic("tdb_validate: waitpid returned "
|
||||||
|
"unexpected PID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEBUG(10, ("tdb_validate: validating child returned.\n"));
|
||||||
|
if (WIFEXITED(child_status)) {
|
||||||
|
DEBUG(10, ("tdb_validate: child exited, code %d.\n",
|
||||||
|
WEXITSTATUS(child_status)));
|
||||||
|
ret = WEXITSTATUS(child_status);
|
||||||
|
}
|
||||||
|
if (WIFSIGNALED(child_status)) {
|
||||||
|
DEBUG(10, ("tdb_validate: child terminated "
|
||||||
|
"by signal %d\n", WTERMSIG(child_status)));
|
||||||
|
#ifdef WCOREDUMP
|
||||||
|
if (WCOREDUMP(child_status)) {
|
||||||
|
DEBUGADD(10, ("core dumped\n"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ret = WTERMSIG(child_status);
|
||||||
|
}
|
||||||
|
if (WIFSTOPPED(child_status)) {
|
||||||
|
DEBUG(10, ("tdb_validate: child was stopped "
|
||||||
|
"by signal %d\n",
|
||||||
|
WSTOPSIG(child_status)));
|
||||||
|
ret = WSTOPSIG(child_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -2749,16 +2749,8 @@ BOOL get_global_winbindd_state_offline(void)
|
|||||||
Validate functions for all possible cache tdb keys.
|
Validate functions for all possible cache tdb keys.
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
struct validation_status {
|
|
||||||
BOOL tdb_error;
|
|
||||||
BOOL bad_freelist;
|
|
||||||
BOOL bad_entry;
|
|
||||||
BOOL unknown_key;
|
|
||||||
BOOL success;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
|
static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA data,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry;
|
struct cache_entry *centry;
|
||||||
|
|
||||||
@ -2786,7 +2778,7 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
if (dbuf.dsize != 8) {
|
if (dbuf.dsize != 8) {
|
||||||
DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
|
DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n",
|
||||||
@ -2798,7 +2790,7 @@ static int validate_seqnum(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbu
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
if (!centry) {
|
if (!centry) {
|
||||||
@ -2821,7 +2813,7 @@ static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
if (!centry) {
|
if (!centry) {
|
||||||
@ -2844,7 +2836,7 @@ static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
DOM_SID sid;
|
DOM_SID sid;
|
||||||
@ -2871,7 +2863,7 @@ static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
|
|
||||||
@ -2893,7 +2885,7 @@ static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
|
|
||||||
@ -2917,7 +2909,7 @@ static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
|
|
||||||
@ -2943,7 +2935,7 @@ static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_entries, i;
|
int32 num_entries, i;
|
||||||
@ -2974,7 +2966,7 @@ static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_entries, i;
|
int32 num_entries, i;
|
||||||
@ -3001,7 +2993,7 @@ static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_groups, i;
|
int32 num_groups, i;
|
||||||
@ -3027,7 +3019,7 @@ static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_aliases, i;
|
int32 num_aliases, i;
|
||||||
@ -3052,7 +3044,7 @@ static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_names, i;
|
int32 num_names, i;
|
||||||
@ -3080,7 +3072,7 @@ static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
/* Can't say anything about this other than must be nonzero. */
|
/* Can't say anything about this other than must be nonzero. */
|
||||||
if (dbuf.dsize == 0) {
|
if (dbuf.dsize == 0) {
|
||||||
@ -3096,7 +3088,7 @@ static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
/* Can't say anything about this other than must be nonzero. */
|
/* Can't say anything about this other than must be nonzero. */
|
||||||
if (dbuf.dsize == 0) {
|
if (dbuf.dsize == 0) {
|
||||||
@ -3112,7 +3104,7 @@ static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
struct cache_entry *centry = create_centry_validate(keystr, dbuf, state);
|
||||||
int32 num_domains, i;
|
int32 num_domains, i;
|
||||||
@ -3141,7 +3133,7 @@ static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA
|
|||||||
|
|
||||||
static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
|
static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
|
||||||
TDB_DATA dbuf,
|
TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
if (dbuf.dsize == 0) {
|
if (dbuf.dsize == 0) {
|
||||||
DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
|
DEBUG(0, ("validate_trustdomcache: Corrupt cache for "
|
||||||
@ -3157,7 +3149,7 @@ static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
if (dbuf.dsize != 4) {
|
if (dbuf.dsize != 4) {
|
||||||
DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
|
DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n",
|
||||||
@ -3171,7 +3163,7 @@ static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf,
|
||||||
struct validation_status *state)
|
struct tdb_validation_status *state)
|
||||||
{
|
{
|
||||||
if (dbuf.dsize != 4) {
|
if (dbuf.dsize != 4) {
|
||||||
DEBUG(0, ("validate_cache_version: Corrupt cache for "
|
DEBUG(0, ("validate_cache_version: Corrupt cache for "
|
||||||
@ -3193,7 +3185,7 @@ static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_D
|
|||||||
|
|
||||||
struct key_val_struct {
|
struct key_val_struct {
|
||||||
const char *keyname;
|
const char *keyname;
|
||||||
int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct validation_status* state);
|
int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct tdb_validation_status* state);
|
||||||
} key_val[] = {
|
} key_val[] = {
|
||||||
{"SEQNUM/", validate_seqnum},
|
{"SEQNUM/", validate_seqnum},
|
||||||
{"NS/", validate_ns},
|
{"NS/", validate_ns},
|
||||||
@ -3224,7 +3216,7 @@ struct key_val_struct {
|
|||||||
static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
|
static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct validation_status *v_state = (struct validation_status *)state;
|
struct tdb_validation_status *v_state = (struct tdb_validation_status *)state;
|
||||||
|
|
||||||
/* Paranoia check. */
|
/* Paranoia check. */
|
||||||
if (kbuf.dsize > 1024) {
|
if (kbuf.dsize > 1024) {
|
||||||
@ -3285,201 +3277,15 @@ static void validate_panic(const char *const why)
|
|||||||
function) will restart us as we don't know if we crashed or not.
|
function) will restart us as we don't know if we crashed or not.
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
/*
|
|
||||||
* internal validation function, executed by the child.
|
|
||||||
*/
|
|
||||||
static int winbindd_validate_cache_child(const char *cache_path, int pfd)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
int tfd = -1;
|
|
||||||
int num_entries = 0;
|
|
||||||
TDB_CONTEXT *tdb = NULL;
|
|
||||||
struct validation_status v_status;
|
|
||||||
|
|
||||||
v_status.tdb_error = False;
|
|
||||||
v_status.bad_freelist = False;
|
|
||||||
v_status.bad_entry = False;
|
|
||||||
v_status.unknown_key = False;
|
|
||||||
v_status.success = True;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
v_status.tdb_error = True;
|
|
||||||
v_status.success = False;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
tfd = tdb_fd(tdb);
|
|
||||||
|
|
||||||
/* Check the cache freelist is good. */
|
|
||||||
if (tdb_validate_freelist(tdb, &num_entries) == -1) {
|
|
||||||
DEBUG(0,("winbindd_validate_cache_child: bad freelist in cache %s\n",
|
|
||||||
cache_path));
|
|
||||||
v_status.bad_freelist = True;
|
|
||||||
v_status.success = False;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10,("winbindd_validate_cache_child: cache %s freelist has %d entries\n",
|
|
||||||
cache_path, num_entries));
|
|
||||||
|
|
||||||
/* Now traverse the cache to validate it. */
|
|
||||||
num_entries = tdb_traverse(tdb, cache_traverse_validate_fn, (void *)&v_status);
|
|
||||||
if (num_entries == -1 || !(v_status.success)) {
|
|
||||||
DEBUG(0,("winbindd_validate_cache_child: cache %s traverse failed\n",
|
|
||||||
cache_path));
|
|
||||||
if (!(v_status.success)) {
|
|
||||||
if (v_status.bad_entry) {
|
|
||||||
DEBUGADD(0, (" -> bad entry found\n"));
|
|
||||||
}
|
|
||||||
if (v_status.unknown_key) {
|
|
||||||
DEBUGADD(0, (" -> unknown key encountered\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10,("winbindd_validate_cache_child: cache %s is good "
|
|
||||||
"with %d entries\n", cache_path, num_entries));
|
|
||||||
ret = 0; /* Cache is good. */
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (tdb) {
|
|
||||||
if (ret == 0) {
|
|
||||||
tdb_close(tdb);
|
|
||||||
}
|
|
||||||
else if (tfd != -1) {
|
|
||||||
close(tfd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache_child: writing status to pipe\n"));
|
|
||||||
write (pfd, (const char *)&v_status, sizeof(v_status));
|
|
||||||
close(pfd);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int winbindd_validate_cache(void)
|
int winbindd_validate_cache(void)
|
||||||
{
|
{
|
||||||
pid_t child_pid = -1;
|
int ret;
|
||||||
int child_status = 0;
|
|
||||||
int wait_pid = 0;
|
|
||||||
int ret = -1;
|
|
||||||
int pipe_fds[2];
|
|
||||||
struct validation_status v_status;
|
|
||||||
int bytes_read = 0;
|
|
||||||
const char *cache_path = lock_path("winbindd_cache.tdb");
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
|
DEBUG(10, ("winbindd_validate_cache: replacing panic function\n"));
|
||||||
smb_panic_fn = validate_panic;
|
smb_panic_fn = validate_panic;
|
||||||
|
|
||||||
/* fork and let the child do the validation.
|
ret = tdb_validate(lock_path("winbindd_cache.tdb"),
|
||||||
* benefit: no need to twist signal handlers and panic functions.
|
cache_traverse_validate_fn);
|
||||||
* just let the child panic. we catch the signal.
|
|
||||||
* communicate the extended status struct over a pipe. */
|
|
||||||
|
|
||||||
if (pipe(pipe_fds) != 0) {
|
|
||||||
DEBUG(0, ("winbindd_validate_cache: unable to create pipe, "
|
|
||||||
"error %s", strerror(errno)));
|
|
||||||
smb_panic("winbind_validate_cache: unable to create pipe.");
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: forking to let child do validation.\n"));
|
|
||||||
child_pid = sys_fork();
|
|
||||||
if (child_pid == 0) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache (validation child): created\n"));
|
|
||||||
close(pipe_fds[0]); /* close reading fd */
|
|
||||||
DEBUG(10, ("winbindd_validate_cache (validation child): "
|
|
||||||
"calling winbindd_validate_cache_child\n"));
|
|
||||||
exit(winbindd_validate_cache_child(cache_path, pipe_fds[1]));
|
|
||||||
}
|
|
||||||
else if (child_pid < 0) {
|
|
||||||
smb_panic("winbindd_validate_cache: fork for validation failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parent */
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: fork succeeded, child PID = %d\n",
|
|
||||||
child_pid));
|
|
||||||
close(pipe_fds[1]); /* close writing fd */
|
|
||||||
|
|
||||||
v_status.success = True;
|
|
||||||
v_status.bad_entry = False;
|
|
||||||
v_status.unknown_key = False;
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: reading from pipe.\n"));
|
|
||||||
bytes_read = read(pipe_fds[0], (void *)&v_status, sizeof(v_status));
|
|
||||||
close(pipe_fds[0]);
|
|
||||||
|
|
||||||
if (bytes_read != sizeof(v_status)) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: read %d bytes from pipe "
|
|
||||||
"but expected %d", bytes_read, (int)sizeof(v_status)));
|
|
||||||
DEBUGADD(10, (" -> assuming child crashed\n"));
|
|
||||||
v_status.success = False;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: read status from child\n"));
|
|
||||||
DEBUGADD(10, (" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
|
|
||||||
DEBUGADD(10, (" * bad freelist: %s\n", v_status.bad_freelist ? "yes" : "no"));
|
|
||||||
DEBUGADD(10, (" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
|
|
||||||
DEBUGADD(10, (" * unknown key: %s\n", v_status.unknown_key ? "yes" : "no"));
|
|
||||||
DEBUGADD(10, (" => overall success: %s\n", v_status.success ? "yes" : "no"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!v_status.success) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: validation not successful.\n"));
|
|
||||||
DEBUGADD(10, ("removing tdb %s.\n", cache_path));
|
|
||||||
unlink(cache_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: waiting for child to finish...\n"));
|
|
||||||
while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: got signal during "
|
|
||||||
"waitpid, retrying\n"));
|
|
||||||
errno = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DEBUG(0, ("winbindd_validate_cache: waitpid failed with "
|
|
||||||
"errno %s\n", strerror(errno)));
|
|
||||||
smb_panic("winbindd_validate_cache: waitpid failed.");
|
|
||||||
}
|
|
||||||
if (wait_pid != child_pid) {
|
|
||||||
DEBUG(0, ("winbindd_validate_cache: waitpid returned pid %d, "
|
|
||||||
"but %d was expexted\n", wait_pid, child_pid));
|
|
||||||
smb_panic("winbindd_validate_cache: waitpid returned "
|
|
||||||
"unexpected PID.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: validating child returned.\n"));
|
|
||||||
if (WIFEXITED(child_status)) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: child exited, code %d.\n",
|
|
||||||
WEXITSTATUS(child_status)));
|
|
||||||
ret = WEXITSTATUS(child_status);
|
|
||||||
}
|
|
||||||
if (WIFSIGNALED(child_status)) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: child terminated "
|
|
||||||
"by signal %d\n", WTERMSIG(child_status)));
|
|
||||||
#ifdef WCOREDUMP
|
|
||||||
if (WCOREDUMP(child_status)) {
|
|
||||||
DEBUGADD(10, ("core dumped\n"));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ret = WTERMSIG(child_status);
|
|
||||||
}
|
|
||||||
if (WIFSTOPPED(child_status)) {
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: child was stopped "
|
|
||||||
"by signal %d\n",
|
|
||||||
WSTOPSIG(child_status)));
|
|
||||||
ret = WSTOPSIG(child_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
|
DEBUG(10, ("winbindd_validate_cache: restoring panic function\n"));
|
||||||
smb_panic_fn = smb_panic;
|
smb_panic_fn = smb_panic;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user