infrastructure to handle ndr requests in the winbind childs
authorStefan Metzmacher <metze@sernet.de>
Mon, 3 Sep 2007 15:28:33 +0000 (17:28 +0200)
committerStefan Metzmacher <metze@sernet.de>
Thu, 11 Oct 2007 15:21:45 +0000 (17:21 +0200)
metze

source/winbindd/winbindd_dual.c

index 7e53fbb..228501b 100644 (file)
@@ -37,14 +37,21 @@ extern BOOL override_logfile;
 
 /* Read some data from a client connection */
 
-static void child_read_request(struct winbindd_cli_state *state)
+static void child_read_struct_request(struct winbindd_cli_state *state)
 {
        ssize_t len;
 
        /* Read data */
 
-       len = read_data(state->sock, (char *)&state->request,
-                       sizeof(state->request));
+       memcpy(&state->request,
+              state->c.autodetect,
+              sizeof(state->c.autodetect));
+
+       len = read_data(state->sock,
+                       (char *)&state->request + sizeof(state->c.autodetect),
+                       sizeof(state->request) - sizeof(state->c.autodetect));
+
+       len += sizeof(state->c.autodetect);
 
        if (len != sizeof(state->request)) {
                DEBUG(len > 0 ? 0 : 3, ("Got invalid request length: %d\n", (int)len));
@@ -81,6 +88,60 @@ static void child_read_request(struct winbindd_cli_state *state)
        }
 }
 
+static void child_read_ndr_request(struct winbindd_cli_state *state)
+{
+       size_t autodetect_len = sizeof(state->c.autodetect);
+       ssize_t len;
+       NTSTATUS status;
+
+       status = winbindd_ndr_parse_autodetect(state->mem_ctx,
+                                              &state->c,
+                                              WINBIND_MAX_LENGTH_PRIVILEGED,
+                                              True);
+       if (!NT_STATUS_IS_OK(status)) {
+               state->finished = True;
+               return;
+       }
+
+       len = read_data(state->sock,
+                       (char *)state->c.in.packet.data + autodetect_len,
+                       state->c.in.packet.length - autodetect_len);
+
+       if (len != state->c.in.packet.length - autodetect_len) {
+               DEBUG(0, ("Could not read the whole packet\n"));
+               state->finished = True;
+               return;
+       }
+}
+
+static void child_read_request(struct winbindd_cli_state *state)
+{
+       ssize_t len;
+
+       /* Read data */
+
+       len = read_data(state->sock, (char *)state->c.autodetect,
+                       sizeof(state->c.autodetect));
+
+       if (len != sizeof(state->c.autodetect)) {
+               DEBUG(len > 0 ? 0 : 3, ("Got invalid request length: %d\n", (int)len));
+               state->finished = True;
+               return;
+       }
+
+       /* as all requests in the child are sync, we can use talloc_tos() */
+       state->mem_ctx = talloc_tos();
+
+       if (strncmp("WBPT", (const char *)&state->c.autodetect[4], 4) == 0) {
+               state->is_ndr = true;
+               child_read_ndr_request(state);
+               return;
+       }
+
+       state->is_ndr = false;
+       child_read_struct_request(state);
+}
+
 /*
  * Machinery for async requests sent to children. You set up a
  * winbindd_request, select a child to query, and issue a async_request
@@ -432,21 +493,23 @@ const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
        { WINBINDD_NUM_CMDS, NULL, "NONE" }
 };
 
-static void child_process_request(struct winbindd_child *child,
-                                 struct winbindd_cli_state *state)
+static void child_process_struct_request(struct winbindd_child *child,
+                                        struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain = child->domain;
        const struct winbindd_child_dispatch_table *table = child->table;
 
+       DEBUG(4,("child daemon request %d\n", (int)state->request.cmd));
+
+       ZERO_STRUCT(state->response);
+       state->request.null_term = '\0';
+
        /* Free response data - we may be interrupted and receive another
           command before being able to send this data off. */
 
        state->response.result = WINBINDD_ERROR;
        state->response.length = sizeof(struct winbindd_response);
 
