LCOV - code coverage report
Current view: top level - source3/winbindd - wb_getgrsid.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 133 194 68.6 %
Date: 2024-04-21 15:09:00 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async getgrsid
       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 "../libcli/security/security.h"
      24             : #include "lib/dbwrap/dbwrap_rbt.h"
      25             : #include "lib/dbwrap/dbwrap.h"
      26             : 
      27             : struct wb_getgrsid_state {
      28             :         struct tevent_context *ev;
      29             :         struct dom_sid sid;
      30             :         int max_nesting;
      31             :         const char *domname;
      32             :         const char *name;
      33             :         enum lsa_SidType type;
      34             :         gid_t gid;
      35             :         struct db_context *members;
      36             :         uint32_t num_sids;
      37             :         struct dom_sid *sids;
      38             : };
      39             : 
      40             : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq);
      41             : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq);
      42             : static void wb_getgrsid_got_members(struct tevent_req *subreq);
      43             : static void wb_getgrsid_got_alias_members(struct tevent_req *subreq);
      44             : 
      45        5720 : struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
      46             :                                     struct tevent_context *ev,
      47             :                                     const struct dom_sid *group_sid,
      48             :                                     int max_nesting)
      49             : {
      50           0 :         struct tevent_req *req, *subreq;
      51           0 :         struct wb_getgrsid_state *state;
      52           0 :         struct dom_sid_buf buf;
      53             : 
      54        5720 :         req = tevent_req_create(mem_ctx, &state, struct wb_getgrsid_state);
      55        5720 :         if (req == NULL) {
      56           0 :                 return NULL;
      57             :         }
      58             : 
      59        5720 :         D_INFO("WB command getgrsid start.\nLooking up group SID %s.\n", dom_sid_str_buf(group_sid, &buf));
      60             : 
      61        5720 :         sid_copy(&state->sid, group_sid);
      62        5720 :         state->ev = ev;
      63        5720 :         state->max_nesting = max_nesting;
      64             : 
      65        5720 :         if (dom_sid_in_domain(&global_sid_Unix_Groups, group_sid)) {
      66             :                 /* unmapped Unix groups must be resolved locally */
      67           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
      68           0 :                 return tevent_req_post(req, ev);
      69             :         }
      70             : 
      71        5720 :         subreq = wb_lookupsid_send(state, ev, &state->sid);
      72        5720 :         if (tevent_req_nomem(subreq, req)) {
      73           0 :                 return tevent_req_post(req, ev);
      74             :         }
      75        5720 :         tevent_req_set_callback(subreq, wb_getgrsid_lookupsid_done, req);
      76        5720 :         return req;
      77             : }
      78             : 
      79        5720 : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq)
      80             : {
      81        5720 :         struct tevent_req *req = tevent_req_callback_data(
      82             :                 subreq, struct tevent_req);
      83        5720 :         struct wb_getgrsid_state *state = tevent_req_data(
      84             :                 req, struct wb_getgrsid_state);
      85           0 :         NTSTATUS status;
      86             : 
      87        5720 :         status = wb_lookupsid_recv(subreq, state, &state->type,
      88             :                                    &state->domname, &state->name);
      89        5720 :         TALLOC_FREE(subreq);
      90        5720 :         if (tevent_req_nterror(req, status)) {
      91           0 :                 return;
      92             :         }
      93             : 
      94        5720 :         switch (state->type) {
      95        5720 :         case SID_NAME_DOM_GRP:
      96             :         case SID_NAME_ALIAS:
      97             :         case SID_NAME_WKN_GRP:
      98             :         /*
      99             :          * also treat user-type SIDS (they might map to ID_TYPE_BOTH)
     100             :          */
     101             :         case SID_NAME_USER:
     102             :         case SID_NAME_COMPUTER:
     103        5720 :                 break;
     104           0 :         default:
     105           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
     106           0 :                 return;
     107             :         }
     108             : 
     109        5720 :         subreq = wb_sids2xids_send(state, state->ev, &state->sid, 1);
     110        5720 :         if (tevent_req_nomem(subreq, req)) {
     111           0 :                 return;
     112             :         }
     113        5720 :         tevent_req_set_callback(subreq, wb_getgrsid_sid2gid_done, req);
     114             : }
     115             : 
     116        5720 : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
     117             : {
     118        5720 :         struct tevent_req *req = tevent_req_callback_data(
     119             :                 subreq, struct tevent_req);
     120        5720 :         struct wb_getgrsid_state *state = tevent_req_data(
     121             :                 req, struct wb_getgrsid_state);
     122           0 :         NTSTATUS status;
     123           0 :         struct unixid xids[1];
     124             : 
     125        5720 :         status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
     126        5720 :         TALLOC_FREE(subreq);
     127        5720 :         if (tevent_req_nterror(req, status)) {
     128          78 :                 return;
     129             :         }
     130             : 
     131             :         /*
     132             :          * We are filtering further down in sids2xids, but that filtering
     133             :          * depends on the actual type of the sid handed in (as determined
     134             :          * by lookupsids). Here we need to filter for the type of object
     135             :          * actually requested, in this case uid.
     136             :          */
     137        5720 :         if (!(xids[0].type == ID_TYPE_GID || xids[0].type == ID_TYPE_BOTH)) {
     138           0 :                 tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
     139           0 :                 return;
     140             :         }
     141             : 
     142        5720 :         state->gid = (gid_t)xids[0].id;
     143             : 
     144        5720 :         switch (state->type) {
     145           8 :         case SID_NAME_USER:
     146             :         case SID_NAME_COMPUTER: {
     147             :                 /*
     148             :                  * special treatment for a user sid that is
     149             :                  * mapped to ID_TYPE_BOTH:
     150             :                  * create a group with the sid/xid as only member
     151             :                  */
     152           0 :                 const char *name;
     153             : 
     154           8 :                 if (xids[0].type != ID_TYPE_BOTH) {
     155           0 :                         tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
     156           0 :                         return;
     157             :                 }
     158             : 
     159           8 :                 state->members = db_open_rbt(state);
     160           8 :                 if (tevent_req_nomem(state->members, req)) {
     161           0 :                         return;
     162             :                 }
     163             : 
     164           8 :                 name = fill_domain_username_talloc(talloc_tos(),
     165             :                                                    state->domname,
     166             :                                                    state->name,
     167             :                                                    true /* can_assume */);
     168           8 :                 if (tevent_req_nomem(name, req)) {
     169           0 :                         return;
     170             :                 }
     171             : 
     172           8 :                 status = add_member_to_db(state->members, &state->sid, name);
     173           8 :                 if (!NT_STATUS_IS_OK(status)) {
     174           0 :                         tevent_req_nterror(req, status);
     175           0 :                         return;
     176             :                 }
     177             : 
     178           8 :                 tevent_req_done(req);
     179           8 :                 return;
     180             :         }
     181         640 :         case SID_NAME_ALIAS:
     182         640 :                 subreq = wb_alias_members_send(state,
     183             :                                                state->ev,
     184         640 :                                                &state->sid,
     185             :                                                state->type,
     186             :                                                state->max_nesting);
     187         640 :                 if (tevent_req_nomem(subreq, req)) {
     188           0 :                         return;
     189             :                 }
     190             :                 /* Decrement the depth based on 'winbind expand groups' */
     191         640 :                 state->max_nesting--;
     192         640 :                 tevent_req_set_callback(subreq,
     193             :                                         wb_getgrsid_got_alias_members,
     194             :                                         req);
     195        5642 :                 break;
     196        5002 :         case SID_NAME_DOM_GRP:
     197        5002 :                 subreq = wb_group_members_send(state,
     198             :                                                state->ev,
     199        5002 :                                                &state->sid,
     200             :                                                1,
     201             :                                                &state->type,
     202             :                                                state->max_nesting);
     203        5002 :                 if (tevent_req_nomem(subreq, req)) {
     204           0 :                         return;
     205             :                 }
     206        5002 :                 tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
     207        5002 :                 break;
     208          70 :         case SID_NAME_WKN_GRP:
     209          70 :                 state->members = db_open_rbt(state);
     210          70 :                 if (tevent_req_nomem(state->members, req)) {
     211           0 :                         return;
     212             :                 }
     213          70 :                 tevent_req_done(req);
     214          70 :                 return;
     215           0 :         default:
     216           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
     217           0 :                 break;
     218             :         }
     219             : }
     220             : 
     221         640 : static void wb_getgrsid_got_alias_members_names(struct tevent_req *subreq)
     222             : {
     223           0 :         struct tevent_req *req =
     224         640 :                 tevent_req_callback_data(subreq, struct tevent_req);
     225           0 :         struct wb_getgrsid_state *state =
     226         640 :                 tevent_req_data(req, struct wb_getgrsid_state);
     227         640 :         struct lsa_RefDomainList *domains = NULL;
     228         640 :         struct lsa_TransNameArray *names = NULL;
     229           0 :         NTSTATUS status;
     230           0 :         uint32_t li;
     231         640 :         uint32_t num_sids = 0;
     232         640 :         struct dom_sid *sids = NULL;
     233         640 :         enum lsa_SidType *types = NULL;
     234             : 
     235         640 :         status = wb_lookupsids_recv(subreq, state, &domains, &names);
     236             : 
     237         640 :         TALLOC_FREE(subreq);
     238         640 :         if (tevent_req_nterror(req, status)) {
     239           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     240         638 :                 return;
     241             :         }
     242             : 
     243         640 :         if (domains == NULL) {
     244           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     245           0 :                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     246           0 :                 return;
     247             :         }
     248             : 
     249         640 :         if (names == NULL) {
     250           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     251           0 :                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     252           0 :                 return;
     253             :         }
     254             : 
     255         640 :         state->members = db_open_rbt(state);
     256         640 :         if (tevent_req_nomem(state->members, req)) {
     257           0 :                 return;
     258             :         }
     259             : 
     260         650 :         for (li = 0; li < state->num_sids; li++) {
     261          10 :                 struct lsa_TranslatedName *n = &names->names[li];
     262             : 
     263          10 :                 if (n->sid_type == SID_NAME_USER ||
     264          10 :                     n->sid_type == SID_NAME_COMPUTER) {
     265           4 :                         const char *name = fill_domain_username_talloc(
     266             :                                 talloc_tos(),
     267           4 :                                 domains->domains[n->sid_index].name.string,
     268             :                                 n->name.string,
     269             :                                 false /* can_assume */);
     270           4 :                         if (tevent_req_nomem(name, req)) {
     271           0 :                                 return;
     272             :                         }
     273             : 
     274           4 :                         status = add_member_to_db(state->members,
     275           4 :                                                   &state->sids[li],
     276             :                                                   name);
     277           4 :                         if (!NT_STATUS_IS_OK(status)) {
     278           0 :                                 tevent_req_nterror(req, status);
     279           0 :                                 return;
     280             :                         }
     281           6 :                 } else if (n->sid_type == SID_NAME_DOM_GRP) {
     282           6 :                         sids = talloc_realloc(talloc_tos(),
     283             :                                               sids,
     284             :                                               struct dom_sid,
     285             :                                               num_sids + 1);
     286           6 :                         if (tevent_req_nomem(sids, req)) {
     287           0 :                                 return;
     288             :                         }
     289           6 :                         sids[num_sids] = state->sids[li];
     290           6 :                         types = talloc_realloc(talloc_tos(),
     291             :                                                types,
     292             :                                                enum lsa_SidType,
     293             :                                                num_sids + 1);
     294           6 :                         if (tevent_req_nomem(types, req)) {
     295           0 :                                 return;
     296             :                         }
     297           6 :                         types[num_sids] = n->sid_type;
     298           6 :                         num_sids++;
     299             :                 } else {
     300           0 :                         struct dom_sid_buf buf;
     301           0 :                         D_DEBUG("SID %s with sid_type=%d is ignored!\n",
     302             :                                 dom_sid_str_buf(&state->sids[li], &buf),
     303             :                                 n->sid_type);
     304             :                 }
     305             :         }
     306             : 
     307         640 :         TALLOC_FREE(names);
     308         640 :         TALLOC_FREE(domains);
     309             : 
     310         640 :         if (num_sids == 0) {
     311         638 :                 tevent_req_done(req);
     312         638 :                 return;
     313             :         }
     314           2 :         subreq = wb_group_members_send(state,
     315             :                                        state->ev,
     316             :                                        sids,
     317             :                                        num_sids,
     318             :                                        types,
     319             :                                        state->max_nesting);
     320           2 :         if (tevent_req_nomem(subreq, req)) {
     321           0 :                 return;
     322             :         }
     323           2 :         tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
     324             : }
     325             : 
     326         640 : static void wb_getgrsid_got_alias_members(struct tevent_req *subreq)
     327             : {
     328           0 :         struct tevent_req *req =
     329         640 :                 tevent_req_callback_data(subreq, struct tevent_req);
     330           0 :         struct wb_getgrsid_state *state =
     331         640 :                 tevent_req_data(req, struct wb_getgrsid_state);
     332           0 :         NTSTATUS status;
     333             : 
     334         640 :         status = wb_alias_members_recv(subreq,
     335             :                                        state,
     336             :                                        &state->num_sids,
     337             :                                        &state->sids);
     338         640 :         TALLOC_FREE(subreq);
     339         640 :         if (tevent_req_nterror(req, status)) {
     340           0 :                 return;
     341             :         }
     342             : 
     343         640 :         subreq = wb_lookupsids_send(state,
     344             :                                     state->ev,
     345             :                                     state->sids,
     346             :                                     state->num_sids);
     347         640 :         if (tevent_req_nomem(subreq, req)) {
     348           0 :                 return;
     349             :         }
     350         640 :         tevent_req_set_callback(subreq,
     351             :                                 wb_getgrsid_got_alias_members_names,
     352             :                                 req);
     353             : }
     354             : 
     355        5004 : static void wb_getgrsid_got_members(struct tevent_req *subreq)
     356             : {
     357        5004 :         struct tevent_req *req = tevent_req_callback_data(
     358             :                 subreq, struct tevent_req);
     359        5004 :         struct wb_getgrsid_state *state = tevent_req_data(
     360             :                 req, struct wb_getgrsid_state);
     361           0 :         NTSTATUS status;
     362        5004 :         struct db_context *members_prev = state->members;
     363             : 
     364        5004 :         status = wb_group_members_recv(subreq, state, &state->members);
     365        5004 :         TALLOC_FREE(subreq);
     366        5004 :         if (tevent_req_nterror(req, status)) {
     367           0 :                 return;
     368             :         }
     369             :         /*
     370             :          * If we have called wb_alias_members_send(), members_prev
     371             :          * might already contain users that are direct members of alias,
     372             :          * add to them the users from nested groups.
     373             :          */
     374        5004 :         if (members_prev != NULL) {
     375           2 :                 status = dbwrap_merge_dbs(state->members,
     376             :                                           members_prev,
     377             :                                           TDB_REPLACE);
     378           2 :                 if (tevent_req_nterror(req, status)) {
     379           0 :                         return;
     380             :                 }
     381             :         }
     382        5004 :         tevent_req_done(req);
     383             : }
     384             : 
     385        5720 : NTSTATUS wb_getgrsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     386             :                           const char **domname, const char **name, gid_t *gid,
     387             :                           struct db_context **members)
     388             : {
     389        5720 :         struct wb_getgrsid_state *state = tevent_req_data(
     390             :                 req, struct wb_getgrsid_state);
     391           0 :         NTSTATUS status;
     392             : 
     393        5720 :         D_INFO("WB command getgrsid end.\n");
     394        5720 :         if (tevent_req_is_nterror(req, &status)) {
     395           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     396           0 :                 return status;
     397             :         }
     398        5720 :         *domname = talloc_move(mem_ctx, &state->domname);
     399        5720 :         *name = talloc_move(mem_ctx, &state->name);
     400        5720 :         *gid = state->gid;
     401        5720 :         *members = talloc_move(mem_ctx, &state->members);
     402        5720 :         return NT_STATUS_OK;
     403             : }

Generated by: LCOV version 1.14