add infrastruture for ndr based requests in the winbindd parent
authorStefan Metzmacher <metze@sernet.de>
Tue, 21 Aug 2007 08:33:48 +0000 (10:33 +0200)
committerStefan Metzmacher <metze@sernet.de>
Thu, 11 Oct 2007 15:21:45 +0000 (17:21 +0200)
metze

source/Makefile.in
source/winbindd/winbindd.c
source/winbindd/winbindd.h

index 5a497be..b50b71f 100644 (file)
@@ -884,6 +884,8 @@ WINBINDD_OBJ1 = \
                winbindd/winbindd_locator.o \
                auth/token_util.o
 
+NDR_WINBIND_PROTOCOL = librpc/gen_ndr/ndr_winbind_protocol.o
+
 WINBINDD_OBJ = \
                $(WINBINDD_OBJ1) $(PASSDB_OBJ) $(GROUPDB_OBJ) \
                $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
@@ -892,7 +894,8 @@ WINBINDD_OBJ = \
                $(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
                $(DCUTIL_OBJ) $(IDMAP_OBJ) $(NSS_INFO_OBJ) \
                $(AFS_OBJ) $(AFS_SETTOKEN_OBJ) lib/launchd.o \
-               $(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) $(LDB_OBJ)
+               $(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) $(LDB_OBJ) \
+               $(NDR_WINBIND_PROTOCOL)
 
 WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
                $(SECRETS_OBJ) $(POPT_LIB_OBJ) $(AFS_SETTOKEN_OBJ) $(RPC_PARSE_OBJ1) $(DOSERR_OBJ)
index 17915fb..12ff28d 100644 (file)
@@ -353,7 +353,7 @@ static struct winbindd_dispatch_table {
        { WINBINDD_NUM_CMDS, NULL, "NONE" }
 };
 
-static void process_request(struct winbindd_cli_state *state)
+static void process_struct_request(struct winbindd_cli_state *state)
 {
        struct winbindd_dispatch_table *table = dispatch_table;
 
@@ -367,10 +367,6 @@ static void process_request(struct winbindd_cli_state *state)
        state->response.result = WINBINDD_PENDING;
        state->response.length = sizeof(struct winbindd_response);
 
-       state->mem_ctx = talloc_init("winbind request");
-       if (state->mem_ctx == NULL)
-               return;
-
        /* Remember who asked us. */
        state->pid = state->request.pid;
 
@@ -378,7 +374,7 @@ static void process_request(struct winbindd_cli_state *state)
 
        for (table = dispatch_table; table->fn; table++) {
                if (state->request.cmd == table->cmd) {
-                       DEBUG(10,("process_request: request fn %s\n",
+                       DEBUG(10,("process_struct_request: request fn %s\n",
                                  table->winbindd_cmd_name ));
                        table->fn(state);
                        break;
@@ -386,12 +382,205 @@ static void process_request(struct winbindd_cli_state *state)
        }
 
        if (!table->fn) {
-               DEBUG(10,("process_request: unknown request fn number %d\n",
+               DEBUG(10,("process_struct_request: unknown request fn number %d\n",
                          (int)state->request.cmd ));
                request_error(state);
        }
 }
 
+
+static const struct winbind_ndr_cmd {
+       uint32 opnum;
+       void (*fn)(struct winbindd_cli_state *state);
+} ndr_cmd_table[] = {
+};
+
+static void request_reset(struct winbindd_cli_state *state, bool wait_for_request);
+
+#define _WINBINDD_NOMEM(ptr) do { \
+       if (!ptr) { \
+               DEBUG(0,("%s: out of memory\n", __location__)); \
+               request_reset(state, false); \
+               return; \
+       } \
+} while (0)
+
+#define _WINBINDD_CHECK_NTSTATUS(status) do { \
+       if (!NT_STATUS_IS_OK(status)) { \
+               DEBUG(0,("%s: status = %s\n", \
+                       __location__, \
+                       nt_errstr(status))); \
+               request_reset(state, false); \
+               return; \
+       } \
+} while (0)
+
+#define WINBINDD_DEBUG_NDR_CALL(lvl, _c, _f, _n) do { \
+       if (DEBUGLVL(lvl)) { \
+               ndr_print_function_debug((ndr_print_function_t) \
+                                        (_c)->ndr.call->ndr_print, \
+                                        _n, \
+                                        _f, \
+                                        (_c)->ndr.r); \
+       } \
+} while (0)
+
+NTSTATUS winbindd_pull_ndr_request(TALLOC_CTX *mem_ctx,
+                                  struct winbindd_ndr_call *c)
+{
+       struct ndr_pull *pull;
+       NTSTATUS status;
+       uint32 opnum;
+
+       DEBUG(10,("winbindd_pull_ndr_request(): packet[%u]\n",
+               c->in.packet.length));
+       dump_data(10, c->in.packet.data, c->in.packet.length);
+
+       pull = ndr_pull_init_blob(&c->in.packet, mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(pull);
+
+       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+       status = ndr_pull_STRUCT_winbind_header(pull,
+                                               NDR_SCALARS|NDR_BUFFERS,
+                                               &c->in.header);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       if (c->in.header.version != WINBIND_HEADER_VERSION) {
+               DEBUG(0,("winbindd_pull_ndr_request: "
+                        "Invalid protocol version: 0x%04X != 0x%04X\n",
+                       c->in.header.version, WINBIND_HEADER_VERSION));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       opnum = c->in.header.opnum;
+
+       if (opnum >= ndr_table_winbind_protocol.num_calls) {
+               DEBUG(10,("winbindd_pull_ndr_request: "
+                         "unknown request opnum number 0x%04X >= 0x%04X\n",
+                         opnum,
+                         ndr_table_winbind_protocol.num_calls));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       DEBUG(3,("winbindd_pull_ndr_request: opnum[%u]\n", opnum));
+
+       c->ndr.call     = &ndr_table_winbind_protocol.calls[opnum];
+       c->ndr.r        = talloc_named(mem_ctx,
+                                      c->ndr.call->struct_size,
+                                      "struct %s",
+                                      c->ndr.call->name);
+       NT_STATUS_HAVE_NO_MEMORY(c->ndr.r);
+
+       status = c->ndr.call->ndr_pull(pull, NDR_IN, c->ndr.r);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       WINBINDD_DEBUG_NDR_CALL(10, c, NDR_IN, "pull_ndr_request");
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS winbindd_pull_ndr_response(TALLOC_CTX *mem_ctx,
+                                   struct winbindd_ndr_call *c)
+{
+       struct ndr_pull *pull;
+       NTSTATUS status;
+       uint32 opnum;
+       const struct ndr_interface_call *call;
+
+       DEBUG(10,("winbindd_pull_ndr_response(): packet[%u]\n",
+               c->out.packet.length));
+       dump_data(10, c->out.packet.data, c->out.packet.length);
+
+       pull = ndr_pull_init_blob(&c->out.packet, mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(pull);
+
+       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+       status = ndr_pull_STRUCT_winbind_header(pull,
+                                               NDR_SCALARS|NDR_BUFFERS,
+                                               &c->out.header);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       if (c->out.header.version != WINBIND_HEADER_VERSION) {
+               DEBUG(0,("winbindd_pull_ndr_response: "
+                        "Invalid protocol version: 0x%04X != 0x%04X\n",
+                        c->out.header.version, WINBIND_HEADER_VERSION));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!(c->out.header.flags & WINBIND_HEADER_FLAGS_RESPONSE)) {
+               DEBUG(0,("winbindd_pull_ndr_response: "
+                        "Flags[0x%08X] miss WINBIND_HEADER_FLAGS_RESPONSE [0x%08X]\n",
+                        c->out.header.flags, WINBIND_HEADER_FLAGS_RESPONSE));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       opnum = c->out.header.opnum;
+
+       if (opnum >= ndr_table_winbind_protocol.num_calls) {
+               DEBUG(10,("winbindd_pull_ndr_response: "
+                         "unknown request opnum number 0x%04X >= 0x%04X\n",
+                         opnum,
+                         ndr_table_winbind_protocol.num_calls));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       DEBUG(3,("winbindd_pull_ndr_response: opnum[%u]\n", opnum));
+
+       call = &ndr_table_winbind_protocol.calls[opnum];
+
+       if (c->ndr.call != call) {
+               DEBUG(10,("winbindd_pull_ndr_response: "
+                         "invalid response [%s] - expected [%s]\n",
+                         call->name, c->ndr.call->name));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (c->out.header.flags & WINBIND_HEADER_FLAGS_ERROR) {
+               status = ndr_pull_winbind_status(pull,
+                                                NDR_SCALARS|NDR_BUFFERS,
+                                                &c->ndr.result);
+               NT_STATUS_NOT_OK_RETURN(status);
+       } else {
+               status = c->ndr.call->ndr_pull(pull, NDR_OUT, c->ndr.r);
+               NT_STATUS_NOT_OK_RETURN(status);
+               c->ndr.result = WINBIND_STATUS_OK;
+
+               WINBINDD_DEBUG_NDR_CALL(10, c, NDR_OUT, "pull_ndr_response");
+       }
+
+       return NT_STATUS_OK;
+}
+
+static void process_ndr_request(struct winbindd_cli_state *state)
+{
+       NTSTATUS status;
+       uint32 i;
+
+       status = winbindd_pull_ndr_request(state->mem_ctx, &state->c);
+       _WINBINDD_CHECK_NTSTATUS(status);
+
+       for (i=0; i < ARRAY_SIZE(ndr_cmd_table); i++) {
+               if (ndr_cmd_table[i].opnum == state->c.in.header.opnum) {
+                       ndr_cmd_table[i].fn(state);
+                       return;
+               }
+       }
+
+       winbindd_reply_ndr_error(state, WINBIND_STATUS_NOT_IMPLEMENTED);
+}
+
+static void process_request(struct winbindd_cli_state *state)
+{
+       if (state->is_ndr) {
+               process_ndr_request(state);
+               return;
+       }
+
+       process_struct_request(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.
@@ -504,13 +693,29 @@ void setup_async_write(struct fd_event *event, void *data, size_t length,
  * This is the main event loop of winbind requests. It goes through a
  * state-machine of 3 read/write requests, 4 if you have extra data to send.
  *
- * An idle winbind client has a read request of 4 bytes outstanding,
- * finalizing function is request_len_recv, checking the length. request_recv
- * then processes the packet. The processing function then at some point has
- * to call request_finished which schedules sending the response.
+
+ * An idle winbind client has a read request of 8 bytes outstanding,
+ * finalizing function is request_autodetect_recv, which autodetects
+ * the used protocol. Then it triggers a read request for the remaining
+ * bytes to complete the request PDU. For the struct based protocol
+ * maybe two reads are needed it the request contains extra data. The
+ * NDR based protocol needs only one read request.
+ *
+ * NOTE: the protocol version is per request and not per client connection
+ *       so the client can mix the old and new requests.
+ *
+ * The process_request() function are calls process_[struct|ndr]_request()
+ * to dispatch the request to the implementation function
+ * depending on the autodetection.
+ *
+ * Struct based requests are finished by calling
+ * request_error() or request_ok().
+ *
+ * NDR bases requests are finished by calling
+ * winbindd_reply_ndr_error() or winbindd_reply_ndr_ok()
  */
 
-static void request_len_recv(void *private_data, BOOL success);
+static void request_autodetect_recv(void *private_data, BOOL success);
 static void request_recv(void *private_data, BOOL success);
 static void request_main_recv(void *private_data, BOOL success);
 static void request_finished(struct winbindd_cli_state *state);
@@ -518,26 +723,40 @@ void request_finished_cont(void *private_data, BOOL success);
 static void response_main_sent(void *private_data, BOOL success);
 static void response_extra_sent(void *private_data, BOOL success);
 
+static void request_reset(struct winbindd_cli_state *state, bool wait_for_request)
+{
+       TALLOC_FREE(state->mem_ctx);
+
+       SAFE_FREE(state->request.extra_data.data);
+       SAFE_FREE(state->response.extra_data.data);
+
+       ZERO_STRUCT(state->request);
+       ZERO_STRUCT(state->response);
+
+       ZERO_STRUCT(state->c);
+
+       if (!wait_for_request) {
+               state->finished = True;
+               return;
+       }
+
+       setup_async_read(&state->fd_event,
+                        state->c.autodetect,
+                        sizeof(state->c.autodetect),
+                        request_autodetect_recv, state);
+}
+
 static void response_extra_sent(void *private_data, BOOL success)
 {
        struct winbindd_cli_state *state =
                talloc_get_type_abort(private_data, struct winbindd_cli_state);
 
-       if (state->mem_ctx != NULL) {
-               talloc_destroy(state->mem_ctx);
-               state->mem_ctx = NULL;
-       }
-
        if (!success) {
-               state->finished = True;
+               request_reset(state, false);
                return;
        }
 
-       SAFE_FREE(state->request.extra_data.data);
-       SAFE_FREE(state->response.extra_data.data);
-
-       setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
-                        request_len_recv, state);
+       request_reset(state, true);
 }
 
 static void response_main_sent(void *private_data, BOOL success)
@@ -546,18 +765,12 @@ static void response_main_sent(void *private_data, BOOL success)
                talloc_get_type_abort(private_data, struct winbindd_cli_state);
 
        if (!success) {
-               state->finished = True;
+               request_reset(state, false);
                return;
        }
 
        if (state->response.length == sizeof(state->response)) {
-               if (state->mem_ctx != NULL) {
-                       talloc_destroy(state->mem_ctx);
-                       state->mem_ctx = NULL;
-               }
-
-               setup_async_read(&state->fd_event, &state->request,
-                                sizeof(uint32), request_len_recv, state);
+               request_reset(state, true);
                return;
        }
 
@@ -597,28 +810,257 @@ void request_finished_cont(void *private_data, BOOL success)
                request_error(state);
 }
 
-static void request_len_recv(void *private_data, BOOL success)
+NTSTATUS winbindd_push_ndr_response(TALLOC_CTX *mem_ctx,
+                                   struct winbindd_ndr_call *c)
+{
+       struct ndr_push *push;
+       NTSTATUS status;
+
+       push = ndr_push_init_ctx(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(push);
+
+       c->out.header           = c->in.header;
+       c->out.header.length    = 0; /* will be overwritten later */
+       c->out.header.flags     = WINBIND_HEADER_FLAGS_RESPONSE;
+
+       if (c->ndr.result != WINBIND_STATUS_OK) {
+               c->out.header.flags |= WINBIND_HEADER_FLAGS_ERROR;
+       }
+
+       status = ndr_push_STRUCT_winbind_header(push,
+                                                NDR_SCALARS|NDR_BUFFERS,
+                                                &c->out.header);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       /* only push the payload if the result is ok */
+       if (c->ndr.result == WINBIND_STATUS_OK) {
+               WINBINDD_DEBUG_NDR_CALL(10, c, NDR_OUT, "push_ndr_response");
+
+               status = c->ndr.call->ndr_push(push,
+                                              NDR_OUT,
+                                              c->ndr.r);
+               NT_STATUS_NOT_OK_RETURN(status);
+       } else {
+               status = ndr_push_winbind_status(push,
+                                                 NDR_SCALARS|NDR_BUFFERS,
+                                                 c->ndr.result);
+               NT_STATUS_NOT_OK_RETURN(status);
+       }
+
+       c->out.packet = ndr_push_blob(push);
+
+       /* fix the length */
+       RSIVAL(c->out.packet.data, 0,
+              c->out.packet.length - 4);
+
+       DEBUG(10,("winbindd_push_ndr_response(): packet[%u]\n",
+               c->out.packet.length));
+       dump_data(10, c->out.packet.data, c->out.packet.length);
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS winbindd_push_ndr_request(TALLOC_CTX *mem_ctx,
+                                  struct winbindd_ndr_call *c)
+{
+       struct ndr_push *push;
+       NTSTATUS status;
+
+       WINBINDD_DEBUG_NDR_CALL(10, c, NDR_IN, "push_ndr_request");
+
+#define _GET_OPNUM(c) (c->ndr.call - ndr_table_winbind_protocol.calls)
+       ZERO_STRUCT(c->in.header);
+       c->in.header.opnum = _GET_OPNUM(c);
+
+       push = ndr_push_init_ctx(mem_ctx);
+       NT_STATUS_HAVE_NO_MEMORY(push);
+
+       status = ndr_push_STRUCT_winbind_header(push,
+                                               NDR_SCALARS|NDR_BUFFERS,
+                                               &c->in.header);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = c->ndr.call->ndr_push(push,
+                                      NDR_IN,
+                                      c->ndr.r);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       c->in.packet = ndr_push_blob(push);
+
+       /* fix the length */
+       RSIVAL(c->in.packet.data, 0,
+              c->in.packet.length - 4);
+
+       DEBUG(10,("winbindd_push_ndr_request(): packet[%u]\n",
+               c->in.packet.length));
+       dump_data(10, c->in.packet.data, c->in.packet.length);
+
+       return NT_STATUS_OK;
+}
+
+void winbindd_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);
+       _WINBINDD_CHECK_NTSTATUS(status);
+
+       setup_async_write(&state->fd_event,
+                         state->c.out.packet.data,
+                         state->c.out.packet.length,
+                         response_extra_sent, state);
+}
+
+void winbindd_reply_ndr_ok(struct winbindd_cli_state *state)
+{
+       winbindd_reply_ndr_error(state, WINBIND_STATUS_OK);
+}
+
+NTSTATUS winbindd_ndr_parse_autodetect(TALLOC_CTX *mem_ctx,
+                                      struct winbindd_ndr_call *c,
+                                      uint32 max_length,
+                                      BOOL in)
+{
+       uint32 min_length = WINBIND_HEADER_SIZE - 4;
+       uint32 length;
+       DATA_BLOB *p;
+
+       length = RIVAL(c->autodetect, 0);
+
+       if (strncmp("WBPT", (const char *)&c->autodetect[4], 4) != 0) {
+               DEBUG(0,("request_header_ndr_recv: "
+                        "Invalid header magic: 0x%08X\n",
+                        RIVAL(c->autodetect, 4)));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (length < min_length) {
+               DEBUG(0,("request_header_ndr_recv: "
+                        "Invalid request size received: %d < %d\n",
+                        length, min_length));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (length > max_length) {
+               DEBUG(0,("request_header_ndr_recv: "
+                        "Invalid request size received: 0x%08X > 0x%08X\n",
+                        length, max_length));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (in) {
+               p = &c->in.packet;
+       } else {
+               p = &c->out.packet;
+       }
+
+       *p = data_blob_talloc(mem_ctx, NULL, length + 4);
+       if (!p->data) {
+               DEBUG(0,("request_header_ndr_recv: out of memory (0x%08X)\n",
+                       length + 4));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       memcpy(p->data,
+              c->autodetect,
+              sizeof(c->autodetect));
+
+       return NT_STATUS_OK;
+}
+
+static void request_ndr_recv(void *private_data, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private_data, struct winbindd_cli_state);
+       NTSTATUS status;
+       uint32 max_length;
+       size_t autodetect_len = sizeof(state->c.autodetect);
+
+       if (!success) {
+               request_reset(state, false);
+               return;
+       }
+
+       if (state->privileged) {
+               max_length = WINBIND_MAX_LENGTH_PRIVILEGED;
+       } else {
+               max_length = WINBIND_MAX_LENGTH_UNPRIVILEGED;
+       }
+
+       status = winbindd_ndr_parse_autodetect(state->mem_ctx,
+                                              &state->c,
+                                              max_length,
+                                              True);
+       if (!NT_STATUS_IS_OK(status)) {
+               state->finished = True;
+               return;
+       }
+
+       state->is_ndr = true;
+       setup_async_read(&state->fd_event,
+                        state->c.in.packet.data + autodetect_len,
+                        state->c.in.packet.length - autodetect_len,
+                        request_recv, state);
+}
+
+static void request_struct_recv(void *private_data, BOOL success)
 {
        struct winbindd_cli_state *state =
                talloc_get_type_abort(private_data, struct winbindd_cli_state);
+       size_t autodetect_len = sizeof(state->c.autodetect);
 
        if (!success) {
                state->finished = True;
                return;
        }
 
+       memcpy(&state->request,
+              state->c.autodetect,
+              autodetect_len);
+
        if (*(uint32 *)(&state->request) != sizeof(state->request)) {
-               DEBUG(0,("request_len_recv: Invalid request size received: %d\n",
+               DEBUG(0,("request_struct_recv: Invalid request size received: %d\n",
                         *(uint32 *)(&state->request)));
                state->finished = True;
                return;
        }
 
-       setup_async_read(&state->fd_event, (uint32 *)(&state->request)+1,
-                        sizeof(state->request) - sizeof(uint32),
+       state->is_ndr = false;
+       setup_async_read(&state->fd_event,
+                        ((uint8 *)(&state->request)) + autodetect_len,
+                        sizeof(state->request) - autodetect_len,
                         request_main_recv, state);
 }
 
+
+static void request_autodetect_recv(void *private_data, BOOL success)
+{
+       struct winbindd_cli_state *state =
+               talloc_get_type_abort(private_data, struct winbindd_cli_state);
+
+       if (!success) {
+               state->finished = True;
+               return;
+       }
+
+       state->mem_ctx = talloc_new(state);
+       if (!state->mem_ctx) {
+               state->finished = True;
+               return;
+       }
+
+       if (strncmp("WBPT", (const char *)&state->c.autodetect[4], 4) == 0) {
+               request_ndr_recv(private_data, success);
+               return;
+       }
+
+       request_struct_recv(private_data, success);
+}
+
 static void request_main_recv(void *private_data, BOOL success)
 {
        struct winbindd_cli_state *state =
@@ -712,8 +1154,10 @@ static void new_connection(int listen_sock, BOOL privileged)
        state->fd_event.flags = 0;
        add_fd_event(&state->fd_event);
 
-       setup_async_read(&state->fd_event, &state->request, sizeof(uint32),
-                        request_len_recv, state);
+       setup_async_read(&state->fd_event,
+                        state->c.autodetect,
+                        sizeof(state->c.autodetect),
+                        request_autodetect_recv, state);
 
        /* Add to connection list */
        
@@ -742,12 +1186,7 @@ static void remove_client(struct winbindd_cli_state *state)
        /* We may have some extra data that was not freed if the client was
           killed unexpectedly */
 
-       SAFE_FREE(state->response.extra_data.data);
-
-       if (state->mem_ctx != NULL) {
-               talloc_destroy(state->mem_ctx);
-               state->mem_ctx = NULL;
-       }
+       request_reset(state, false);
 
        remove_fd_event(&state->fd_event);
                
index d61254a..3036661 100644 (file)
@@ -24,6 +24,7 @@
 #define _WINBINDD_H
 
 #include "nsswitch/winbind_struct_protocol.h"
+#include "librpc/gen_ndr/ndr_winbind_protocol.h"
 
 #ifdef HAVE_LIBNSCD
 #include <libnscd.h>
@@ -80,6 +81,20 @@ struct winbindd_cli_state {
                                                   * initialized? */
        struct getent_state *getpwent_state;      /* State for getpwent() */
        struct getent_state *getgrent_state;      /* State for getgrent() */
+
+       bool is_ndr;
+       struct winbindd_ndr_call {
+               uint8 autodetect[8];
+               struct {
+                       DATA_BLOB packet;
+                       struct winbind_header header;
+               } in, out;
+               struct {
+                       const struct ndr_interface_call *call;
+                       void *r;
+                       enum winbind_status result;
+               } ndr;
+       } c;
 };
 
 /* State between get{pw,gr}ent() calls */