libcli-cldap: avoid the case local == remote == NULL
[sfrench/samba-autobuild/.git] / libcli / cldap / cldap.c
index 37b4f4913dbfc5beb1ccca7da6eb00458526f607..b7df9d22835c850497ccdbdbb6a26d932dbaac33 100644 (file)
@@ -61,15 +61,6 @@ struct cldap_socket {
         */
        bool connected;
 
-       /*
-        * we allow sync requests only, if the caller
-        * did not pass an event context to cldap_socket_init()
-        */
-       struct {
-               bool allow_poll;
-               struct tevent_context *ctx;
-       } event;
-
        /* the queue for outgoing dgrams */
        struct tevent_queue *send_queue;
 
@@ -86,6 +77,7 @@ struct cldap_socket {
 
        /* what to do with incoming request packets */
        struct {
+               struct tevent_context *ev;
                void (*handler)(struct cldap_socket *,
                                void *private_data,
                                struct cldap_incoming *);
@@ -97,6 +89,7 @@ struct cldap_search_state {
        struct cldap_search_state *prev, *next;
 
        struct {
+               struct tevent_context *ev;
                struct cldap_socket *cldap;
        } caller;
 
@@ -136,6 +129,8 @@ static void cldap_recvfrom_done(struct tevent_req *subreq);
 
 static bool cldap_recvfrom_setup(struct cldap_socket *c)
 {
+       struct tevent_context *ev;
+
        if (c->recv_subreq) {
                return true;
        }
@@ -144,7 +139,12 @@ static bool cldap_recvfrom_setup(struct cldap_socket *c)
                return true;
        }
 
-       c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
+       ev = c->incoming.ev;
+       if (ev == NULL) {
+               ev = c->searches.list->caller.ev;
+       }
+
+       c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
        if (!c->recv_subreq) {
                return false;
        }
@@ -284,7 +284,7 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
 nomem:
        in->recv_errno = ENOMEM;
 error:
-       status = map_nt_error_from_unix(in->recv_errno);
+       status = map_nt_error_from_unix_common(in->recv_errno);
 nterror:
        /* in connected mode the first pending search gets the error */
        if (!c->connected) {
@@ -304,7 +304,6 @@ done:
   initialise a cldap_sock
 */
 NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
-                          struct tevent_context *ev,
                           const struct tsocket_address *local_addr,
                           const struct tsocket_address *remote_addr,
                           struct cldap_socket **_cldap)
@@ -313,31 +312,46 @@ NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
        struct tsocket_address *any = NULL;
        NTSTATUS status;
        int ret;
+       const char *fam = NULL;
+
+       if (local_addr == NULL && remote_addr == NULL) {
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
+       if (remote_addr) {
+               bool is_ipv4;
+               bool is_ipv6;
+
+               is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
+               is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
+
+               if (is_ipv4) {
+                       fam = "ipv4";
+               } else if (is_ipv6) {
+                       fam = "ipv6";
+               } else {
+                       return NT_STATUS_INVALID_ADDRESS;
+               }
+       }
 
        c = talloc_zero(mem_ctx, struct cldap_socket);
        if (!c) {
                goto nomem;
        }
 
-       if (!ev) {
-               ev = tevent_context_init(c);
-               if (!ev) {
-                       goto nomem;
+       if (!local_addr) {
+               /*
+                * Here we know the address family of the remote address.
+                */
+               if (fam == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER_MIX;
                }
-               c->event.allow_poll = true;
-       }
-       c->event.ctx = ev;
 
-       if (!local_addr) {
-               /* we use ipv4 here instead of ip, as otherwise we end
-                  up with a PF_INET6 socket, and sendto() for ipv4
-                  addresses will fail. That breaks cldap name
-                  resolution for winbind to IPv4 hosts. */
-               ret = tsocket_address_inet_from_strings(c, "ipv4",
+               ret = tsocket_address_inet_from_strings(c, fam,
                                                        NULL, 0,
                                                        &any);
                if (ret != 0) {
-                       status = map_nt_error_from_unix(errno);
+                       status = map_nt_error_from_unix_common(errno);
                        goto nterror;
                }
                local_addr = any;
@@ -351,7 +365,7 @@ NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
        ret = tdgram_inet_udp_socket(local_addr, remote_addr,
                                     c, &c->sock);
        if (ret != 0) {
-               status = map_nt_error_from_unix(errno);
+               status = map_nt_error_from_unix_common(errno);
                goto nterror;
        }
        talloc_free(any);
@@ -381,6 +395,7 @@ nterror:
   setup a handler for incoming requests
 */
 NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
+                                   struct tevent_context *ev,
                                    void (*handler)(struct cldap_socket *,
                                                    void *private_data,
                                                    struct cldap_incoming *),
@@ -390,11 +405,7 @@ NTSTATUS cldap_set_incoming_handler(struct cldap_socket *c,
                return NT_STATUS_PIPE_CONNECTED;
        }
 
-       /* if sync requests are allowed, we don't allow an incoming handler */
-       if (c->event.allow_poll) {
-               return NT_STATUS_INVALID_PIPE_STATE;
-       }
-
+       c->incoming.ev = ev;
        c->incoming.handler = handler;
        c->incoming.private_data = private_data;
 
@@ -428,6 +439,10 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
                return NT_STATUS_PIPE_CONNECTED;
        }
 
+       if (cldap->incoming.ev == NULL) {
+               return NT_STATUS_INVALID_PIPE_STATE;
+       }
+
        if (!io->dest) {
                return NT_STATUS_INVALID_ADDRESS;
        }
@@ -480,7 +495,7 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
        data_blob_free(&blob2);
 
        subreq = tdgram_sendto_queue_send(state,
-                                         cldap->event.ctx,
+                                         cldap->incoming.ev,
                                          cldap->sock,
                                          cldap->send_queue,
                                          state->blob.data,
@@ -533,8 +548,9 @@ static void cldap_search_state_wakeup_done(struct tevent_req *subreq);
   queue a cldap reply for send
 */
 struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
-                                   struct cldap_socket *cldap,
-                                   const struct cldap_search *io)
+                                    struct tevent_context *ev,
+                                    struct cldap_socket *cldap,
+                                    const struct cldap_search *io)
 {
        struct tevent_req *req, *subreq;
        struct cldap_search_state *state = NULL;
@@ -551,6 +567,7 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
        ZERO_STRUCTP(state);
+       state->caller.ev = ev;
        state->req = req;
        state->caller.cldap = cldap;
        state->message_id = -1;
@@ -630,13 +647,13 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
                                         state->request.delay % 1000000);
        }
 
-       if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
-               tevent_req_nomem(NULL, req);
+       if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
+               tevent_req_oom(req);
                goto post;
        }
 
        subreq = tdgram_sendto_queue_send(state,
-                                         state->caller.cldap->event.ctx,
+                                         state->caller.ev,
                                          state->caller.cldap->sock,
                                          state->caller.cldap->send_queue,
                                          state->request.blob.data,
@@ -652,7 +669,7 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
        return req;
 
  post:
-       return tevent_req_post(req, cldap->event.ctx);
+       return tevent_req_post(req, state->caller.ev);
 }
 
 static void cldap_search_state_queue_done(struct tevent_req *subreq)
@@ -669,7 +686,7 @@ static void cldap_search_state_queue_done(struct tevent_req *subreq)
        talloc_free(subreq);
        if (ret == -1) {
                NTSTATUS status;
-               status = map_nt_error_from_unix(sys_errno);
+               status = map_nt_error_from_unix_common(sys_errno);
                DLIST_REMOVE(state->caller.cldap->searches.list, state);
                ZERO_STRUCT(state->caller.cldap);
                tevent_req_nterror(req, status);
@@ -680,7 +697,7 @@ static void cldap_search_state_queue_done(struct tevent_req *subreq)
 
        /* wait for incoming traffic */
        if (!cldap_recvfrom_setup(state->caller.cldap)) {
-               tevent_req_nomem(NULL, req);
+               tevent_req_oom(req);
                return;
        }
 
@@ -692,7 +709,7 @@ static void cldap_search_state_queue_done(struct tevent_req *subreq)
        next = tevent_timeval_current_ofs(state->request.delay / 1000000,
                                          state->request.delay % 1000000);
        subreq = tevent_wakeup_send(state,
-                                   state->caller.cldap->event.ctx,
+                                   state->caller.ev,
                                    next);
        if (tevent_req_nomem(subreq, req)) {
                return;
@@ -716,7 +733,7 @@ static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
        }
 
        subreq = tdgram_sendto_queue_send(state,
-                                         state->caller.cldap->event.ctx,
+                                         state->caller.ev,
                                          state->caller.cldap->sock,
                                          state->caller.cldap->send_queue,
                                          state->request.blob.data,
@@ -805,29 +822,47 @@ NTSTATUS cldap_search(struct cldap_socket *cldap,
                      TALLOC_CTX *mem_ctx,
                      struct cldap_search *io)
 {
+       TALLOC_CTX *frame;
        struct tevent_req *req;
+       struct tevent_context *ev;
        NTSTATUS status;
 
-       if (!cldap->event.allow_poll) {
+       if (cldap->searches.list) {
+               return NT_STATUS_PIPE_BUSY;
+       }
+
+       if (cldap->incoming.handler) {
                return NT_STATUS_INVALID_PIPE_STATE;
        }
 
-       if (cldap->searches.list) {
-               return NT_STATUS_PIPE_BUSY;
+       frame = talloc_stackframe();
+
+       ev = tevent_context_init(frame);
+       if (ev == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
        }
 
-       req = cldap_search_send(mem_ctx, cldap, io);
-       NT_STATUS_HAVE_NO_MEMORY(req);
+       req = cldap_search_send(mem_ctx, ev, cldap, io);
+       if (req == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       if (!tevent_req_poll(req, cldap->event.ctx)) {
-               talloc_free(req);
-               return NT_STATUS_INTERNAL_ERROR;
+       if (!tevent_req_poll(req, ev)) {
+               status = map_nt_error_from_unix_common(errno);
+               TALLOC_FREE(frame);
+               return status;
        }
 
        status = cldap_search_recv(req, mem_ctx, io);
-       talloc_free(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
 
-       return status;
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
 }
 
 struct cldap_netlogon_state {
@@ -839,8 +874,9 @@ static void cldap_netlogon_state_done(struct tevent_req *subreq);
   queue a cldap netlogon for send
 */
 struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
-                                     struct cldap_socket *cldap,
-                                     const struct cldap_netlogon *io)
+                                      struct tevent_context *ev,
+                                      struct cldap_socket *cldap,
+                                      const struct cldap_netlogon *io)
 {
        struct tevent_req *req, *subreq;
        struct cldap_netlogon_state *state;
@@ -928,7 +964,7 @@ struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
        state->search.in.timeout        = 2;
        state->search.in.retries        = 2;
 
-       subreq = cldap_search_send(state, cldap, &state->search);
+       subreq = cldap_search_send(state, ev, cldap, &state->search);
        if (tevent_req_nomem(subreq, req)) {
                goto post;
        }
@@ -936,7 +972,7 @@ struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
 
        return req;
 post:
-       return tevent_req_post(req, cldap->event.ctx);
+       return tevent_req_post(req, ev);
 }
 
 static void cldap_netlogon_state_done(struct tevent_req *subreq)
@@ -1010,29 +1046,47 @@ NTSTATUS cldap_netlogon(struct cldap_socket *cldap,
                        TALLOC_CTX *mem_ctx,
                        struct cldap_netlogon *io)
 {
+       TALLOC_CTX *frame;
        struct tevent_req *req;
+       struct tevent_context *ev;
        NTSTATUS status;
 
-       if (!cldap->event.allow_poll) {
+       if (cldap->searches.list) {
+               return NT_STATUS_PIPE_BUSY;
+       }
+
+       if (cldap->incoming.handler) {
                return NT_STATUS_INVALID_PIPE_STATE;
        }
 
-       if (cldap->searches.list) {
-               return NT_STATUS_PIPE_BUSY;
+       frame = talloc_stackframe();
+
+       ev = tevent_context_init(frame);
+       if (ev == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
        }
 
-       req = cldap_netlogon_send(mem_ctx, cldap, io);
-       NT_STATUS_HAVE_NO_MEMORY(req);
+       req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
+       if (req == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       if (!tevent_req_poll(req, cldap->event.ctx)) {
-               talloc_free(req);
-               return NT_STATUS_INTERNAL_ERROR;
+       if (!tevent_req_poll(req, ev)) {
+               status = map_nt_error_from_unix_common(errno);
+               TALLOC_FREE(frame);
+               return status;
        }
 
        status = cldap_netlogon_recv(req, mem_ctx, io);
-       talloc_free(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
+               return status;
+       }
 
-       return status;
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
 }