LCOV - code coverage report
Current view: top level - source3/winbindd - wb_group_members.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 173 226 76.5 %
Date: 2024-04-21 15:09:00 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async lookupgroupmembers
       4             :    Copyright (C) Volker Lendecke 2009
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "winbindd.h"
      22             : #include "librpc/gen_ndr/ndr_winbind_c.h"
      23             : #include "../librpc/gen_ndr/ndr_security.h"
      24             : #include "../libcli/security/security.h"
      25             : #include "lib/util/util_tdb.h"
      26             : #include "lib/dbwrap/dbwrap.h"
      27             : #include "lib/dbwrap/dbwrap_rbt.h"
      28             : 
      29             : /*
      30             :  * We have 3 sets of routines here:
      31             :  *
      32             :  * wb_lookupgroupmem is the low-level one-group routine
      33             :  *
      34             :  * wb_groups_members walks a list of groups
      35             :  *
      36             :  * wb_group_members finally is the high-level routine expanding groups
      37             :  * recursively
      38             :  */
      39             : 
      40             : /*
      41             :  * TODO: fill_grent_mem_domusers must be re-added
      42             :  */
      43             : 
      44             : /*
      45             :  * Look up members of a single group. Essentially a wrapper around the
      46             :  * lookup_groupmem winbindd_methods routine.
      47             :  */
      48             : 
      49             : struct wb_lookupgroupmem_state {
      50             :         struct dom_sid sid;
      51             :         struct wbint_Principals members;
      52             : };
      53             : 
      54             : static void wb_lookupgroupmem_done(struct tevent_req *subreq);
      55             : 
      56          14 : static struct tevent_req *wb_lookupgroupmem_send(TALLOC_CTX *mem_ctx,
      57             :                                                  struct tevent_context *ev,
      58             :                                                  const struct dom_sid *group_sid,
      59             :                                                  enum lsa_SidType type)
      60             : {
      61           0 :         struct tevent_req *req, *subreq;
      62           0 :         struct wb_lookupgroupmem_state *state;
      63           0 :         struct winbindd_domain *domain;
      64             : 
      65          14 :         req = tevent_req_create(mem_ctx, &state,
      66             :                                 struct wb_lookupgroupmem_state);
      67          14 :         if (req == NULL) {
      68           0 :                 return NULL;
      69             :         }
      70          14 :         sid_copy(&state->sid, group_sid);
      71             : 
      72          14 :         domain = find_domain_from_sid_noinit(group_sid);
      73          14 :         if (domain == NULL) {
      74           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
      75           0 :                 return tevent_req_post(req, ev);
      76             :         }
      77             : 
      78          14 :         subreq = dcerpc_wbint_LookupGroupMembers_send(
      79          14 :                 state, ev, dom_child_handle(domain), &state->sid, type,
      80          14 :                 &state->members);
      81          14 :         if (tevent_req_nomem(subreq, req)) {
      82           0 :                 return tevent_req_post(req, ev);
      83             :         }
      84          14 :         tevent_req_set_callback(subreq, wb_lookupgroupmem_done, req);
      85          14 :         return req;
      86             : }
      87             : 
      88          14 : static void wb_lookupgroupmem_done(struct tevent_req *subreq)
      89             : {
      90          14 :         struct tevent_req *req = tevent_req_callback_data(
      91             :                 subreq, struct tevent_req);
      92          14 :         struct wb_lookupgroupmem_state *state = tevent_req_data(
      93             :                 req, struct wb_lookupgroupmem_state);
      94           0 :         NTSTATUS status, result;
      95             : 
      96          14 :         status = dcerpc_wbint_LookupGroupMembers_recv(subreq, state, &result);
      97          14 :         TALLOC_FREE(subreq);
      98          14 :         if (any_nt_status_not_ok(status, result, &status)) {
      99           0 :                 tevent_req_nterror(req, status);
     100           0 :                 return;
     101             :         }
     102          14 :         tevent_req_done(req);
     103             : }
     104             : 
     105          14 : static NTSTATUS wb_lookupgroupmem_recv(struct tevent_req *req,
     106             :                                        TALLOC_CTX *mem_ctx,
     107             :                                        uint32_t *num_members,
     108             :                                        struct wbint_Principal **members)
     109             : {
     110          14 :         struct wb_lookupgroupmem_state *state = tevent_req_data(
     111             :                 req, struct wb_lookupgroupmem_state);
     112           0 :         NTSTATUS status;
     113             : 
     114          14 :         if (tevent_req_is_nterror(req, &status)) {
     115           0 :                 return status;
     116             :         }
     117             : 
     118          14 :         *num_members = state->members.num_principals;
     119          14 :         *members = talloc_move(mem_ctx, &state->members.principals);
     120          14 :         return NT_STATUS_OK;
     121             : }
     122             : 
     123             : /*
     124             :  * Same as wb_lookupgroupmem for a list of groups
     125             :  */
     126             : 
     127             : struct wb_groups_members_state {
     128             :         struct tevent_context *ev;
     129             :         struct wbint_Principal *groups;
     130             :         uint32_t num_groups;
     131             :         uint32_t next_group;
     132             :         struct wbint_Principal *all_members;
     133             : };
     134             : 
     135             : static NTSTATUS wb_groups_members_next_subreq(
     136             :         struct wb_groups_members_state *state,
     137             :         TALLOC_CTX *mem_ctx, struct tevent_req **psubreq);
     138             : static void wb_groups_members_done(struct tevent_req *subreq);
     139             : 
     140          10 : static struct tevent_req *wb_groups_members_send(TALLOC_CTX *mem_ctx,
     141             :                                                  struct tevent_context *ev,
     142             :                                                  uint32_t num_groups,
     143             :                                                  struct wbint_Principal *groups)
     144             : {
     145          10 :         struct tevent_req *req, *subreq = NULL;
     146           0 :         struct wb_groups_members_state *state;
     147           0 :         NTSTATUS status;
     148             : 
     149          10 :         req = tevent_req_create(mem_ctx, &state,
     150             :                                 struct wb_groups_members_state);
     151          10 :         if (req == NULL) {
     152           0 :                 return NULL;
     153             :         }
     154          10 :         state->ev = ev;
     155          10 :         state->groups = groups;
     156          10 :         state->num_groups = num_groups;
     157          10 :         state->next_group = 0;
     158          10 :         state->all_members = NULL;
     159             : 
     160          10 :         D_DEBUG("Looking up %"PRIu32" group(s).\n", num_groups);
     161          10 :         status = wb_groups_members_next_subreq(state, state, &subreq);
     162          10 :         if (tevent_req_nterror(req, status)) {
     163           0 :                 return tevent_req_post(req, ev);
     164             :         }
     165          10 :         if (subreq == NULL) {
     166           0 :                 tevent_req_done(req);
     167           0 :                 return tevent_req_post(req, ev);
     168             :         }
     169          10 :         tevent_req_set_callback(subreq, wb_groups_members_done, req);
     170          10 :         return req;
     171             : }
     172             : 
     173          24 : static NTSTATUS wb_groups_members_next_subreq(
     174             :         struct wb_groups_members_state *state,
     175             :         TALLOC_CTX *mem_ctx, struct tevent_req **psubreq)
     176             : {
     177           0 :         struct tevent_req *subreq;
     178           0 :         struct wbint_Principal *g;
     179             : 
     180          24 :         if (state->next_group >= state->num_groups) {
     181          10 :                 *psubreq = NULL;
     182          10 :                 return NT_STATUS_OK;
     183             :         }
     184             : 
     185          14 :         g = &state->groups[state->next_group];
     186          14 :         state->next_group += 1;
     187             : 
     188          14 :         subreq = wb_lookupgroupmem_send(mem_ctx, state->ev, &g->sid, g->type);
     189          14 :         if (subreq == NULL) {
     190           0 :                 return NT_STATUS_NO_MEMORY;
     191             :         }
     192          14 :         *psubreq = subreq;
     193          14 :         return NT_STATUS_OK;
     194             : }
     195             : 
     196          14 : static void wb_groups_members_done(struct tevent_req *subreq)
     197             : {
     198          14 :         struct tevent_req *req = tevent_req_callback_data(
     199             :                 subreq, struct tevent_req);
     200          14 :         struct wb_groups_members_state *state = tevent_req_data(
     201             :                 req, struct wb_groups_members_state);
     202           0 :         uint32_t i, num_all_members;
     203          14 :         uint32_t num_members = 0;
     204          14 :         struct wbint_Principal *members = NULL;
     205           0 :         NTSTATUS status;
     206             : 
     207          14 :         status = wb_lookupgroupmem_recv(subreq, state, &num_members, &members);
     208          14 :         TALLOC_FREE(subreq);
     209             : 
     210             :         /*
     211             :          * In this error handling here we might have to be a bit more generous
     212             :          * and just continue if an error occurred.
     213             :          */
     214             : 
     215          14 :         if (!NT_STATUS_IS_OK(status)) {
     216           0 :                 if (!NT_STATUS_EQUAL(
     217             :                             status, NT_STATUS_TRUSTED_DOMAIN_FAILURE)) {
     218           0 :                         tevent_req_nterror(req, status);
     219           0 :                         return;
     220             :                 }
     221           0 :                 num_members = 0;
     222             :         }
     223             : 
     224          14 :         num_all_members = talloc_array_length(state->all_members);
     225             : 
     226          14 :         D_DEBUG("Adding %"PRIu32" new member(s) to existing %"PRIu32" member(s)\n",
     227             :                 num_members,
     228             :                 num_all_members);
     229             : 
     230          14 :         state->all_members = talloc_realloc(
     231             :                 state, state->all_members, struct wbint_Principal,
     232             :                 num_all_members + num_members);
     233          14 :         if ((num_all_members + num_members != 0)
     234          14 :             && tevent_req_nomem(state->all_members, req)) {
     235           0 :                 return;
     236             :         }
     237          40 :         for (i=0; i<num_members; i++) {
     238           0 :                 struct wbint_Principal *src, *dst;
     239          26 :                 src = &members[i];
     240          26 :                 dst = &state->all_members[num_all_members + i];
     241          26 :                 sid_copy(&dst->sid, &src->sid);
     242          26 :                 dst->name = talloc_move(state->all_members, &src->name);
     243          26 :                 dst->type = src->type;
     244             :         }
     245          14 :         TALLOC_FREE(members);
     246             : 
     247          14 :         status = wb_groups_members_next_subreq(state, state, &subreq);
     248          14 :         if (tevent_req_nterror(req, status)) {
     249           0 :                 return;
     250             :         }
     251          14 :         if (subreq == NULL) {
     252          10 :                 tevent_req_done(req);
     253          10 :                 return;
     254             :         }
     255           4 :         tevent_req_set_callback(subreq, wb_groups_members_done, req);
     256             : }
     257             : 
     258          10 : static NTSTATUS wb_groups_members_recv(struct tevent_req *req,
     259             :                                        TALLOC_CTX *mem_ctx,
     260             :                                        uint32_t *num_members,
     261             :                                        struct wbint_Principal **members)
     262             : {
     263          10 :         struct wb_groups_members_state *state = tevent_req_data(
     264             :                 req, struct wb_groups_members_state);
     265           0 :         NTSTATUS status;
     266             : 
     267          10 :         if (tevent_req_is_nterror(req, &status)) {
     268           0 :                 return status;
     269             :         }
     270          10 :         *num_members = talloc_array_length(state->all_members);
     271          10 :         *members = talloc_move(mem_ctx, &state->all_members);
     272          10 :         return NT_STATUS_OK;
     273             : }
     274             : 
     275             : 
     276             : /*
     277             :  * This is the routine expanding a list of groups up to a certain level. We
     278             :  * collect the users in a rbt database: We have to add them without duplicates,
     279             :  * and the db is indexed by SID.
     280             :  */
     281             : 
     282             : struct wb_group_members_state {
     283             :         struct tevent_context *ev;
     284             :         int depth;
     285             :         struct db_context *users;
     286             :         struct wbint_Principal *groups;
     287             : };
     288             : 
     289             : static NTSTATUS wb_group_members_next_subreq(
     290             :         struct wb_group_members_state *state,
     291             :         TALLOC_CTX *mem_ctx, struct tevent_req **psubreq);
     292             : static void wb_group_members_done(struct tevent_req *subreq);
     293             : 
     294        5004 : struct tevent_req *wb_group_members_send(TALLOC_CTX *mem_ctx,
     295             :                                          struct tevent_context *ev,
     296             :                                          const struct dom_sid *sid,
     297             :                                          uint32_t num_sids,
     298             :                                          enum lsa_SidType *type,
     299             :                                          int max_depth)
     300             : {
     301        5004 :         struct tevent_req *req, *subreq = NULL;
     302           0 :         struct wb_group_members_state *state;
     303           0 :         NTSTATUS status;
     304           0 :         struct dom_sid_buf buf;
     305           0 :         uint32_t i;
     306             : 
     307        5004 :         req = tevent_req_create(mem_ctx, &state,
     308             :                                 struct wb_group_members_state);
     309        5004 :         if (req == NULL) {
     310           0 :                 return NULL;
     311             :         }
     312        5004 :         D_INFO("WB command group_members start (max_depth=%d).\n", max_depth);
     313       10012 :         for (i = 0; i < num_sids; i++) {
     314        5008 :                 D_INFO("Looking up members of group SID %s with SID type %d\n",
     315             :                        dom_sid_str_buf(&sid[i], &buf),
     316             :                        type[i]);
     317             :         }
     318             : 
     319        5004 :         state->ev = ev;
     320        5004 :         state->depth = max_depth;
     321        5004 :         state->users = db_open_rbt(state);
     322        5004 :         if (tevent_req_nomem(state->users, req)) {
     323           0 :                 return tevent_req_post(req, ev);
     324             :         }
     325             : 
     326        5004 :         state->groups = talloc_array(state, struct wbint_Principal, num_sids);
     327        5004 :         if (tevent_req_nomem(state->groups, req)) {
     328           0 :                 return tevent_req_post(req, ev);
     329             :         }
     330             : 
     331       10012 :         for (i = 0; i < num_sids; i++) {
     332        5008 :                 state->groups[i].name = NULL;
     333        5008 :                 sid_copy(&state->groups[i].sid, &sid[i]);
     334        5008 :                 state->groups[i].type = type[i];
     335             :         }
     336             : 
     337        5004 :         status = wb_group_members_next_subreq(state, state, &subreq);
     338        5004 :         if (tevent_req_nterror(req, status)) {
     339           0 :                 return tevent_req_post(req, ev);
     340             :         }
     341        5004 :         if (subreq == NULL) {
     342        4996 :                 tevent_req_done(req);
     343        4996 :                 return tevent_req_post(req, ev);
     344             :         }
     345           8 :         tevent_req_set_callback(subreq, wb_group_members_done, req);
     346           8 :         return req;
     347             : }
     348             : 
     349        5014 : static NTSTATUS wb_group_members_next_subreq(
     350             :         struct wb_group_members_state *state,
     351             :         TALLOC_CTX *mem_ctx, struct tevent_req **psubreq)
     352             : {
     353           0 :         struct tevent_req *subreq;
     354             : 
     355        5014 :         if ((talloc_array_length(state->groups) == 0)
     356        5006 :             || (state->depth <= 0)) {
     357        5004 :                 *psubreq = NULL;
     358        5004 :                 D_DEBUG("Finished. The depth is %d.\n", state->depth);
     359        5004 :                 return NT_STATUS_OK;
     360             :         }
     361          10 :         state->depth -= 1;
     362             : 
     363          10 :         D_DEBUG("The depth is decremented to %d.\n", state->depth);
     364          20 :         subreq = wb_groups_members_send(
     365          10 :                 mem_ctx, state->ev, talloc_array_length(state->groups),
     366             :                 state->groups);
     367          10 :         if (subreq == NULL) {
     368           0 :                 return NT_STATUS_NO_MEMORY;
     369             :         }
     370          10 :         *psubreq = subreq;
     371          10 :         return NT_STATUS_OK;
     372             : }
     373             : 
     374          36 : NTSTATUS add_member_to_db(struct db_context *db, struct dom_sid *sid,
     375             :                           const char *name)
     376          36 : {
     377          36 :         size_t len = ndr_size_dom_sid(sid, 0);
     378          36 :         uint8_t sidbuf[len];
     379          36 :         TDB_DATA key = { .dptr = sidbuf, .dsize = sizeof(sidbuf) };
     380           0 :         NTSTATUS status;
     381             : 
     382          36 :         sid_linearize(sidbuf, sizeof(sidbuf), sid);
     383             : 
     384          36 :         status = dbwrap_store(db, key, string_term_tdb_data(name), 0);
     385          36 :         return status;
     386             : }
     387             : 
     388          10 : static void wb_group_members_done(struct tevent_req *subreq)
     389             : {
     390          10 :         struct tevent_req *req = tevent_req_callback_data(
     391             :                 subreq, struct tevent_req);
     392          10 :         struct wb_group_members_state *state = tevent_req_data(
     393             :                 req, struct wb_group_members_state);
     394           0 :         uint32_t i, num_groups, new_groups;
     395          10 :         uint32_t num_members = 0;
     396          10 :         struct wbint_Principal *members = NULL;
     397           0 :         NTSTATUS status;
     398             : 
     399          10 :         status = wb_groups_members_recv(subreq, state, &num_members, &members);
     400          10 :         TALLOC_FREE(subreq);
     401          10 :         if (tevent_req_nterror(req, status)) {
     402           8 :                 return;
     403             :         }
     404             : 
     405          10 :         new_groups = 0;
     406          36 :         for (i=0; i<num_members; i++) {
     407          26 :                 switch (members[i].type) {
     408           2 :                 case SID_NAME_DOM_GRP:
     409             :                 case SID_NAME_ALIAS:
     410             :                 case SID_NAME_WKN_GRP:
     411           2 :                         new_groups += 1;
     412           2 :                         break;
     413          24 :                 default:
     414             :                         /* Ignore everything else */
     415          24 :                         break;
     416             :                 }
     417             :         }
     418             : 
     419          10 :         num_groups = 0;
     420          10 :         TALLOC_FREE(state->groups);
     421          10 :         state->groups = talloc_array(state, struct wbint_Principal,
     422             :                                      new_groups);
     423             : 
     424             :         /*
     425             :          * Collect the users into state->users and the groups into
     426             :          * state->groups for the next iteration.
     427             :          */
     428             : 
     429          36 :         for (i=0; i<num_members; i++) {
     430          26 :                 switch (members[i].type) {
     431          24 :                 case SID_NAME_USER:
     432             :                 case SID_NAME_COMPUTER: {
     433             :                         /*
     434             :                          * Add a copy of members[i] to state->users
     435             :                          */
     436          24 :                         status = add_member_to_db(state->users, &members[i].sid,
     437          24 :                                                   members[i].name);
     438          24 :                         if (tevent_req_nterror(req, status)) {
     439           0 :                                 return;
     440             :                         }
     441             : 
     442          24 :                         break;
     443             :                 }
     444           2 :                 case SID_NAME_DOM_GRP:
     445             :                 case SID_NAME_ALIAS:
     446             :                 case SID_NAME_WKN_GRP: {
     447           0 :                         struct wbint_Principal *g;
     448             :                         /*
     449             :                          * Save members[i] for the next round
     450             :                          */
     451           2 :                         g = &state->groups[num_groups];
     452           2 :                         sid_copy(&g->sid, &members[i].sid);
     453           2 :                         g->name = talloc_move(state->groups, &members[i].name);
     454           2 :                         g->type = members[i].type;
     455           2 :                         num_groups += 1;
     456           2 :                         break;
     457             :                 }
     458           0 :                 default:
     459             :                         /* Ignore everything else */
     460           0 :                         break;
     461             :                 }
     462             :         }
     463             : 
     464          10 :         status = wb_group_members_next_subreq(state, state, &subreq);
     465          10 :         if (tevent_req_nterror(req, status)) {
     466           0 :                 return;
     467             :         }
     468          10 :         if (subreq == NULL) {
     469           8 :                 tevent_req_done(req);
     470           8 :                 return;
     471             :         }
     472           2 :         tevent_req_set_callback(subreq, wb_group_members_done, req);
     473             : }
     474             : 
     475        5004 : NTSTATUS wb_group_members_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     476             :                                struct db_context **members)
     477             : {
     478        5004 :         struct wb_group_members_state *state = tevent_req_data(
     479             :                 req, struct wb_group_members_state);
     480           0 :         NTSTATUS status;
     481             : 
     482        5004 :         D_INFO("WB command group_members end.\n");
     483        5004 :         if (tevent_req_is_nterror(req, &status)) {
     484           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     485           0 :                 return status;
     486             :         }
     487        5004 :         *members = talloc_move(mem_ctx, &state->users);
     488        5004 :         return NT_STATUS_OK;
     489             : }

Generated by: LCOV version 1.14