diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2009-01-05 18:01:04 +0100 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2009-01-05 18:01:04 +0100 |
commit | 37e6849d451c4f49c6a0c96a78a5ef81baab83d4 (patch) | |
tree | d1e443f66fa367340ef04d39349e50e7100b9b5f /source3/winbindd | |
parent | de7dc2cec059305d28cc75a5347bfd88f3cb5c95 (diff) | |
parent | 0581094023ba5e561184a2ea57f6e905161de978 (diff) | |
download | samba-37e6849d451c4f49c6a0c96a78a5ef81baab83d4.tar.gz samba-37e6849d451c4f49c6a0c96a78a5ef81baab83d4.tar.bz2 samba-37e6849d451c4f49c6a0c96a78a5ef81baab83d4.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3/winbindd')
-rw-r--r-- | source3/winbindd/winbindd.c | 38 | ||||
-rw-r--r-- | source3/winbindd/winbindd.h | 43 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cm.c | 52 | ||||
-rw-r--r-- | source3/winbindd/winbindd_cred_cache.c | 318 | ||||
-rw-r--r-- | source3/winbindd/winbindd_dual.c | 82 | ||||
-rw-r--r-- | source3/winbindd/winbindd_proto.h | 10 |
6 files changed, 411 insertions, 132 deletions
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c index e881ab412e..cf1dbf6f72 100644 --- a/source3/winbindd/winbindd.c +++ b/source3/winbindd/winbindd.c @@ -415,16 +415,16 @@ static void process_request(struct winbindd_cli_state *state) /* * A list of file descriptors being monitored by select in the main processing - * loop. fd_event->handler is called whenever the socket is readable/writable. + * loop. winbindd_fd_event->handler is called whenever the socket is readable/writable. */ -static struct fd_event *fd_events = NULL; +static struct winbindd_fd_event *fd_events = NULL; -void add_fd_event(struct fd_event *ev) +void add_fd_event(struct winbindd_fd_event *ev) { - struct fd_event *match; + struct winbindd_fd_event *match; - /* only add unique fd_event structs */ + /* only add unique winbindd_fd_event structs */ for (match=fd_events; match; match=match->next ) { #ifdef DEVELOPER @@ -438,17 +438,17 @@ void add_fd_event(struct fd_event *ev) DLIST_ADD(fd_events, ev); } -void remove_fd_event(struct fd_event *ev) +void remove_fd_event(struct winbindd_fd_event *ev) { DLIST_REMOVE(fd_events, ev); } /* - * Handler for fd_events to complete a read/write request, set up by + * Handler for winbindd_fd_events to complete a read/write request, set up by * setup_async_read/setup_async_write. */ -static void rw_callback(struct fd_event *event, int flags) +static void rw_callback(struct winbindd_fd_event *event, int flags) { size_t todo; ssize_t done = 0; @@ -489,11 +489,11 @@ static void rw_callback(struct fd_event *event, int flags) } /* - * Request an async read/write on a fd_event structure. (*finished) is called + * Request an async read/write on a winbindd_fd_event structure. (*finished) is called * when the request is completed or an error had occurred. */ -void setup_async_read(struct fd_event *event, void *data, size_t length, +void setup_async_read(struct winbindd_fd_event *event, void *data, size_t length, void (*finished)(void *private_data, bool success), void *private_data) { @@ -507,7 +507,7 @@ void setup_async_read(struct fd_event *event, void *data, size_t length, event->flags = EVENT_FD_READ; } -void setup_async_write(struct fd_event *event, void *data, size_t length, +void setup_async_write(struct winbindd_fd_event *event, void *data, size_t length, void (*finished)(void *private_data, bool success), void *private_data) { @@ -826,7 +826,7 @@ void winbind_check_sigterm(bool is_parent) static void process_loop(void) { struct winbindd_cli_state *state; - struct fd_event *ev; + struct winbindd_fd_event *ev; fd_set r_fds, w_fds; int maxfd, listen_sock, listen_priv_sock, selret; struct timeval timeout, ev_timeout; @@ -865,6 +865,13 @@ static void process_loop(void) timeout.tv_usec = 0; /* Check for any event timeouts. */ + { + struct timeval now; + GetTimeOfDay(&now); + + event_add_to_select_args(winbind_event_context(), &now, + &r_fds, &w_fds, &ev_timeout, &maxfd); + } if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) { timeout = timeval_min(&timeout, &ev_timeout); } @@ -918,9 +925,11 @@ static void process_loop(void) /* selret > 0 */ + run_events(winbind_event_context(), selret, &r_fds, &w_fds); + ev = fd_events; while (ev != NULL) { - struct fd_event *next = ev->next; + struct winbindd_fd_event *next = ev->next; int flags = 0; if (FD_ISSET(ev->fd, &r_fds)) flags |= EVENT_FD_READ; @@ -1191,7 +1200,8 @@ int main(int argc, char **argv, char **envp) TimeInit(); - if (!reinit_after_fork(winbind_messaging_context(), false)) { + if (!reinit_after_fork(winbind_messaging_context(), + winbind_event_context(), false)) { DEBUG(0,("reinit_after_fork() failed\n")); exit(1); } diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 04b0b39f81..d8e6ec4c7f 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -39,15 +39,11 @@ #define WB_REPLACE_CHAR '_' -/* bits for fd_event.flags */ -#define EVENT_FD_READ 1 -#define EVENT_FD_WRITE 2 - -struct fd_event { - struct fd_event *next, *prev; +struct winbindd_fd_event { + struct winbindd_fd_event *next, *prev; int fd; int flags; /* see EVENT_FD_* flags */ - void (*handler)(struct fd_event *fde, int flags); + void (*handler)(struct winbindd_fd_event *fde, int flags); void *data; size_t length, done; void (*finished)(void *private_data, bool success); @@ -65,7 +61,7 @@ struct sid_ctr { struct winbindd_cli_state { struct winbindd_cli_state *prev, *next; /* Linked list pointers */ int sock; /* Open socket from client */ - struct fd_event fd_event; + struct winbindd_fd_event fd_event; pid_t pid; /* pid of client */ bool finished; /* Can delete from list */ bool write_extra_data; /* Write extra_data field */ @@ -151,7 +147,7 @@ struct winbindd_child { struct winbindd_domain *domain; char *logfilename; - struct fd_event event; + struct winbindd_fd_event event; struct timed_event *lockout_policy_event; struct timed_event *machine_password_change_event; struct winbindd_async_request *requests; @@ -377,7 +373,34 @@ enum ent_type { LIST_USERS = 0, LIST_GROUPS, }; - + +struct WINBINDD_MEMORY_CREDS { + struct WINBINDD_MEMORY_CREDS *next, *prev; + const char *username; /* lookup key. */ + uid_t uid; + int ref_count; + size_t len; + uint8_t *nt_hash; /* Base pointer for the following 2 */ + uint8_t *lm_hash; + char *pass; +}; + +struct WINBINDD_CCACHE_ENTRY { + struct WINBINDD_CCACHE_ENTRY *next, *prev; + const char *principal_name; + const char *ccname; + const char *service; + const char *username; + const char *realm; + struct WINBINDD_MEMORY_CREDS *cred_ptr; + int ref_count; + uid_t uid; + time_t create_time; + time_t renew_until; + time_t refresh_time; + struct timed_event *event; +}; + #include "winbindd/winbindd_proto.h" #define WINBINDD_ESTABLISH_LOOP 30 diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 3135b6a2a3..e5e3565604 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -212,7 +212,8 @@ 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(), true)) { + if (!reinit_after_fork(winbind_messaging_context(), + winbind_event_context(), true)) { DEBUG(0,("reinit_after_fork() failed\n")); messaging_send_buf(winbind_messaging_context(), pid_to_procid(parent_pid), @@ -271,7 +272,7 @@ static bool fork_child_dc_connect(struct winbindd_domain *domain) static void check_domain_online_handler(struct event_context *ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct winbindd_domain *domain = @@ -285,7 +286,7 @@ static void check_domain_online_handler(struct event_context *ctx, /* Are we still in "startup" mode ? */ - if (domain->startup && (now->tv_sec > domain->startup_time + 30)) { + if (domain->startup && (now.tv_sec > domain->startup_time + 30)) { /* No longer in "startup" mode. */ DEBUG(10,("check_domain_online_handler: domain %s no longer in 'startup' mode.\n", domain->name )); @@ -366,7 +367,6 @@ void set_domain_offline(struct winbindd_domain *domain) domain->check_online_event = event_add_timed(winbind_event_context(), NULL, timeval_current_ofs(domain->check_online_timeout,0), - "check_domain_online_handler", check_domain_online_handler, domain); @@ -402,8 +402,6 @@ void set_domain_offline(struct winbindd_domain *domain) static void set_domain_online(struct winbindd_domain *domain) { - struct timeval now; - DEBUG(10,("set_domain_online: called for domain %s\n", domain->name )); @@ -422,9 +420,7 @@ 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; @@ -497,6 +493,15 @@ 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. @@ -505,29 +510,20 @@ void set_domain_online_request(struct winbindd_domain *domain) 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; + TALLOC_FREE(domain->check_online_event); - tev.tv_sec += 5; + domain->check_online_event = event_add_timed(winbind_event_context(), + NULL, + tev, + check_domain_online_handler, + domain); - set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev); + /* 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/source3/winbindd/winbindd_cred_cache.c b/source3/winbindd/winbindd_cred_cache.c index 311b1d1822..900f9acdfa 100644 --- a/source3/winbindd/winbindd_cred_cache.c +++ b/source3/winbindd/winbindd_cred_cache.c @@ -34,6 +34,10 @@ #define MAX_CCACHES 100 static struct WINBINDD_CCACHE_ENTRY *ccache_list; +static void krb5_ticket_gain_handler(struct event_context *, + struct timed_event *, + struct timeval, + void *); /* The Krb5 ticket refresh handler should be scheduled at one-half of the period from now till the tkt @@ -71,13 +75,27 @@ static int ccache_entry_count(void) return i; } +void ccache_remove_all_after_fork(void) +{ + struct WINBINDD_CCACHE_ENTRY *cur, *next; + + for (cur = ccache_list; cur; cur = next) { + next = cur->next; + DLIST_REMOVE(ccache_list, cur); + TALLOC_FREE(cur->event); + TALLOC_FREE(cur); + } + + return; +} + /**************************************************************** Do the work of refreshing the ticket. ****************************************************************/ static void krb5_ticket_refresh_handler(struct event_context *event_ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct WINBINDD_CCACHE_ENTRY *entry = @@ -85,6 +103,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 +116,83 @@ 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 */ + entry->event = event_add_timed(winbind_event_context(), + entry, + timeval_set(new_start, 0), + krb5_ticket_gain_handler, + entry); + 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 +204,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,24 +216,73 @@ 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 */ + entry->event = event_add_timed(winbind_event_context(), + entry, + timeval_set(new_start, 0), + krb5_ticket_gain_handler, + entry); + 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; + entry->event = event_add_timed(winbind_event_context(), entry, + timeval_set(expire_time, 0), + krb5_ticket_gain_handler, + entry); + return; + } + if (entry->refresh_time == 0) { + entry->refresh_time = new_start; + } entry->event = event_add_timed(winbind_event_context(), entry, timeval_set(new_start, 0), - "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, entry); @@ -187,7 +295,7 @@ done: static void krb5_ticket_gain_handler(struct event_context *event_ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct WINBINDD_CCACHE_ENTRY *entry = @@ -239,6 +347,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,13 +360,17 @@ 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 + entry->refresh_time = 0; entry->event = event_add_timed(winbind_event_context(), entry, t, - "krb5_ticket_gain_handler", krb5_ticket_gain_handler, entry); @@ -269,10 +384,12 @@ static void krb5_ticket_gain_handler(struct event_context *event_ctx, t = timeval_set(KRB5_EVENT_REFRESH_TIME(entry->refresh_time), 0); #endif + if (entry->refresh_time == 0) { + entry->refresh_time = t.tv_sec; + } entry->event = event_add_timed(winbind_event_context(), entry, t, - "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, entry); @@ -280,6 +397,43 @@ static void krb5_ticket_gain_handler(struct event_context *event_ctx, #endif } +void ccache_regain_all_now(void) +{ + struct WINBINDD_CCACHE_ENTRY *cur; + struct timeval t = timeval_current(); + + for (cur = ccache_list; cur; cur = cur->next) { + struct timed_event *new_event; + + /* + * if refresh_time is 0, we know that the + * the event has the krb5_ticket_gain_handler + */ + if (cur->refresh_time == 0) { + new_event = event_add_timed(winbind_event_context(), + cur, + t, + krb5_ticket_gain_handler, + cur); + } else { + new_event = event_add_timed(winbind_event_context(), + cur, + t, + krb5_ticket_refresh_handler, + cur); + } + + if (!new_event) { + continue; + } + + TALLOC_FREE(cur->event); + cur->event = new_event; + } + + return; +} + /**************************************************************** Check if an ccache entry exists. ****************************************************************/ @@ -331,6 +485,10 @@ NTSTATUS add_ccache_to_list(const char *princ_name, { struct WINBINDD_CCACHE_ENTRY *entry = NULL; struct timeval t; + NTSTATUS ntret; +#ifdef HAVE_KRB5 + int ret; +#endif if ((username == NULL && princ_name == NULL) || ccname == NULL || uid < 0) { @@ -343,6 +501,28 @@ NTSTATUS add_ccache_to_list(const char *princ_name, return NT_STATUS_NO_MORE_ENTRIES; } + /* If it is cached login, destroy krb5 ticket + * to avoid surprise. */ +#ifdef HAVE_KRB5 + if (postponed_request) { + /* ignore KRB5_FCC_NOFILE error here */ + ret = ads_kdestroy(ccname); + if (ret == KRB5_FCC_NOFILE) { + ret = 0; + } + if (ret) { + DEBUG(0, ("add_ccache_to_list: failed to destroy " + "user krb5 ccache %s with %s\n", ccname, + error_message(ret))); + return krb5_to_nt_status(ret); + } else { + DEBUG(10, ("add_ccache_to_list: successfully destroyed " + "krb5 ccache %s for user %s\n", ccname, + username)); + } + } +#endif + /* Reference count old entries */ entry = get_ccache_by_username(username); if (entry) { @@ -355,7 +535,51 @@ NTSTATUS add_ccache_to_list(const char *princ_name, "ref count on entry %s is now %d\n", username, entry->ref_count)); /* FIXME: in this case we still might want to have a krb5 cred - * event handler created - gd*/ + * event handler created - gd + * Add ticket refresh handler here */ + + if (!lp_winbind_refresh_tickets() || renew_until <= 0) { + return NT_STATUS_OK; + } + + if (!entry->event) { + if (postponed_request) { + t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); + entry->event = event_add_timed(winbind_event_context(), + entry, + t, + krb5_ticket_gain_handler, + entry); + } else { + /* Renew at 1/2 the ticket expiration time */ +#if defined(DEBUG_KRB5_TKT_RENEWAL) + t = timeval_set(time(NULL)+30, 0); +#else + t = timeval_set(KRB5_EVENT_REFRESH_TIME(ticket_end), 0); +#endif + entry->event = event_add_timed(winbind_event_context(), + entry, + t, + krb5_ticket_refresh_handler, + entry); + } + + if (!entry->event) { + ntret = remove_ccache(username); + if (!NT_STATUS_IS_OK(ntret)) { + DEBUG(0, ("add_ccache_to_list: Failed to remove krb5 " + "ccache %s for user %s\n", entry->ccname, + entry->username)); + DEBUG(0, ("add_ccache_to_list: error is %s\n", + nt_errstr(ntret))); + return ntret; + } + return NT_STATUS_NO_MEMORY; + } + + DEBUG(10,("add_ccache_to_list: added krb5_ticket handler\n")); + } + return NT_STATUS_OK; } @@ -406,10 +630,10 @@ NTSTATUS add_ccache_to_list(const char *princ_name, if (postponed_request) { t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); + entry->refresh_time = 0; entry->event = event_add_timed(winbind_event_context(), entry, t, - "krb5_ticket_gain_handler", krb5_ticket_gain_handler, entry); } else { @@ -419,10 +643,12 @@ NTSTATUS add_ccache_to_list(const char *princ_name, #else t = timeval_set(KRB5_EVENT_REFRESH_TIME(ticket_end), 0); #endif + if (entry->refresh_time == 0) { + entry->refresh_time = t.tv_sec; + } entry->event = event_add_timed(winbind_event_context(), entry, t, - "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, entry); } diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 4f1e92ed7c..1499141c34 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -175,7 +175,7 @@ static void async_main_request_sent(void *private_data, bool success) static void async_request_timeout_handler(struct event_context *ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct winbindd_async_request *state = @@ -247,7 +247,6 @@ static void async_request_sent(void *private_data_data, bool success) state->reply_timeout_event = event_add_timed(winbind_event_context(), NULL, timeval_current_ofs(300,0), - "async_request_timeout", async_request_timeout_handler, state); if (!state->reply_timeout_event) { @@ -827,7 +826,7 @@ void winbind_msg_dump_domain_list(struct messaging_context *msg_ctx, static void account_lockout_policy_handler(struct event_context *ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct winbindd_child *child = @@ -866,7 +865,6 @@ static void account_lockout_policy_handler(struct event_context *ctx, child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL, timeval_current_ofs(3600, 0), - "account_lockout_policy_handler", account_lockout_policy_handler, child); } @@ -919,7 +917,7 @@ static bool calculate_next_machine_pwd_change(const char *domain, static void machine_password_change_handler(struct event_context *ctx, struct timed_event *te, - const struct timeval *now, + struct timeval now, void *private_data) { struct winbindd_child *child = @@ -971,7 +969,6 @@ static void machine_password_change_handler(struct event_context *ctx, child->machine_password_change_event = event_add_timed(winbind_event_context(), NULL, next_change, - "machine_password_change_handler", machine_password_change_handler, child); } @@ -985,6 +982,7 @@ static void child_msg_offline(struct messaging_context *msg, DATA_BLOB *data) { struct winbindd_domain *domain; + struct winbindd_domain *primary_domain = NULL; const char *domainname = (const char *)data->data; if (data->data == NULL || data->length == 0) { @@ -998,6 +996,8 @@ static void child_msg_offline(struct messaging_context *msg, return; } + primary_domain = find_our_domain(); + /* Mark the requested domain offline. */ for (domain = domain_list(); domain; domain = domain->next) { @@ -1007,6 +1007,11 @@ static void child_msg_offline(struct messaging_context *msg, if (strequal(domain->name, domainname)) { DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name)); set_domain_offline(domain); + /* we are in the trusted domain, set the primary domain + * offline too */ + if (domain != primary_domain) { + set_domain_offline(primary_domain); + } } } } @@ -1020,6 +1025,7 @@ static void child_msg_online(struct messaging_context *msg, DATA_BLOB *data) { struct winbindd_domain *domain; + struct winbindd_domain *primary_domain = NULL; const char *domainname = (const char *)data->data; if (data->data == NULL || data->length == 0) { @@ -1033,6 +1039,8 @@ static void child_msg_online(struct messaging_context *msg, return; } + primary_domain = find_our_domain(); + /* Set our global state as online. */ set_global_winbindd_state_online(); @@ -1047,6 +1055,16 @@ static void child_msg_online(struct messaging_context *msg, DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name)); winbindd_flush_negative_conn_cache(domain); set_domain_online_request(domain); + + /* we can be in trusted domain, which will contact primary domain + * we have to bring primary domain online in trusted domain process + * see, winbindd_dual_pam_auth() --> winbindd_dual_pam_auth_samlogon() + * --> contact_domain = find_our_domain() + * */ + if (domain != primary_domain) { + winbindd_flush_negative_conn_cache(primary_domain); + set_domain_online_request(primary_domain); + } } } } @@ -1177,13 +1195,18 @@ static bool fork_domain_child(struct winbindd_child *child) state.sock = fdpair[0]; close(fdpair[1]); - if (!reinit_after_fork(winbind_messaging_context(), true)) { + if (!reinit_after_fork(winbind_messaging_context(), + winbind_event_context(), true)) { DEBUG(0,("reinit_after_fork() failed\n")); _exit(0); } close_conns_after_fork(); + /* Ensure we're not handling an event inherited from + our parent. */ + ccache_remove_all_after_fork(); + if (!override_logfile) { lp_set_logfile(child->logfilename); reopen_logs(); @@ -1219,33 +1242,34 @@ static bool fork_domain_child(struct winbindd_child *child) messaging_register(winbind_messaging_context(), NULL, MSG_DEBUG, debug_message); + primary_domain = find_our_domain(); + + if (primary_domain == NULL) { + smb_panic("no primary domain found"); + } + /* we have destroy all time event in reinit_after_fork() + * set check_online_event to NULL */ + for (domain = domain_list(); domain; domain = domain->next) { + domain->check_online_event = NULL; + } + /* It doesn't matter if we allow cache login, + * try to bring domain online after fork. */ if ( child->domain ) { child->domain->startup = True; child->domain->startup_time = time(NULL); - } - - /* Ensure we have no pending check_online events other - than one for this domain or the primary domain. */ - - for (domain = domain_list(); domain; domain = domain->next) { - if (domain->primary) { - primary_domain = domain; - } - if ((domain != child->domain) && !domain->primary) { - TALLOC_FREE(domain->check_online_event); + /* we can be in primary domain or in trusted domain + * If we are in trusted domain, set the primary domain + * in start-up mode */ + if (!(child->domain->internal)) { + set_domain_online_request(child->domain); + if (!(child->domain->primary)) { + primary_domain->startup = True; + primary_domain->startup_time = time(NULL); + set_domain_online_request(primary_domain); + } } } - if (primary_domain == NULL) { - smb_panic("no primary domain found"); - } - - /* Ensure we're not handling an event inherited from - our parent. */ - - cancel_named_event(winbind_event_context(), - "krb5_ticket_refresh_handler"); - /* We might be in the idmap child...*/ if (child->domain && !(child->domain->internal) && lp_winbind_offline_logon()) { @@ -1266,7 +1290,6 @@ static bool fork_domain_child(struct winbindd_child *child) child->lockout_policy_event = event_add_timed( winbind_event_context(), NULL, timeval_zero(), - "account_lockout_policy_handler", account_lockout_policy_handler, child); } @@ -1281,7 +1304,6 @@ static bool fork_domain_child(struct winbindd_child *child) &next_change)) { child->machine_password_change_event = event_add_timed( winbind_event_context(), NULL, next_change, - "machine_password_change_handler", machine_password_change_handler, child); } diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 3869ac5771..32f057ad61 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -53,12 +53,12 @@ bool register_message_flags(bool doreg, uint32 msg_flags); struct event_context *winbind_event_context(void); struct messaging_context *winbind_messaging_context(void); -void add_fd_event(struct fd_event *ev); -void remove_fd_event(struct fd_event *ev); -void setup_async_read(struct fd_event *event, void *data, size_t length, +void add_fd_event(struct winbindd_fd_event *ev); +void remove_fd_event(struct winbindd_fd_event *ev); +void setup_async_read(struct winbindd_fd_event *event, void *data, size_t length, void (*finished)(void *private_data, bool success), void *private_data); -void setup_async_write(struct fd_event *event, void *data, size_t length, +void setup_async_write(struct winbindd_fd_event *event, void *data, size_t length, void (*finished)(void *private_data, bool success), void *private_data); void request_error(struct winbindd_cli_state *state); @@ -243,6 +243,8 @@ bool ccache_entry_exists(const char *username); bool ccache_entry_identical(const char *username, uid_t uid, const char *ccname); +void ccache_remove_all_after_fork(void); +void ccache_regain_all_now(void); NTSTATUS add_ccache_to_list(const char *princ_name, const char *ccname, const char *service, |