LCOV - code coverage report
Current view: top level - source3/winbindd - wb_group_members.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 39 200 19.5 %
Date: 2024-06-13 04:01:37 Functions: 4 12 33.3 %

          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           0 : 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             :         struct tevent_req *req, *subreq;
      62             :         struct wb_lookupgroupmem_state *state;
      63             :         struct winbindd_domain *domain;
      64             : 
      65           0 :         req = tevent_req_create(mem_ctx, &state,
      66             :                                 struct wb_lookupgroupmem_state);
      67           0 :         if (req == NULL) {
      68           0 :                 return NULL;
      69             :         }
      70           0 :         sid_copy(&state->sid, group_sid);
      71             : 
      72           0 :         domain = find_domain_from_sid_noinit(group_sid);
      73           0 :         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           0 :         subreq = dcerpc_wbint_LookupGroupMembers_send(
      79           0 :                 state, ev, dom_child_handle(domain), &state->sid, type,
      80           0 :                 &state->members);
      81           0 :         if (tevent_req_nomem(subreq, req)) {
      82           0 :                 return tevent_req_post(req, ev);
      83             :         }
      84           0 :         tevent_req_set_callback(subreq, wb_lookupgroupmem_done, req);
      85           0 :         return req;
      86             : }
      87             : 
      88           0 : static void wb_lookupgroupmem_done(struct tevent_req *subreq)
      89             : {
      90           0 :         struct tevent_req *req = tevent_req_callback_data(
      91             :                 subreq, struct tevent_req);
      92           0 :         struct wb_lookupgroupmem_state *state = tevent_req_data(
      93             :                 req, struct wb_lookupgroupmem_state);
      94             :         NTSTATUS status, result;
      95             : 
      96           0 :         status = dcerpc_wbint_LookupGroupMembers_recv(subreq, state, &result);
      97           0 :         TALLOC_FREE(subreq);
      98           0 :         if (any_nt_status_not_ok(status, result, &status)) {
      99           0 :                 tevent_req_nterror(req, status);
     100           0 :                 return;
     101             :         }
     102           0 :         tevent_req_done(req);
     103             : }
     104             : 
     105           0 : 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           0 :         struct wb_lookupgroupmem_state *state = tevent_req_data(
     111             :                 req, struct wb_lookupgroupmem_state);
     112             :         NTSTATUS status;
     113             : 
     114           0 :         if (tevent_req_is_nterror(req, &status)) {
     115           0 :                 return status;
     116             :         }
     117             : 
     118           0 :         *num_members = state->members.num_principals;
     119           0 :         *members = talloc_move(mem_ctx, &state->members.principals);
     120           0 :         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           0 : 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           0 :         struct tevent_req *req, *subreq = NULL;
     146             :         struct wb_groups_members_state *state;
     147             :         NTSTATUS status;
     148             : 
     149           0 :         req = tevent_req_create(mem_ctx, &state,
     150             :                                 struct wb_groups_members_state);
     151           0 :         if (req == NULL) {
     152           0 :                 return NULL;
     153             :         }
     154           0 :         state->ev = ev;
     155           0 :         state->groups = groups;
     156           0 :         state->num_groups = num_groups;
     157           0 :         state->next_group = 0;
     158           0 :         state->all_members = NULL;
     159             : 
     160           0 :         D_DEBUG("Looking up %"PRIu32" group(s).\n", num_groups);
     161           0 :         status = wb_groups_members_next_subreq(state, state, &subreq);
     162           0 :         if (tevent_req_nterror(req, status)) {
     163           0 :                 return tevent_req_post(req, ev);
     164             :         }
     165           0 :         if (subreq == NULL) {
     166           0 :                 tevent_req_done(req);
     167           0 :                 return tevent_req_post(req, ev);
     168             :         }
     169           0 :         tevent_req_set_callback(subreq, wb_groups_members_done, req);
     170           0 :         return req;
     171             : }
     172             : 
     173           0 : 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             :         struct tevent_req *subreq;
     178             :         struct wbint_Principal *g;
     179             : 
     180           0 :         if (state->next_group >= state->num_groups) {
     181           0 :                 *psubreq = NULL;
     182           0 :                 return NT_STATUS_OK;
     183             :         }
     184             : 
     185           0 :         g = &state->groups[state->next_group];
     186           0 :         state->next_group += 1;
     187             : 
     188           0 :         subreq = wb_lookupgroupmem_send(mem_ctx, state->ev, &g->sid, g->type);
     189           0 :         if (subreq == NULL) {
     190           0 :                 return NT_STATUS_NO_MEMORY;
     191             :         }
     192           0 :         *psubreq = subreq;
     193           0 :         return NT_STATUS_OK;
     194             : }
     195             : 
     196           0 : static void wb_groups_members_done(struct tevent_req *subreq)
     197             : {
     198           0 :         struct tevent_req *req = tevent_req_callback_data(
     199             :                 subreq, struct tevent_req);
     200           0 :         struct wb_groups_members_state *state = tevent_req_data(
     201             :                 req, struct wb_groups_members_state);
     202             :         uint32_t i, num_all_members;
     203           0 :         uint32_t num_members = 0;
     204           0 :         struct wbint_Principal *members = NULL;
     205             :         NTSTATUS status;
     206             : 
     207           0 :         status = wb_lookupgroupmem_recv(subreq, state, &num_members, &members);
     208           0 :         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           0 :         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           0 :         num_all_members = talloc_array_length(state->all_members);
     225             : 
     226           0 :         D_DEBUG("Adding %"PRIu32" new member(s) to existing %"PRIu32" member(s)\n",
     227             :                 num_members,
     228             :                 num_all_members);
     229             : 
     230           0 :         state->all_members = talloc_realloc(
     231             :                 state, state->all_members, struct wbint_Principal,
     232             :                 num_all_members + num_members);
     233           0 :         if ((num_all_members + num_members != 0)
     234           0 :             && tevent_req_nomem(state->all_members, req)) {
     235           0 :                 return;
     236             :         }
     237           0 :         for (i=0; i<num_members; i++) {
     238             :                 struct wbint_Principal *src, *dst;
     239           0 :                 src = &members[i];
     240           0 :                 dst = &state->all_members[num_all_members + i];
     241           0 :                 sid_copy(&dst->sid, &src->sid);
     242           0 :                 dst->name = talloc_move(state->all_members, &src->name);
     243           0 :                 dst->type = src->type;
     244             :         }
     245           0 :         TALLOC_FREE(members);
     246             : 
     247           0 :         status = wb_groups_members_next_subreq(state, state, &subreq);
     248           0 :         if (tevent_req_nterror(req, status)) {
     249           0 :                 return;
     250             :         }
     251           0 :         if (subreq == NULL) {
     252           0 :                 tevent_req_done(req);
     253           0 :                 return;
     254             :         }
     255           0 :         tevent_req_set_callback(subreq, wb_groups_members_done, req);
     256             : }
     257             : 
     258           0 : 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           0 :         struct wb_groups_members_state *state = tevent_req_data(
     264             :                 req, struct wb_groups_members_state);
     265             :         NTSTATUS status;
     266             : 
     267           0 :         if (tevent_req_is_nterror(req, &status)) {
     268           0 :                 return status;
     269             :         }
     270           0 :         *num_members = talloc_array_length(state->all_members);
     271           0 :         *members = talloc_move(mem_ctx, &state->all_members);
     272           0 :         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        2894 : struct tevent_req *wb_group_members_send(TALLOC_CTX *mem_ctx,
     295             :                                          struct tevent_context *ev,
     296             :                                          const struct dom_sid *sid,
     297             :                                          enum lsa_SidType type,
     298             :                                          int max_depth)
     299             : {
     300        2894 :         struct tevent_req *req, *subreq = NULL;
     301             :         struct wb_group_members_state *state;
     302             :         NTSTATUS status;
     303             :         struct dom_sid_buf buf;
     304             : 
     305        2894 :         req = tevent_req_create(mem_ctx, &state,
     306             :                                 struct wb_group_members_state);
     307        2894 :         if (req == NULL) {
     308           0 :                 return NULL;
     309             :         }
     310        2894 :         D_INFO("WB command group_members start.\n"
     311             :                "Looking up domain SID %s with SID type %d and max_depth %d.\n",
     312             :                dom_sid_str_buf(sid, &buf),
     313             :                type,
     314             :                max_depth);
     315             : 
     316        2894 :         state->ev = ev;
     317        2894 :         state->depth = max_depth;
     318        2894 :         state->users = db_open_rbt(state);
     319        2894 :         if (tevent_req_nomem(state->users, req)) {
     320           0 :                 return tevent_req_post(req, ev);
     321             :         }
     322             : 
     323        2894 :         state->groups = talloc(state, struct wbint_Principal);
     324        2894 :         if (tevent_req_nomem(state->groups, req)) {
     325           0 :                 return tevent_req_post(req, ev);
     326             :         }
     327        2894 :         state->groups->name = NULL;
     328        2894 :         sid_copy(&state->groups->sid, sid);
     329        2894 :         state->groups->type = type;
     330             : 
     331        2894 :         status = wb_group_members_next_subreq(state, state, &subreq);
     332        2894 :         if (tevent_req_nterror(req, status)) {
     333           0 :                 return tevent_req_post(req, ev);
     334             :         }
     335        2894 :         if (subreq == NULL) {
     336        2894 :                 tevent_req_done(req);
     337        2894 :                 return tevent_req_post(req, ev);
     338             :         }
     339           0 :         tevent_req_set_callback(subreq, wb_group_members_done, req);
     340           0 :         return req;
     341             : }
     342             : 
     343        2894 : static NTSTATUS wb_group_members_next_subreq(
     344             :         struct wb_group_members_state *state,
     345             :         TALLOC_CTX *mem_ctx, struct tevent_req **psubreq)
     346             : {
     347             :         struct tevent_req *subreq;
     348             : 
     349        2894 :         if ((talloc_array_length(state->groups) == 0)
     350        2894 :             || (state->depth <= 0)) {
     351        2894 :                 *psubreq = NULL;
     352        2894 :                 D_DEBUG("Finished. The depth is %d.\n", state->depth);
     353        2894 :                 return NT_STATUS_OK;
     354             :         }
     355           0 :         state->depth -= 1;
     356             : 
     357           0 :         D_DEBUG("The depth is decremented to %d.\n", state->depth);
     358           0 :         subreq = wb_groups_members_send(
     359           0 :                 mem_ctx, state->ev, talloc_array_length(state->groups),
     360             :                 state->groups);
     361           0 :         if (subreq == NULL) {
     362           0 :                 return NT_STATUS_NO_MEMORY;
     363             :         }
     364           0 :         *psubreq = subreq;
     365           0 :         return NT_STATUS_OK;
     366             : }
     367             : 
     368           8 : NTSTATUS add_member_to_db(struct db_context *db, struct dom_sid *sid,
     369             :                           const char *name)
     370           8 : {
     371           8 :         size_t len = ndr_size_dom_sid(sid, 0);
     372           8 :         uint8_t sidbuf[len];
     373           8 :         TDB_DATA key = { .dptr = sidbuf, .dsize = sizeof(sidbuf) };
     374             :         NTSTATUS status;
     375             : 
     376           8 :         sid_linearize(sidbuf, sizeof(sidbuf), sid);
     377             : 
     378           8 :         status = dbwrap_store(db, key, string_term_tdb_data(name), 0);
     379           8 :         return status;
     380             : }
     381             : 
     382           0 : static void wb_group_members_done(struct tevent_req *subreq)
     383             : {
     384           0 :         struct tevent_req *req = tevent_req_callback_data(
     385             :                 subreq, struct tevent_req);
     386           0 :         struct wb_group_members_state *state = tevent_req_data(
     387             :                 req, struct wb_group_members_state);
     388             :         uint32_t i, num_groups, new_groups;
     389           0 :         uint32_t num_members = 0;
     390           0 :         struct wbint_Principal *members = NULL;
     391             :         NTSTATUS status;
     392             : 
     393           0 :         status = wb_groups_members_recv(subreq, state, &num_members, &members);
     394           0 :         TALLOC_FREE(subreq);
     395           0 :         if (tevent_req_nterror(req, status)) {
     396           0 :                 return;
     397             :         }
     398             : 
     399           0 :         new_groups = 0;
     400           0 :         for (i=0; i<num_members; i++) {
     401           0 :                 switch (members[i].type) {
     402           0 :                 case SID_NAME_DOM_GRP:
     403             :                 case SID_NAME_ALIAS:
     404             :                 case SID_NAME_WKN_GRP:
     405           0 :                         new_groups += 1;
     406           0 :                         break;
     407           0 :                 default:
     408             :                         /* Ignore everything else */
     409           0 :                         break;
     410             :                 }
     411             :         }
     412             : 
     413           0 :         num_groups = 0;
     414           0 :         TALLOC_FREE(state->groups);
     415           0 :         state->groups = talloc_array(state, struct wbint_Principal,
     416             :                                      new_groups);
     417             : 
     418             :         /*
     419             :          * Collect the users into state->users and the groups into
     420             :          * state->groups for the next iteration.
     421             :          */
     422             : 
     423           0 :         for (i=0; i<num_members; i++) {
     424           0 :                 switch (members[i].type) {
     425           0 :                 case SID_NAME_USER:
     426             :                 case SID_NAME_COMPUTER: {
     427             :                         /*
     428             :                          * Add a copy of members[i] to state->users
     429             :                          */
     430           0 :                         status = add_member_to_db(state->users, &members[i].sid,
     431           0 :                                                   members[i].name);
     432           0 :                         if (tevent_req_nterror(req, status)) {
     433           0 :                                 return;
     434             :                         }
     435             : 
     436           0 :                         break;
     437             :                 }
     438           0 :                 case SID_NAME_DOM_GRP:
     439             :                 case SID_NAME_ALIAS:
     440             :                 case SID_NAME_WKN_GRP: {
     441             :                         struct wbint_Principal *g;
     442             :                         /*
     443             :                          * Save members[i] for the next round
     444             :                          */
     445           0 :                         g = &state->groups[num_groups];
     446           0 :                         sid_copy(&g->sid, &members[i].sid);
     447           0 :                         g->name = talloc_move(state->groups, &members[i].name);
     448           0 :                         g->type = members[i].type;
     449           0 :                         num_groups += 1;
     450           0 :                         break;
     451             :                 }
     452           0 :                 default:
     453             :                         /* Ignore everything else */
     454           0 :                         break;
     455             :                 }
     456             :         }
     457             : 
     458           0 :         status = wb_group_members_next_subreq(state, state, &subreq);
     459           0 :         if (tevent_req_nterror(req, status)) {
     460           0 :                 return;
     461             :         }
     462           0 :         if (subreq == NULL) {
     463           0 :                 tevent_req_done(req);
     464           0 :                 return;
     465             :         }
     466           0 :         tevent_req_set_callback(subreq, wb_group_members_done, req);
     467             : }
     468             : 
     469        2894 : NTSTATUS wb_group_members_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     470             :                                struct db_context **members)
     471             : {
     472        2894 :         struct wb_group_members_state *state = tevent_req_data(
     473             :                 req, struct wb_group_members_state);
     474             :         NTSTATUS status;
     475             : 
     476        2894 :         D_INFO("WB command group_members end.\n");
     477        2894 :         if (tevent_req_is_nterror(req, &status)) {
     478           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     479           0 :                 return status;
     480             :         }
     481        2894 :         *members = talloc_move(mem_ctx, &state->users);
     482        2894 :         return NT_STATUS_OK;
     483             : }

Generated by: LCOV version 1.13