r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / nsswitch / winbindd_dual.c
index 0c8491084d4b2ab10428e30838a07710b5ed5716..92e5782fa38d6c97e6b71b9aa9523f82b08b575b 100644 (file)
@@ -8,7 +8,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -17,8 +17,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 /*
@@ -97,6 +96,8 @@ struct winbindd_async_request {
        struct winbindd_response *response;
        void (*continuation)(void *private_data, BOOL success);
        struct timed_event *reply_timeout_event;
+       pid_t child_pid; /* pid of the child we're waiting on. Used to detect
+                           a restart of the child (child->pid != child_pid). */
        void *private_data;
 };
 
@@ -174,34 +175,51 @@ static void async_request_timeout_handler(struct event_context *ctx,
        struct winbindd_async_request *state =
                talloc_get_type_abort(private_data, struct winbindd_async_request);
 
-       /* Deal with the reply - set to error. */
+       DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
+               "Closing connection to it.\n",
+               state->child_pid ));
 
+       /* Deal with the reply - set to error. */
        async_reply_recv(private_data, False);
+}
 
-       /* 
-        * Close the socket to the child. Should cause the
       * child to exit.
-        */
+/**************************************************************
+ Common function called on both async send and recv fail.
Cleans up the child and schedules the next request.
+**************************************************************/
 
-       DEBUG(0,("async_request_timeout_handler: child pid %u is not responding. "
-               "Closing connection to it.\n",
-               state->child->pid ));
+static void async_request_fail(struct winbindd_async_request *state)
+{
+       DLIST_REMOVE(state->child->requests, state);
+
+       TALLOC_FREE(state->reply_timeout_event);
+
+       SMB_ASSERT(state->child_pid != (pid_t)0);
 
-       winbind_child_died(state->child->pid);
+       /* If not already reaped, send kill signal to child. */
+       if (state->child->pid == state->child_pid) {
+               kill(state->child_pid, SIGTERM);
+
+               /* 
+                * Close the socket to the child.
+                */
+               winbind_child_died(state->child_pid);
+       }
+
+       state->response->length = sizeof(struct winbindd_response);
+       state->response->result = WINBINDD_ERROR;
+       state->continuation(state->private_data, False);
 }
 
 static void async_request_sent(void *private_data_data, BOOL success)
 {
-       uint32_t timeout;
        struct winbindd_async_request *state =
                talloc_get_type_abort(private_data_data, struct winbindd_async_request);
 
        if (!success) {
-               DEBUG(5, ("Could not send async request\n"));
-
-               state->response->length = sizeof(struct winbindd_response);
-               state->response->result = WINBINDD_ERROR;
-               state->continuation(state->private_data, False);
+               DEBUG(5, ("Could not send async request to child pid %u\n",
+                       (unsigned int)state->child_pid ));
+               async_request_fail(state);
                return;
        }
 
@@ -212,35 +230,20 @@ static void async_request_sent(void *private_data_data, BOOL success)
                         sizeof(state->response->result),
                         async_reply_recv, state);
 
-       timeout = 30;
-
-       if (state->request->cmd == WINBINDD_PAM_AUTH
-           || state->request->cmd == WINBINDD_PAM_AUTH_CRAP ) {
-
-               /* 
-                * Normal timeouts are 30s, but auth requests may take a long
-                * time to timeout.
-                */
-
-               timeout = 300;
-       }
-
        /* 
-        * Set up a timeout of for the response. If we don't get it close the
-        * child socket and report failure.
+        * Set up a timeout of 300 seconds for the response.
+        * If we don't get it close the child socket and
+        * report failure.
         */
 
-       state->reply_timeout_event = event_add_timed(
-               winbind_event_context(),
-               NULL,
-               timeval_current_ofs(timeout,0),
-               "async_request_timeout",
-               async_request_timeout_handler,
-               state);
-
+       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) {
-               smb_panic("async_request_sent: failed to add timeout "
-                         "handler.\n");
+               smb_panic("async_request_sent: failed to add timeout handler.\n");
        }
 }
 
@@ -250,27 +253,23 @@ static void async_reply_recv(void *private_data, BOOL success)
                talloc_get_type_abort(private_data, struct winbindd_async_request);
        struct winbindd_child *child = state->child;
 
