+ struct winbindd_child *child;
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->pid == pid) {
+ break;
+ }
+ }
+
+ if (child == NULL) {
+ DEBUG(0, ("Unknown child %d died!\n", pid));
+ return;
+ }
+
+ remove_fd_event(&child->event);
+ close(child->event.fd);
+ child->event.fd = 0;
+ child->event.flags = 0;
+ child->pid = 0;
+
+ schedule_async_request(child);
+}
+
+/* Ensure any negative cache entries with the netbios or realm names are removed. */
+
+void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
+{
+ flush_negative_conn_cache_for_domain(domain->name);
+ if (*domain->alt_name) {
+ flush_negative_conn_cache_for_domain(domain->alt_name);
+ }
+}
+
+/* Set our domains as offline and forward the offline message to our children. */
+
+void winbind_msg_offline(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+ struct winbindd_domain *domain;
+
+ DEBUG(10,("winbind_msg_offline: got offline message.\n"));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("winbind_msg_offline: rejecting offline message.\n"));
+ return;
+ }
+
+ /* Set our global state as offline. */
+ if (!set_global_winbindd_state_offline()) {
+ DEBUG(10,("winbind_msg_offline: offline request failed.\n"));
+ return;
+ }
+
+ /* Set all our domains as offline. */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ DEBUG(5,("winbind_msg_offline: marking %s offline.\n", domain->name));
+ set_domain_offline(domain);
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ /* Don't send message to idmap child. We've already
+ done so above. */
+ if (!child->domain || (child == idmap_child())) {
+ continue;
+ }
+
+ /* Or internal domains (this should not be possible....) */
+ if (child->domain->internal) {
+ continue;
+ }
+
+ /* Each winbindd child should only process requests for one domain - make sure
+ we only set it online / offline for that domain. */
+
+ DEBUG(10,("winbind_msg_offline: sending message to pid %u for domain %s.\n",
+ (unsigned int)child->pid, domain->name ));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_OFFLINE,
+ (uint8 *)child->domain->name,
+ strlen(child->domain->name)+1);
+ }
+}
+
+/* Set our domains as online and forward the online message to our children. */
+
+void winbind_msg_online(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+ struct winbindd_domain *domain;
+
+ DEBUG(10,("winbind_msg_online: got online message.\n"));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("winbind_msg_online: rejecting online message.\n"));
+ return;
+ }
+
+ /* Set our global state as online. */
+ set_global_winbindd_state_online();
+
+ smb_nscd_flush_user_cache();
+ smb_nscd_flush_group_cache();
+
+ /* Set all our domains as online. */
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ DEBUG(5,("winbind_msg_online: requesting %s to go online.\n", domain->name));
+
+ winbindd_flush_negative_conn_cache(domain);
+ set_domain_online_request(domain);
+
+ /* Send an online message to the idmap child when our
+ primary domain comes back online */
+
+ if ( domain->primary ) {
+ struct winbindd_child *idmap = idmap_child();
+
+ if ( idmap->pid != 0 ) {
+ messaging_send_buf(msg_ctx,
+ pid_to_procid(idmap->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)domain->name,
+ strlen(domain->name)+1);
+ }
+
+ }
+ }
+
+ for (child = children; child != NULL; child = child->next) {
+ /* Don't send message to idmap child. */
+ if (!child->domain || (child == idmap_child())) {
+ continue;
+ }
+
+ /* Or internal domains (this should not be possible....) */
+ if (child->domain->internal) {
+ continue;
+ }
+
+ /* Each winbindd child should only process requests for one domain - make sure
+ we only set it online / offline for that domain. */
+
+ DEBUG(10,("winbind_msg_online: sending message to pid %u for domain %s.\n",
+ (unsigned int)child->pid, child->domain->name ));
+
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_ONLINE,
+ (uint8 *)child->domain->name,
+ strlen(child->domain->name)+1);
+ }
+}
+
+/* Forward the online/offline messages to our children. */
+void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_child *child;
+
+ DEBUG(10,("winbind_msg_onlinestatus: got onlinestatus message.\n"));
+
+ for (child = children; child != NULL; child = child->next) {
+ if (child->domain && child->domain->primary) {
+ DEBUG(10,("winbind_msg_onlinestatus: "
+ "sending message to pid %u of primary domain.\n",
+ (unsigned int)child->pid));
+ messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+ MSG_WINBIND_ONLINESTATUS,
+ (uint8 *)data->data,
+ data->length);
+ break;
+ }
+ }
+}
+
+
+static void account_lockout_policy_handler(struct event_context *ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
+{
+ struct winbindd_child *child =
+ (struct winbindd_child *)private_data;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct winbindd_methods *methods;
+ SAM_UNK_INFO_12 lockout_policy;
+ NTSTATUS result;
+
+ DEBUG(10,("account_lockout_policy_handler called\n"));
+
+ if (child->lockout_policy_event) {
+ TALLOC_FREE(child->lockout_policy_event);
+ }
+
+ if ( !winbindd_can_contact_domain( child->domain ) ) {
+ DEBUG(10,("account_lockout_policy_handler: Removing myself since I "
+ "do not have an incoming trust to domain %s\n",
+ child->domain->name));
+
+ return;
+ }
+
+ methods = child->domain->methods;
+
+ mem_ctx = talloc_init("account_lockout_policy_handler ctx");
+ if (!mem_ctx) {
+ result = NT_STATUS_NO_MEMORY;
+ } else {
+ result = methods->lockout_policy(child->domain, mem_ctx, &lockout_policy);
+ }
+
+ talloc_destroy(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("account_lockout_policy_handler: lockout_policy failed error %s\n",
+ nt_errstr(result)));
+ }
+
+ 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);
+}
+
+/* Deal with a request to go offline. */
+
+static void child_msg_offline(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("child_msg_offline received for domain %s.\n", domainname));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("child_msg_offline: rejecting offline message.\n"));
+ return;
+ }
+
+ /* Mark the requested domain offline. */
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ if (strequal(domain->name, domainname)) {
+ DEBUG(5,("child_msg_offline: marking %s offline.\n", domain->name));
+ set_domain_offline(domain);
+ }
+ }
+}
+
+/* Deal with a request to go online. */
+
+static void child_msg_online(struct messaging_context *msg,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+ const char *domainname = (const char *)data->data;
+
+ if (data->data == NULL || data->length == 0) {
+ return;
+ }
+
+ DEBUG(5,("child_msg_online received for domain %s.\n", domainname));
+
+ if (!lp_winbind_offline_logon()) {
+ DEBUG(10,("child_msg_online: rejecting online message.\n"));
+ return;
+ }
+
+ /* Set our global state as online. */
+ set_global_winbindd_state_online();
+
+ /* Try and mark everything online - delete any negative cache entries
+ to force a reconnect now. */
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ if (strequal(domain->name, domainname)) {
+ DEBUG(5,("child_msg_online: requesting %s to go online.\n", domain->name));
+ winbindd_flush_negative_conn_cache(domain);
+ set_domain_online_request(domain);
+ }
+ }
+}
+
+static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
+{
+ struct winbindd_domain *domain;
+ char *buf = NULL;
+
+ if ((buf = talloc_asprintf(mem_ctx, "global:%s ",
+ get_global_winbindd_state_offline() ?
+ "Offline":"Online")) == NULL) {
+ return NULL;
+ }
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if ((buf = talloc_asprintf_append(buf, "%s:%s ",
+ domain->name,
+ domain->online ?
+ "Online":"Offline")) == NULL) {
+ return NULL;
+ }
+ }
+
+ buf = talloc_asprintf_append(buf, "\n");
+
+ DEBUG(5,("collect_onlinestatus: %s", buf));
+
+ return buf;
+}
+
+static void child_msg_onlinestatus(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ TALLOC_CTX *mem_ctx;
+ const char *message;
+ struct server_id *sender;
+
+ DEBUG(5,("winbind_msg_onlinestatus received.\n"));
+
+ if (!data->data) {
+ return;
+ }
+
+ sender = (struct server_id *)data->data;
+
+ mem_ctx = talloc_init("winbind_msg_onlinestatus");
+ if (mem_ctx == NULL) {
+ return;
+ }