summaryrefslogtreecommitdiff
path: root/source3/winbindd
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2009-01-05 18:01:04 +0100
committerJelmer Vernooij <jelmer@samba.org>2009-01-05 18:01:04 +0100
commit37e6849d451c4f49c6a0c96a78a5ef81baab83d4 (patch)
treed1e443f66fa367340ef04d39349e50e7100b9b5f /source3/winbindd
parentde7dc2cec059305d28cc75a5347bfd88f3cb5c95 (diff)
parent0581094023ba5e561184a2ea57f6e905161de978 (diff)
downloadsamba-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.c38
-rw-r--r--source3/winbindd/winbindd.h43
-rw-r--r--source3/winbindd/winbindd_cm.c52
-rw-r--r--source3/winbindd/winbindd_cred_cache.c318
-rw-r--r--source3/winbindd/winbindd_dual.c82
-rw-r--r--source3/winbindd/winbindd_proto.h10
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,