]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s3:winbind: s/wb_group_members_send/wb_alias_members_send/ for SID_NAME_ALIAS in...
authorPavel Filipenský <pfilipensky@samba.org>
Tue, 21 Mar 2023 07:33:37 +0000 (08:33 +0100)
committerAndreas Schneider <asn@cryptomilk.org>
Tue, 13 Jun 2023 12:15:32 +0000 (12:15 +0000)
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
source3/winbindd/wb_getgrsid.c

index f2c7d9d72fdcbd89bd6cff47122aa2275475bb14..4fd696dfa103bd7279d8ebf88d0c448a7f81a94e 100644 (file)
@@ -22,6 +22,7 @@
 #include "librpc/gen_ndr/ndr_winbind_c.h"
 #include "../libcli/security/security.h"
 #include "lib/dbwrap/dbwrap_rbt.h"
+#include "lib/dbwrap/dbwrap.h"
 
 struct wb_getgrsid_state {
        struct tevent_context *ev;
@@ -32,11 +33,14 @@ struct wb_getgrsid_state {
        enum lsa_SidType type;
        gid_t gid;
        struct db_context *members;
+       uint32_t num_sids;
+       struct dom_sid *sids;
 };
 
 static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq);
 static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq);
 static void wb_getgrsid_got_members(struct tevent_req *subreq);
+static void wb_getgrsid_got_alias_members(struct tevent_req *subreq);
 
 struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
                                    struct tevent_context *ev,
@@ -137,7 +141,9 @@ static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
 
        state->gid = (gid_t)xids[0].id;
 
-       if (state->type == SID_NAME_USER || state->type == SID_NAME_COMPUTER) {
+       switch (state->type) {
+       case SID_NAME_USER:
+       case SID_NAME_COMPUTER: {
                /*
                 * special treatment for a user sid that is
                 * mapped to ID_TYPE_BOTH:
@@ -172,16 +178,144 @@ static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
                tevent_req_done(req);
                return;
        }
+       case SID_NAME_ALIAS:
+               subreq = wb_alias_members_send(state,
+                                              state->ev,
+                                              &state->sid,
+                                              state->type,
+                                              state->max_nesting);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+               /* Decrement the depth based on 'winbind expand groups' */
+               state->max_nesting--;
+               tevent_req_set_callback(subreq,
+                                       wb_getgrsid_got_alias_members,
+                                       req);
+               break;
+       case SID_NAME_DOM_GRP:
+               subreq = wb_group_members_send(state,
+                                              state->ev,
+                                              &state->sid,
+                                              1,
+                                              &state->type,
+                                              state->max_nesting);
+               if (tevent_req_nomem(subreq, req)) {
+                       return;
+               }
+               tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
+               break;
+       case SID_NAME_WKN_GRP:
+               state->members = db_open_rbt(state);
+               if (tevent_req_nomem(state->members, req)) {
+                       return;
+               }
+               tevent_req_done(req);
+               return;
+       default:
+               tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
+               break;
+       }
+}
 
-       /*
-        * the "regular" case of a group type sid.
-        */
+static void wb_getgrsid_got_alias_members_names(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq, struct tevent_req);
+       struct wb_getgrsid_state *state =
+               tevent_req_data(req, struct wb_getgrsid_state);
+       struct lsa_RefDomainList *domains = NULL;
+       struct lsa_TransNameArray *names = NULL;
+       NTSTATUS status;
+       uint32_t li;
+       uint32_t num_sids = 0;
+       struct dom_sid *sids = NULL;
+       enum lsa_SidType *types = NULL;
 
+       status = wb_lookupsids_recv(subreq, state, &domains, &names);
+
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               D_WARNING("Failed with %s.\n", nt_errstr(status));
+               return;
+       }
+
+       if (domains == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
+               return;
+       }
+
+       if (names == NULL) {
+               tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+               D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
+               return;
+       }
+
+       state->members = db_open_rbt(state);
+       if (tevent_req_nomem(state->members, req)) {
+               return;
+       }
+
+       for (li = 0; li < state->num_sids; li++) {
+               struct lsa_TranslatedName *n = &names->names[li];
+
+               if (n->sid_type == SID_NAME_USER ||
+                   n->sid_type == SID_NAME_COMPUTER) {
+                       const char *name = fill_domain_username_talloc(
+                               talloc_tos(),
+                               domains->domains[n->sid_index].name.string,
+                               n->name.string,
+                               false /* can_assume */);
+                       if (tevent_req_nomem(name, req)) {
+                               return;
+                       }
+
+                       status = add_member_to_db(state->members,
+                                                 &state->sids[li],
+                                                 name);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               tevent_req_nterror(req, status);
+                               return;
+                       }
+               } else if (n->sid_type == SID_NAME_DOM_GRP) {
+                       sids = talloc_realloc(talloc_tos(),
+                                             sids,
+                                             struct dom_sid,
+                                             num_sids + 1);
+                       if (tevent_req_nomem(sids, req)) {
+                               return;
+                       }
+                       sids[num_sids] = state->sids[li];
+                       types = talloc_realloc(talloc_tos(),
+                                              types,
+                                              enum lsa_SidType,
+                                              num_sids + 1);
+                       if (tevent_req_nomem(types, req)) {
+                               return;
+                       }
+                       types[num_sids] = n->sid_type;
+                       num_sids++;
+               } else {
+                       struct dom_sid_buf buf;
+                       D_DEBUG("SID %s with sid_type=%d is ignored!\n",
+                               dom_sid_str_buf(&state->sids[li], &buf),
+                               n->sid_type);
+               }
+       }
+
+       TALLOC_FREE(names);
+       TALLOC_FREE(domains);
+
+       if (num_sids == 0) {
+               tevent_req_done(req);
+               return;
+       }
        subreq = wb_group_members_send(state,
                                       state->ev,
-                                      &state->sid,
-                                      1,
-                                      &state->type,
+                                      sids,
+                                      num_sids,
+                                      types,
                                       state->max_nesting);
        if (tevent_req_nomem(subreq, req)) {
                return;
@@ -189,6 +323,35 @@ static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
        tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
 }
 
+static void wb_getgrsid_got_alias_members(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq, struct tevent_req);
+       struct wb_getgrsid_state *state =
+               tevent_req_data(req, struct wb_getgrsid_state);
+       NTSTATUS status;
+
+       status = wb_alias_members_recv(subreq,
+                                      state,
+                                      &state->num_sids,
+                                      &state->sids);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       subreq = wb_lookupsids_send(state,
+                                   state->ev,
+                                   state->sids,
+                                   state->num_sids);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq,
+                               wb_getgrsid_got_alias_members_names,
+                               req);
+}
+
 static void wb_getgrsid_got_members(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
@@ -196,12 +359,26 @@ static void wb_getgrsid_got_members(struct tevent_req *subreq)
        struct wb_getgrsid_state *state = tevent_req_data(
                req, struct wb_getgrsid_state);
        NTSTATUS status;
+       struct db_context *members_prev = state->members;
 
        status = wb_group_members_recv(subreq, state, &state->members);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       /*
+        * If we have called wb_alias_members_send(), members_prev
+        * might already contain users that are direct members of alias,
+        * add to them the users from nested groups.
+        */
+       if (members_prev != NULL) {
+               status = dbwrap_merge_dbs(state->members,
+                                         members_prev,
+                                         TDB_REPLACE);
+               if (tevent_req_nterror(req, status)) {
+                       return;
+               }
+       }
        tevent_req_done(req);
 }