winbindd: Fix a startup race with allocate_gid
authorVolker Lendecke <vl@samba.org>
Tue, 23 Mar 2021 14:13:55 +0000 (15:13 +0100)
committerJeremy Allison <jra@samba.org>
Wed, 24 Mar 2021 20:31:30 +0000 (20:31 +0000)
If you try to allocate a GID before winbind is fully set up,
idmap_child_handle() is still NULL. Add the required
wb_parent_idmap_setup_send()/recv() to allocate_gid().

Bug: https://bugzilla.samba.org/show_bug.cgi?id=14678
RN: Fix a crash in winbind when allocate-gid is called early

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/winbindd/winbindd_allocate_gid.c

index 85aa136947391563bab55adb140cfe650cb4c504..2841d96e5f9a6294226491651793dbb6d8d66ec9 100644 (file)
 #include "librpc/gen_ndr/ndr_winbind_c.h"
 
 struct winbindd_allocate_gid_state {
+       struct tevent_context *ev;
        uint64_t gid;
 };
 
+static void winbindd_allocate_gid_initialized(struct tevent_req *subreq);
 static void winbindd_allocate_gid_done(struct tevent_req *subreq);
 
 struct tevent_req *winbindd_allocate_gid_send(TALLOC_CTX *mem_ctx,
@@ -34,25 +36,56 @@ struct tevent_req *winbindd_allocate_gid_send(TALLOC_CTX *mem_ctx,
 {
        struct tevent_req *req, *subreq;
        struct winbindd_allocate_gid_state *state;
-       struct dcerpc_binding_handle *child_binding_handle = NULL;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct winbindd_allocate_gid_state);
        if (req == NULL) {
                return NULL;
        }
+       state->ev = ev;
 
        DEBUG(3, ("allocate_gid\n"));
 
+       subreq = wb_parent_idmap_setup_send(state, ev);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(
+               subreq, winbindd_allocate_gid_initialized, req);
+       return req;
+}
+
+static void winbindd_allocate_gid_initialized(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct winbindd_allocate_gid_state *state = tevent_req_data(
+               req, struct winbindd_allocate_gid_state);
+       NTSTATUS status;
+       const struct wb_parent_idmap_config *cfg = NULL;
+       struct dcerpc_binding_handle *child_binding_handle = NULL;
+
+       status = wb_parent_idmap_setup_recv(subreq, &cfg);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       if (cfg->num_doms == 0) {
+               /*
+                * idmap_tdb also returns UNSUCCESSFUL if a range is full
+                */
+               tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
+               return;
+       }
+
        child_binding_handle = idmap_child_handle();
 
-       subreq = dcerpc_wbint_AllocateGid_send(state, ev, child_binding_handle,
-                                              &state->gid);
+       subreq = dcerpc_wbint_AllocateGid_send(
+               state, state->ev, child_binding_handle, &state->gid);
        if (tevent_req_nomem(subreq, req)) {
-               return tevent_req_post(req, ev);
+               return;
        }
        tevent_req_set_callback(subreq, winbindd_allocate_gid_done, req);
-       return req;
 }
 
 static void winbindd_allocate_gid_done(struct tevent_req *subreq)