[SCM] Samba Shared Repository - branch v3-2-test updated -
release-3-2-0pre2-3347-g80a3759
Jeremy Allison
jra at samba.org
Sat Jan 10 22:34:10 GMT 2009
The branch, v3-2-test has been updated
via 80a37595ef5c289fcc02a8902e18eb9ab289b28c (commit)
from 9811454d8ae3f09d9a206f14ed533fa6382a914c (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test
- Log -----------------------------------------------------------------
commit 80a37595ef5c289fcc02a8902e18eb9ab289b28c
Author: Bo Yang <boyang at novell.com>
Date: Sat Jan 10 14:33:36 2009 -0800
Backport of the clean event context after fork and
krb5 refresh chain fixes.
-----------------------------------------------------------------------
Summary of changes:
source/lib/events.c | 32 ----
source/winbindd/winbindd.c | 5 +
source/winbindd/winbindd_cm.c | 80 ++++----
source/winbindd/winbindd_cred_cache.c | 326 +++++++++++++++++++++++++++-----
source/winbindd/winbindd_dual.c | 165 +++++++++++-------
5 files changed, 423 insertions(+), 185 deletions(-)
Changeset truncated at 500 lines:
diff --git a/source/lib/events.c b/source/lib/events.c
index 2dae56e..27dd052 100644
--- a/source/lib/events.c
+++ b/source/lib/events.c
@@ -386,38 +386,6 @@ struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
return result;
}
-int set_event_dispatch_time(struct event_context *event_ctx,
- const char *event_name, struct timeval when)
-{
- struct timed_event *te;
-
- for (te = event_ctx->timed_events; te; te = te->next) {
- if (strcmp(event_name, te->event_name) == 0) {
- DLIST_REMOVE(event_ctx->timed_events, te);
- te->when = when;
- add_event_by_time(te);
- return 1;
- }
- }
- return 0;
-}
-
-/* Returns 1 if event was found and cancelled, 0 otherwise. */
-
-int cancel_named_event(struct event_context *event_ctx,
- const char *event_name)
-{
- struct timed_event *te;
-
- for (te = event_ctx->timed_events; te; te = te->next) {
- if (strcmp(event_name, te->event_name) == 0) {
- TALLOC_FREE(te);
- return 1;
- }
- }
- return 0;
-}
-
void dump_event_list(struct event_context *event_ctx)
{
struct timed_event *te;
diff --git a/source/winbindd/winbindd.c b/source/winbindd/winbindd.c
index 442f072..683e554 100644
--- a/source/winbindd/winbindd.c
+++ b/source/winbindd/winbindd.c
@@ -1222,6 +1222,11 @@ int main(int argc, char **argv, char **envp)
TimeInit();
+ /* Don't use winbindd_reinit_after_fork here as
+ * we're just starting up and haven't created any
+ * winbindd-specific resources we must free yet. JRA.
+ */
+
if (!reinit_after_fork(winbind_messaging_context(),
winbind_event_context(), false)) {
DEBUG(0,("reinit_after_fork() failed\n"));
diff --git a/source/winbindd/winbindd_cm.c b/source/winbindd/winbindd_cm.c
index 343ad39..3996e48 100644
--- a/source/winbindd/winbindd_cm.c
+++ b/source/winbindd/winbindd_cm.c
@@ -173,6 +173,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
TALLOC_CTX *mem_ctx = NULL;
pid_t child_pid;
pid_t parent_pid = sys_getpid();
+ char *lfile = NULL;
/* Stop zombies */
CatchChild();
@@ -199,22 +200,24 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain)
/* Leave messages blocked - we will never process one. */
- if (!reinit_after_fork(winbind_messaging_context(),
- winbind_event_context(), true)) {
+ if (!override_logfile) {
+ if (asprintf(&lfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) == -1) {
+ DEBUG(0, ("fork_child_dc_connect: out of memory!\n"));
+ return false;
+ }
+ }
+
+ if (!winbindd_reinit_after_fork(lfile)) {
DEBUG(0,("reinit_after_fork() failed\n"));
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name) + 1);
_exit(0);
}
- close_conns_after_fork();
-
- if (!override_logfile) {
- char *logfile;
- if (asprintf(&logfile, "%s/log.winbindd-dc-connect", get_dyn_LOGFILEBASE()) > 0) {
- lp_set_logfile(logfile);
- SAFE_FREE(logfile);
- reopen_logs();
- }
- }
+ SAFE_FREE(lfile);
mem_ctx = talloc_init("fork_child_dc_connect");
if (!mem_ctx) {
@@ -378,9 +381,10 @@ void set_domain_offline(struct winbindd_domain *domain)
Set domain online - if allowed.
****************************************************************/
+void ccache_regain_all_now(void);
+
static void set_domain_online(struct winbindd_domain *domain)
{
- struct timeval now;
DEBUG(10,("set_domain_online: called for domain %s\n",
domain->name ));
@@ -400,10 +404,8 @@ static void set_domain_online(struct winbindd_domain *domain)
winbindd_set_locator_kdc_envs(domain);
/* If we are waiting to get a krb5 ticket, trigger immediately. */
- GetTimeOfDay(&now);
- set_event_dispatch_time(winbind_event_context(),
- "krb5_ticket_gain_handler", now);
-
+ ccache_regain_all_now();
+
/* Ok, we're out of any startup mode now... */
domain->startup = False;
@@ -475,37 +477,35 @@ void set_domain_online_request(struct winbindd_domain *domain)
because network manager seems to lie.
Wait at least 5 seconds. Heuristics suck... */
+ GetTimeOfDay(&tev);
+
+ /* Go into "startup" mode again. */
+ domain->startup_time = tev.tv_sec;
+ domain->startup = True;
+
+ tev.tv_sec += 5;
if (!domain->check_online_event) {
/* If we've come from being globally offline we
don't have a check online event handler set.
We need to add one now we're trying to go
back online. */
-
DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
domain->name ));
-
- domain->check_online_event = event_add_timed(winbind_event_context(),
- NULL,
- timeval_current_ofs(5, 0),
- "check_domain_online_handler",
- check_domain_online_handler,
- domain);
-
- /* The above *has* to succeed for winbindd to work. */
- if (!domain->check_online_event) {
- smb_panic("set_domain_online_request: failed to add online handler");
- }
}
-
- GetTimeOfDay(&tev);
-
- /* Go into "startup" mode again. */
- domain->startup_time = tev.tv_sec;
- domain->startup = True;
-
- tev.tv_sec += 5;
-
- set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
+
+ TALLOC_FREE(domain->check_online_event);
+
+ domain->check_online_event = event_add_timed(winbind_event_context(),
+ NULL,
+ tev,
+ "check_domain_online_handler",
+ check_domain_online_handler,
+ domain);
+
+ /* The above *has* to succeed for winbindd to work. */
+ if (!domain->check_online_event) {
+ smb_panic("set_domain_online_request: failed to add online handler");
+ }
}
/****************************************************************
diff --git a/source/winbindd/winbindd_cred_cache.c b/source/winbindd/winbindd_cred_cache.c
index 311b1d1..05294a9 100644
--- a/source/winbindd/winbindd_cred_cache.c
+++ b/source/winbindd/winbindd_cred_cache.c
@@ -34,6 +34,8 @@
#define MAX_CCACHES 100
static struct WINBINDD_CCACHE_ENTRY *ccache_list;
+static void add_krb5_ticket_gain_handler_event(struct WINBINDD_CCACHE_ENTRY *entry,
+ struct timeval t);
/* The Krb5 ticket refresh handler should be scheduled
at one-half of the period from now till the tkt
@@ -71,6 +73,72 @@ static int ccache_entry_count(void)
return i;
}
+void ccache_remove_all_after_fork(void)
+{
+ struct WINBINDD_CCACHE_ENTRY *cur;
+ cur = ccache_list;
+ while (cur) {
+ DLIST_REMOVE(ccache_list, cur);
+ TALLOC_FREE(cur->event);
+ TALLOC_FREE(cur);
+ cur = ccache_list;
+ }
+}
+
+static void krb5_ticket_gain_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data);
+static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data);
+
+void ccache_regain_all_now(void)
+{
+ struct WINBINDD_CCACHE_ENTRY *cur;
+ struct timeval t = timeval_current();
+
+ cur = ccache_list;
+ while (cur) {
+ TALLOC_FREE(cur->event);
+ if (cur->refresh_time) {
+ cur->event = event_add_timed(winbind_event_context(),
+ cur, t,
+ "krb5_ticket_refresh_handler",
+ krb5_ticket_refresh_handler,
+ cur);
+ } else {
+ cur->event = event_add_timed(winbind_event_context(),
+ cur, t,
+ "krb5_ticket_gain_handler",
+ krb5_ticket_gain_handler,
+ cur);
+ }
+ if (!cur->event) {
+ DEBUG(0,("ccache_regain_all_now: out of memory!!\n"));
+ }
+ }
+ return;
+}
+
+/****************************************************************
+ The gain initial tikcet case is recongnized as entry->refresh_time
+ is always zero.
+****************************************************************/
+
+static void add_krb5_ticket_gain_handler_event(struct WINBINDD_CCACHE_ENTRY *entry,
+ struct timeval t)
+{
+ entry->refresh_time = 0;
+ entry->event = event_add_timed(winbind_event_context(), entry,
+ t,
+ "krb5_ticket_gain_handler",
+ krb5_ticket_gain_handler,
+ entry);
+}
+
+
/****************************************************************
Do the work of refreshing the ticket.
****************************************************************/
@@ -85,6 +153,7 @@ static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
#ifdef HAVE_KRB5
int ret;
time_t new_start;
+ time_t expire_time = 0;
struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr;
#endif
@@ -97,44 +166,80 @@ static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
#ifdef HAVE_KRB5
/* Kinit again if we have the user password and we can't renew the old
- * tgt anymore */
-
- if ((entry->renew_until < time(NULL)) && cred_ptr && cred_ptr->pass) {
-
- set_effective_uid(entry->uid);
-
- ret = kerberos_kinit_password_ext(entry->principal_name,
- cred_ptr->pass,
- 0, /* hm, can we do time correction here ? */
- &entry->refresh_time,
- &entry->renew_until,
- entry->ccname,
- False, /* no PAC required anymore */
- True,
- WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
- NULL);
- gain_root_privilege();
-
- if (ret) {
- DEBUG(3,("krb5_ticket_refresh_handler: "
- "could not re-kinit: %s\n",
- error_message(ret)));
- TALLOC_FREE(entry->event);
- return;
- }
-
- DEBUG(10,("krb5_ticket_refresh_handler: successful re-kinit "
- "for: %s in ccache: %s\n",
- entry->principal_name, entry->ccname));
+ * tgt anymore
+ * NB
+ * This happens when machine are put to sleep for a very long time. */
+
+ if (entry->renew_until < time(NULL)) {
+rekinit:
+ if (cred_ptr && cred_ptr->pass) {
+
+ set_effective_uid(entry->uid);
+
+ ret = kerberos_kinit_password_ext(entry->principal_name,
+ cred_ptr->pass,
+ 0, /* hm, can we do time correction here ? */
+ &entry->refresh_time,
+ &entry->renew_until,
+ entry->ccname,
+ False, /* no PAC required anymore */
+ True,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
+ NULL);
+ gain_root_privilege();
+
+ if (ret) {
+ DEBUG(3,("krb5_ticket_refresh_handler: "
+ "could not re-kinit: %s\n",
+ error_message(ret)));
+ /* destroy the ticket because we cannot rekinit
+ * it, ignore error here */
+ ads_kdestroy(entry->ccname);
+
+ /* Don't break the ticket refresh chain: retry
+ * refreshing ticket sometime later when KDC is
+ * unreachable -- BoYang
+ * */
+
+ if ((ret == KRB5_KDC_UNREACH)
+ || (ret == KRB5_REALM_CANT_RESOLVE)) {
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ new_start = time(NULL) + 30;
+#else
+ new_start = time(NULL) +
+ MAX(30, lp_winbind_cache_time());
+#endif
+ /* try to regain ticket here */
+ add_krb5_ticket_gain_handler_event(entry,
+ timeval_set(new_start, 0));
+ return;
+ }
+ TALLOC_FREE(entry->event);
+ return;
+ }
+
+ DEBUG(10,("krb5_ticket_refresh_handler: successful re-kinit "
+ "for: %s in ccache: %s\n",
+ entry->principal_name, entry->ccname));
#if defined(DEBUG_KRB5_TKT_RENEWAL)
- new_start = time(NULL) + 30;
+ new_start = time(NULL) + 30;
#else
- /* The tkt should be refreshed at one-half the period
- from now to the expiration time */
- new_start = KRB5_EVENT_REFRESH_TIME(entry->refresh_time);
+ /* The tkt should be refreshed at one-half the period
+ from now to the expiration time */
+ expire_time = entry->refresh_time;
+ new_start = KRB5_EVENT_REFRESH_TIME(entry->refresh_time);
#endif
- goto done;
+ goto done;
+ } else {
+ /* can this happen?
+ * No cached credentials
+ * destroy ticket and refresh chain
+ * */
+ ads_kdestroy(entry->ccname);
+ TALLOC_FREE(entry->event);
+ return;
+ }
}
set_effective_uid(entry->uid);
@@ -146,6 +251,7 @@ static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
#if defined(DEBUG_KRB5_TKT_RENEWAL)
new_start = time(NULL) + 30;
#else
+ expire_time = new_start;
new_start = KRB5_EVENT_REFRESH_TIME(new_start);
#endif
@@ -157,21 +263,65 @@ static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
error_message(ret)));
/* maybe we are beyond the renewing window */
+ /* evil rises here, we refresh ticket failed,
+ * but the ticket might be expired. Therefore,
+ * When we refresh ticket failed, destory the
+ * ticket */
+
+ ads_kdestroy(entry->ccname);
+
/* avoid breaking the renewal chain: retry in
* lp_winbind_cache_time() seconds when the KDC was not
- * available right now. */
+ * available right now.
+ * the return code can be KRB5_REALM_CANT_RESOLVE*/
- if (ret == KRB5_KDC_UNREACH) {
+ if ((ret == KRB5_KDC_UNREACH)
+ || (ret == KRB5_REALM_CANT_RESOLVE)) {
+#if defined(DEBUG_KRB5_TKT_RENEWAL)
+ new_start = time(NULL) + 30;
+#else
new_start = time(NULL) +
MAX(30, lp_winbind_cache_time());
- goto done;
+#endif
+ /* ticket is destroyed here, we have to regain it
+ * if it is possible */
+ add_krb5_ticket_gain_handler_event(entry,
+ timeval_set(new_start, 0));
+ return;
}
+ /* This is evil, if the ticket was already expired.
+ * renew ticket function returns KRB5KRB_AP_ERR_TKT_EXPIRED.
+ * But there is still a chance that we can rekinit it.
+ *
+ * This happens when user login in online mode, and then network
+ * down or something cause winbind goes offline for a very long time,
+ * and then goes online again. ticket expired, renew failed.
+ * This happens when machine are put to sleep for a long time,
+ * but shorter than entry->renew_util.
+ * NB
+ * Looks like the KDC is reachable, we want to rekinit as soon as
+ * possible instead of waiting some time later. */
+ if ((ret == KRB5KRB_AP_ERR_TKT_EXPIRED)
+ || (ret == KRB5_FCC_NOFILE)) goto rekinit;
+
return;
}
done:
+ /* in cases that ticket will be unrenewable soon, we don't try to renew ticket
+ * but try to regain ticket if it is possible */
+ if (entry->renew_until && expire_time
+ && (entry->renew_until <= expire_time)) {
+ /* try to regain ticket 10 seconds beforre expiration */
+ expire_time -= 10;
+ add_krb5_ticket_gain_handler_event(entry, timeval_set(expire_time, 0));
+ return;
+ }
+ if (!entry->refresh_time) {
+ entry->refresh_time = new_start;
+ }
entry->event = event_add_timed(winbind_event_context(), entry,
timeval_set(new_start, 0),
"krb5_ticket_refresh_handler",
@@ -239,6 +389,9 @@ static void krb5_ticket_gain_handler(struct event_context *event_ctx,
DEBUG(3,("krb5_ticket_gain_handler: "
"could not kinit: %s\n",
error_message(ret)));
+ /* evil. If we cannot do it, destroy any the __maybe__
+ * __existing__ ticket */
+ ads_kdestroy(entry->ccname);
goto retry_later;
}
@@ -249,15 +402,14 @@ static void krb5_ticket_gain_handler(struct event_context *event_ctx,
goto got_ticket;
retry_later:
-
+
+#if defined(DEBUG_KRB5_TKT_REGAIN)
+ t = timeval_set(time(NULL) + 30, 0);
+#else
t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0);
+#endif
--
Samba Shared Repository
More information about the samba-cvs
mailing list