diff options
author | Michael Adam <obnox@samba.org> | 2007-05-14 12:57:24 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:22:01 -0500 |
commit | cb47bb6d8f987febfc7b70b2de2d8d32b2ce8229 (patch) | |
tree | 55e8829a2c66a86caea3bcbae558e2158a1393b9 /source3/nsswitch | |
parent | b4a7b7a8889737e2891fc1176feabd4ce47f2737 (diff) | |
download | samba-cb47bb6d8f987febfc7b70b2de2d8d32b2ce8229.tar.gz samba-cb47bb6d8f987febfc7b70b2de2d8d32b2ce8229.tar.bz2 samba-cb47bb6d8f987febfc7b70b2de2d8d32b2ce8229.zip |
r22845: Modified and extended the winbindd cache validation code:
* Replaced signal catching/longjmp magic by a fork:
Let the child do the actual validation of the entries.
Exit code and signals are intercepted by waitpid.
* Fix logic so that also encounter of an unknown key in the
tdb leads to an error.
* Extended status of validation is kept in a (as yet simple)
stuct and communicated over a pipe from child to parent.
* Added two validation_ functions for two new keys.
The call of winbindd_validate_cache is still commented out
in the winbindd main loop. But I am currently testing it
and so far it seems to work fine.
The next step in my plan is to generalize the validation
mechanism to a tdb_open_log_validate function in lib/util_tdb.c.
There ist nothing very special about the cache tdb here,
and this might be useful elsewhere...
Michael
(This used to be commit 417325b9e6f9ac0afe1f2f3b552527788f6a7cee)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/winbindd_cache.c | 420 |
1 files changed, 283 insertions, 137 deletions
diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 8464b41deb..0d368ed6e2 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -7,6 +7,7 @@ Copyright (C) Gerald Carter 2003-2007 Copyright (C) Volker Lendecke 2005 Copyright (C) Guenther Deschner 2005 + Copyright (C) Michael Adam 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2764,9 +2765,16 @@ BOOL get_global_winbindd_state_offline(void) Validate functions for all possible cache tdb keys. ***********************************************************************/ -static BOOL bad_cache_entry; +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 cache_entry *centry; @@ -2781,9 +2789,10 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat if (centry->len < 8) { /* huh? corrupt cache? */ - DEBUG(0,("validate_create_centry: Corrupt cache for key %s (len < 8) ?\n", kstr)); + DEBUG(0,("create_centry_validate: Corrupt cache for key %s (len < 8) ?\n", kstr)); centry_free(centry); - bad_cache_entry = True; + state->bad_entry = True; + state->success = False; return NULL; } @@ -2792,20 +2801,22 @@ static struct cache_entry *create_centry_validate(const char *kstr, TDB_DATA dat return centry; } -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) { if (dbuf.dsize != 8) { DEBUG(0,("validate_seqnum: Corrupt cache for key %s (len %u != 8) ?\n", keystr, (unsigned int)dbuf.dsize )); - bad_cache_entry = True; + state->bad_entry = True; return 1; } return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); if (!centry) { return 1; } @@ -2818,16 +2829,17 @@ static int validate_ns(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_ns: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); if (!centry) { return 1; } @@ -2840,16 +2852,17 @@ static int validate_sn(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_sn: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); DOM_SID sid; if (!centry) { @@ -2866,16 +2879,17 @@ static int validate_u(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_u: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); if (!centry) { return 1; @@ -2887,16 +2901,17 @@ static int validate_loc_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_loc_pol: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); if (!centry) { return 1; @@ -2910,16 +2925,17 @@ static int validate_pwd_pol(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_pwd_pol: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); if (!centry) { return 1; @@ -2935,16 +2951,17 @@ static int validate_cred(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_cred: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_entries, i; if (!centry) { @@ -2965,16 +2982,17 @@ static int validate_ul(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_ul: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_entries, i; if (!centry) { @@ -2991,16 +3009,17 @@ static int validate_gl(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_gl: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_groups, i; if (!centry) { @@ -3016,16 +3035,17 @@ static int validate_ug(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_ug: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_aliases, i; if (!centry) { @@ -3040,16 +3060,17 @@ static int validate_ua(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_ua: %s ok\n", keystr)); return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_names, i; if (!centry) { @@ -3067,20 +3088,22 @@ static int validate_gm(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_gm: %s ok\n", keystr)); return 0; } -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) { /* Can't say anything about this other than must be nonzero. */ if (dbuf.dsize == 0) { DEBUG(0,("validate_dr: Corrupt cache for key %s (len == 0) ?\n", keystr)); - bad_cache_entry = True; + state->bad_entry = True; + state->success = False; return 1; } @@ -3088,13 +3111,15 @@ static int validate_dr(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) return 0; } -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) { /* Can't say anything about this other than must be nonzero. */ if (dbuf.dsize == 0) { DEBUG(0,("validate_de: Corrupt cache for key %s (len == 0) ?\n", keystr)); - bad_cache_entry = True; + state->bad_entry = True; + state->success = False; return 1; } @@ -3102,9 +3127,10 @@ static int validate_de(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) return 0; } -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 cache_entry *centry = create_centry_validate(keystr, dbuf); + struct cache_entry *centry = create_centry_validate(keystr, dbuf, state); int32 num_domains, i; if (!centry) { @@ -3122,25 +3148,60 @@ static int validate_trustdoms(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA centry_free(centry); - if (bad_cache_entry) { + if (!(state->success)) { return 1; } DEBUG(10,("validate_trustdoms: %s ok\n", keystr)); return 0; } -static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf) +static int validate_trustdomcache(TALLOC_CTX *mem_ctx, const char *keystr, + TDB_DATA dbuf, + struct validation_status *state) +{ + if (dbuf.dsize == 0) { + DEBUG(0, ("validate_trustdomcache: Corrupt cache for " + "key %s (len ==0) ?\n", keystr)); + state->bad_entry = True; + state->success = False; + return 1; + } + + DEBUG(10, ("validate_trustdomcache: %s ok\n", keystr)); + DEBUGADD(10, (" Don't trust me, I am a DUMMY!\n")); + return 0; +} + +static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, + struct validation_status *state) { if (dbuf.dsize != 4) { DEBUG(0,("validate_offline: Corrupt cache for key %s (len %u != 4) ?\n", keystr, (unsigned int)dbuf.dsize )); - bad_cache_entry = True; + state->bad_entry = True; + state->success = False; return 1; } DEBUG(10,("validate_offline: %s ok\n", keystr)); return 0; } +static int validate_cache_version(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, + struct validation_status *state) +{ + if (dbuf.dsize != 4) { + DEBUG(0, ("validate_cache_version: Corrupt cache for " + "key %s (len %u != 4) ?\n", + keystr, (unsigned int)dbuf.dsize)); + state->bad_entry = True; + state->success = False; + return 1; + } + + DEBUG(10, ("validate_cache_version: %s ok\n", keystr)); + return 0; +} + /*********************************************************************** A list of all possible cache tdb keys with associated validation functions. @@ -3148,7 +3209,7 @@ static int validate_offline(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA db struct key_val_struct { const char *keyname; - int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf); + int (*validate_data_fn)(TALLOC_CTX *mem_ctx, const char *keystr, TDB_DATA dbuf, struct validation_status* state); } key_val[] = { {"SEQNUM/", validate_seqnum}, {"NS/", validate_ns}, @@ -3165,7 +3226,9 @@ struct key_val_struct { {"DR/", validate_dr}, {"DE/", validate_de}, {"TRUSTDOMS/", validate_trustdoms}, + {"TRUSTDOMCACHE/", validate_trustdomcache}, {"WINBINDD_OFFLINE", validate_offline}, + {WINBINDD_CACHE_VERSION_KEYSTR, validate_cache_version}, {NULL, NULL} }; @@ -3177,6 +3240,7 @@ struct key_val_struct { static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state) { int i; + struct validation_status *v_state = (struct validation_status *)state; /* Paranoia check. */ if (kbuf.dsize > 1024) { @@ -3206,7 +3270,8 @@ static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_D return 1; } - ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf); + ret = key_val[i].validate_data_fn(mem_ctx, keystr, dbuf, + v_state); SAFE_FREE(keystr); talloc_destroy(mem_ctx); @@ -3218,40 +3283,17 @@ static int cache_traverse_validate_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_D dump_data(0, (uint8 *)kbuf.dptr, kbuf.dsize); DEBUG(0,("data :\n")); dump_data(0, (uint8 *)dbuf.dptr, dbuf.dsize); + v_state->unknown_key = True; + v_state->success = False; return 1; /* terminate. */ } static void validate_panic(const char *const why) { - DEBUG(0,("validating cache: would panic %s\n", why )); - bad_cache_entry = True; -} - -/* 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); + DEBUG(0,("validating cache: would panic %s\n", why )); + DEBUGADD(0, ("exiting instead (cache validation mode)\n")); + exit(47); } -#endif /*********************************************************************** Try and validate every entry in the winbindd cache. If we fail here, @@ -3259,102 +3301,206 @@ static void sig_abrt(int sig) function) will restart us as we don't know if we crashed or not. ***********************************************************************/ -int winbindd_validate_cache(void) +/* + * internal validation function, executed by the child. + */ +static int winbindd_validate_cache_child(const char *cache_path, int pfd) { - BOOL ret = -1; - int fd = -1; + int ret = -1; + int tfd = -1; int num_entries = 0; 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; - } - - /* Doh ! Volker is very smart :-). Use TDB_NOMMAP to prevent - * any wild pointer references when reading a corrupt tdb file. */ + 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_NOMMAP : (TDB_NOMMAP | TDB_CLEAR_IF_FIRST), + 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; } - fd = tdb_fd(tdb); + tfd = tdb_fd(tdb); /* Check the cache freelist is good. */ if (tdb_validate_freelist(tdb, &num_entries) == -1) { - DEBUG(0,("winbindd_validate_cache: bad freelist in cache %s\n", + 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: cache %s freelist has %d entries\n", + DEBUG(10,("winbindd_validate_cache_child: cache %s freelist has %d entries\n", cache_path, num_entries)); - smb_panic_fn = validate_panic; - /* Now traverse the cache to validate it. */ - num_entries = tdb_traverse(tdb, cache_traverse_validate_fn, NULL); - if (num_entries == -1 || bad_cache_entry) { - DEBUG(0,("winbindd_validate_cache: cache %s traverse failed\n", + 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: cache %s is good " + DEBUG(10,("winbindd_validate_cache_child: cache %s is good " "with %d entries\n", cache_path, num_entries)); ret = 0; /* Cache is good. */ - out: - - bad_cache_entry = False; - smb_panic_fn = smb_panic; - - /* 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 - +out: if (tdb) { if (ret == 0) { tdb_close(tdb); - } else if (fd != -1) { - close(fd); + } + else if (tfd != -1) { + close(tfd); } } - if (ret) { + 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) +{ + pid_t child_pid = -1; + 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")); + smb_panic_fn = validate_panic; + + /* 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, ("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, 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%s\n", + WTERMSIG(child_status), +#if defined(WCOREDUMP) + WCOREDUMP(child_status)?" (core dumped)":"" +#else + "" +#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")); + smb_panic_fn = smb_panic; return ret; } |