-       /* as all requests in the child are sync, we can use talloc_tos() */
-       state->mem_ctx = talloc_tos();
-
        /* Process command */
 
        for (; table->fn; table++) {
@@ -897,6 +960,91 @@ static void child_msg_dump_event_list(struct messaging_context *msg,
        dump_event_list(winbind_event_context());
 }
 
+static const struct winbind_ndr_cmd {
+       uint32 opnum;
+       void (*fn)(struct winbindd_domain *domain,
+                  struct winbindd_cli_state *state);
+} ndr_child_cmd_table[] = {
+};
+
+static void child_reply_ndr_error(struct winbindd_cli_state *state,
+                                 enum winbind_status result)
+{
+       NTSTATUS status;
+
+       state->c.ndr.result = result;
+
+       status = winbindd_push_ndr_response(state->mem_ctx, &state->c);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("child_reply_ndr_error: "
+                       "failed to pull request structure: %s\n",
+                       nt_errstr(status)));
+               exit(1);
+       }
+
+       if (write_data(state->sock,
+                      (const char *)state->c.out.packet.data,
+                      state->c.out.packet.length) !=
+                   state->c.out.packet.length) {
+               DEBUG(1,("child_reply_ndr_error: "
+                       "Could not write ndr result\n"));
+               exit(1);
+       }
+}
+
+static void child_process_ndr_request(struct winbindd_domain *domain,
+                                     struct winbindd_cli_state *state)
+{
+       NTSTATUS status;
+       uint32 i;
+
+       status = winbindd_pull_ndr_request(state->mem_ctx, &state->c);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("child_process_ndr_request: "
+                       "failed to pull request structure: %s\n",
+                       nt_errstr(status)));
+               return;
+       }
+
+       for (i=0; i < ARRAY_SIZE(ndr_child_cmd_table); i++) {
+               if (ndr_child_cmd_table[i].opnum == state->c.in.header.opnum) {
+                       ndr_child_cmd_table[i].fn(domain, state);
+                       child_reply_ndr_error(state, WINBIND_STATUS_OK);
+                       return;
+               }
+       }
+
+       child_reply_ndr_error(state, WINBIND_STATUS_NOT_IMPLEMENTED);
+}
+
+static void child_process_request(struct winbindd_domain *domain,
+                                 struct winbindd_cli_state *state)
+{
+       if (state->is_ndr) {
+               child_process_ndr_request(domain, state);
+               return;
+       }
+
+       child_process_struct_request(domain, state);
+
+       SAFE_FREE(state->request.extra_data.data);
+
+       cache_store_response(sys_getpid(), &state->response);
+
+       SAFE_FREE(state->response.extra_data.data);
+
+       /* We just send the result code back, the result
+        * structure needs to be fetched via the
+        * winbindd_cache. Hmm. That needs fixing... */
+
+       if (write_data(state->sock,
+                      (const char *)&state->response.result,
+                      sizeof(state->response.result)) !=
+                   sizeof(state->response.result)) {
+               DEBUG(0, ("Could not write result\n"));
+               exit(1);
+       }
+}
 
 static BOOL fork_domain_child(struct winbindd_child *child)
 {
@@ -1080,29 +1228,8 @@ static BOOL fork_domain_child(struct winbindd_child *child)
                        exit(0);
                }
 
-               DEBUG(4,("child daemon request %d\n", (int)state.request.cmd));
-
-               ZERO_STRUCT(state.response);
-               state.request.null_term = '\0';
                child_process_request(child, &state);
 
-               SAFE_FREE(state.request.extra_data.data);
-
-               cache_store_response(sys_getpid(), &state.response);
-
-               SAFE_FREE(state.response.extra_data.data);
-
-               /* We just send the result code back, the result
-                * structure needs to be fetched via the
-                * winbindd_cache. Hmm. That needs fixing... */
-
-               if (write_data(state.sock,
-                              (const char *)&state.response.result,
-                              sizeof(state.response.result)) !=
-                   sizeof(state.response.result)) {
-                       DEBUG(0, ("Could not write result\n"));
-                       exit(1);
-               }
                TALLOC_FREE(frame);
        }
 }