summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/messages.h2
-rw-r--r--source3/nsswitch/winbindd_cm.c199
-rw-r--r--source3/nsswitch/winbindd_dual.c5
3 files changed, 183 insertions, 23 deletions
diff --git a/source3/include/messages.h b/source3/include/messages.h
index b0305373c0..7b948e012e 100644
--- a/source3/include/messages.h
+++ b/source3/include/messages.h
@@ -78,6 +78,8 @@
#define MSG_WINBIND_ONLINE 4003
#define MSG_WINBIND_OFFLINE 4004
#define MSG_WINBIND_ONLINESTATUS 4005
+#define MSG_WINBIND_TRY_TO_GO_ONLINE 4006
+#define MSG_WINBIND_FAILED_TO_GO_ONLINE 4007
/* Flags to classify messages - used in message_send_all() */
/* Sender will filter by flag. */
diff --git a/source3/nsswitch/winbindd_cm.c b/source3/nsswitch/winbindd_cm.c
index c0a6aeb85d..07360e85d5 100644
--- a/source3/nsswitch/winbindd_cm.c
+++ b/source3/nsswitch/winbindd_cm.c
@@ -67,31 +67,167 @@
extern struct winbindd_methods reconnect_methods;
+struct dc_name_ip {
+ fstring name;
+ struct in_addr ip;
+};
+
static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
static void set_dc_type_and_flags( struct winbindd_domain *domain );
+static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
+ struct dc_name_ip **dcs, int *num_dcs);
/****************************************************************
- If we're still offline, exponentially increase the timeout check.
+ Child failed to find DC's. Reschedule check.
****************************************************************/
-static void calc_new_online_timeout_check(struct winbindd_domain *domain)
+static void msg_failed_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
{
- int wbc = lp_winbind_cache_time();
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)buf;
- if (domain->startup) {
- domain->check_online_timeout = 10;
- } else if (domain->check_online_timeout < wbc) {
- domain->check_online_timeout = wbc;
- } else {
- uint32 new_to = domain->check_online_timeout * 3;
- if (new_to > (3*60*60)) {
- new_to = 3*60*60; /* 3 hours. */
+ if (buf == NULL || len == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_fail_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_fail_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* Reschedule the online check. */
+ set_domain_offline(domain);
+ break;
+ }
+ }
+}
+
+/****************************************************************
+ Actually cause a reconnect from a message.
+****************************************************************/
+
+static void msg_try_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)buf;
+
+ if (buf == NULL || len == 0) {
+ return;
+ }
+
+ DEBUG(5,("msg_try_to_go_online: received for domain %s.\n", domainname));
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+
+ if (strequal(domain->name, domainname)) {
+
+ if (domain->online) {
+ /* We're already online, ignore. */
+ DEBUG(5,("msg_try_to_go_online: domain %s "
+ "already online.\n", domainname));
+ continue;
+ }
+
+ /* This call takes care of setting the online
+ flag to true if we connected, or re-adding
+ the offline handler if false. Bypasses online
+ check so always does network calls. */
+
+ init_dc_connection_network(domain);
+ break;
}
- domain->check_online_timeout = new_to;
}
}
/****************************************************************
+ Fork a child to try and contact a DC. Do this as contacting a
+ DC requires blocking lookups and we don't want to block our
+ parent.
+****************************************************************/
+
+static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
+{
+ extern BOOL override_logfile;
+ struct dc_name_ip *dcs = NULL;
+ int num_dcs = 0;
+ TALLOC_CTX *mem_ctx = NULL;
+ pid_t child_pid;
+ pid_t parent_pid = sys_getpid();
+
+ /* Stop zombies */
+ CatchChild();
+
+ message_block();
+
+ child_pid = sys_fork();
+
+ if (child_pid == -1) {
+ DEBUG(0, ("fork_child_dc_connect: Could not fork: %s\n", strerror(errno)));
+ message_unblock();
+ return False;
+ }
+
+ if (child_pid != 0) {
+ /* Parent */
+ message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,msg_try_to_go_online);
+ message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,msg_failed_to_go_online);
+ message_unblock();
+ return True;
+ }
+
+ /* Child. */
+
+ /* Leave messages blocked - we will never process one. */
+
+ /* tdb needs special fork handling */
+ if (tdb_reopen_all(1) == -1) {
+ DEBUG(0,("tdb_reopen_all failed.\n"));
+ _exit(0);
+ }
+
+ close_conns_after_fork();
+
+ if (!override_logfile) {
+ reopen_logs();
+ }
+
+ mem_ctx = talloc_init("fork_child_dc_connect");
+ if (!mem_ctx) {
+ DEBUG(0,("talloc_init failed.\n"));
+ _exit(0);
+ }
+
+ if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
+ /* Still offline ? Can't find DC's. */
+ message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_FAILED_TO_GO_ONLINE,
+ domain->name,
+ strlen(domain->name)+1, False);
+ _exit(0);
+ }
+
+ /* We got a DC. Send a message to our parent to get it to
+ try and do the same. */
+
+ message_send_pid(pid_to_procid(parent_pid), MSG_WINBIND_TRY_TO_GO_ONLINE,
+ domain->name,
+ strlen(domain->name)+1, False);
+ _exit(0);
+}
+
+/****************************************************************
Handler triggered if we're offline to try and detect a DC.
****************************************************************/
@@ -127,12 +263,32 @@ static void check_domain_online_handler(struct timed_event *te,
return;
}
- /* This call takes care of setting the online
- flag to true if we connected, or re-adding
- the offline handler if false. Bypasses online
- check so always does network calls. */
+ /* Fork a child to test if it can contact a DC.
+ If it can then send ourselves a message to
+ cause a reconnect. */
- init_dc_connection_network(domain);
+ fork_child_dc_connect(domain);
+}
+
+/****************************************************************
+ If we're still offline, exponentially increase the timeout check.
+****************************************************************/
+
+static void calc_new_online_timeout_check(struct winbindd_domain *domain)
+{
+ int wbc = lp_winbind_cache_time();
+
+ if (domain->startup) {
+ domain->check_online_timeout = 10;
+ } else if (domain->check_online_timeout < wbc) {
+ domain->check_online_timeout = wbc;
+ } else {
+ uint32 new_to = domain->check_online_timeout * 3;
+ if (new_to > (3*60*60)) {
+ new_to = 3*60*60; /* 3 hours. */
+ }
+ domain->check_online_timeout = new_to;
+ }
}
/****************************************************************
@@ -244,6 +400,10 @@ static void set_domain_online(struct winbindd_domain *domain)
TALLOC_FREE(domain->check_online_event);
}
+ /* Ensure we ignore any pending child messages. */
+ message_deregister(MSG_WINBIND_TRY_TO_GO_ONLINE);
+ message_deregister(MSG_WINBIND_FAILED_TO_GO_ONLINE);
+
domain->online = True;
}
@@ -662,11 +822,6 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
return result;
}
-struct dc_name_ip {
- fstring name;
- struct in_addr ip;
-};
-
static BOOL add_one_dc_unique(TALLOC_CTX *mem_ctx, const char *domain_name,
const char *dcname, struct in_addr ip,
struct dc_name_ip **dcs, int *num)
diff --git a/source3/nsswitch/winbindd_dual.c b/source3/nsswitch/winbindd_dual.c
index 70af8333c5..a61b158c24 100644
--- a/source3/nsswitch/winbindd_dual.c
+++ b/source3/nsswitch/winbindd_dual.c
@@ -769,7 +769,10 @@ static BOOL fork_domain_child(struct winbindd_child *child)
}
ZERO_STRUCT(state);
- state.pid = getpid();
+ state.pid = sys_getpid();
+
+ /* Stop zombies */
+ CatchChild();
/* Ensure we don't process messages whilst we're
changing the disposition for the child. */