-       if (state->reply_timeout_event) {
-               TALLOC_FREE(state->reply_timeout_event);
-       }
+       TALLOC_FREE(state->reply_timeout_event);
 
        state->response->length = sizeof(struct winbindd_response);
 
        if (!success) {
-               DEBUG(5, ("Could not receive async reply\n"));
-
-               cache_cleanup_response(child->pid);
-               DLIST_REMOVE(child->requests, state);
+               DEBUG(5, ("Could not receive async reply from child pid %u\n",
+                       (unsigned int)state->child_pid ));
 
-               state->response->result = WINBINDD_ERROR;
-               state->continuation(state->private_data, False);
+               cache_cleanup_response(state->child_pid);
+               async_request_fail(state);
                return;
        }
 
-       SMB_ASSERT(cache_retrieve_response(child->pid,
+       SMB_ASSERT(cache_retrieve_response(state->child_pid,
                                           state->response));
 
-       cache_cleanup_response(child->pid);
+       cache_cleanup_response(state->child_pid);
        
        DLIST_REMOVE(child->requests, state);
 
@@ -305,6 +304,9 @@ static void schedule_async_request(struct winbindd_child *child)
                return;
        }
 
+       /* Now we know who we're sending to - remember the pid. */
+       request->child_pid = child->pid;
+
        setup_async_write(&child->event, request->request,
                          sizeof(*request->request),
                          async_main_request_sent, request);
@@ -519,7 +521,7 @@ void winbind_child_died(pid_t pid)
        }
 
        if (child == NULL) {
-               DEBUG(0, ("Unknown child %d died!\n", pid));
+               DEBUG(5, ("Already reaped child %u died\n", (unsigned int)pid));
                return;
        }
 
@@ -700,6 +702,29 @@ void winbind_msg_onlinestatus(struct messaging_context *msg_ctx,
        }
 }
 
+void winbind_msg_dump_event_list(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_dump_event_list received\n"));
+
+       dump_event_list(winbind_event_context());
+
+       for (child = children; child != NULL; child = child->next) {
+
+               DEBUG(10,("winbind_msg_dump_event_list: sending message to pid %u\n",
+                       (unsigned int)child->pid));
+
+               messaging_send_buf(msg_ctx, pid_to_procid(child->pid),
+                                  MSG_DUMP_EVENT_LIST,
+                                  NULL, 0);
+       }
+
+}
 
 static void account_lockout_policy_handler(struct event_context *ctx,
                                           struct timed_event *te,
@@ -715,9 +740,7 @@ static void account_lockout_policy_handler(struct event_context *ctx,
 
        DEBUG(10,("account_lockout_policy_handler called\n"));
 
-       if (child->lockout_policy_event) {
-               TALLOC_FREE(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 "
@@ -887,6 +910,18 @@ static void child_msg_onlinestatus(struct messaging_context *msg_ctx,
        talloc_destroy(mem_ctx);
 }
 
+static void child_msg_dump_event_list(struct messaging_context *msg,
+                                     void *private_data,
+                                     uint32_t msg_type,
+                                     struct server_id server_id,
+                                     DATA_BLOB *data)
+{
+       DEBUG(5,("child_msg_dump_event_list received\n"));
+
+       dump_event_list(winbind_event_context());
+}
+
+
 static BOOL fork_domain_child(struct winbindd_child *child)
 {
        int fdpair[2];
@@ -960,6 +995,8 @@ static BOOL fork_domain_child(struct winbindd_child *child)
                             MSG_WINBIND_ONLINE, NULL);
        messaging_deregister(winbind_messaging_context(),
                             MSG_WINBIND_ONLINESTATUS, NULL);
+       messaging_deregister(winbind_messaging_context(),
+                            MSG_DUMP_EVENT_LIST, NULL);
 
        /* Handle online/offline messages. */
        messaging_register(winbind_messaging_context(), NULL,
@@ -968,6 +1005,8 @@ static BOOL fork_domain_child(struct winbindd_child *child)
                           MSG_WINBIND_ONLINE, child_msg_online);
        messaging_register(winbind_messaging_context(), NULL,
                           MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus);
+       messaging_register(winbind_messaging_context(), NULL,
+                          MSG_DUMP_EVENT_LIST, child_msg_dump_event_list);
 
        if ( child->domain ) {
                child->domain->startup = True;
@@ -979,9 +1018,7 @@ static BOOL fork_domain_child(struct winbindd_child *child)
 
        for (domain = domain_list(); domain; domain = domain->next) {
                if (domain != child->domain) {
-                       if (domain->check_online_event) {
-                               TALLOC_FREE(domain->check_online_event);
-                       }
+                       TALLOC_FREE(domain->check_online_event);
                }
        }