LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_getgroups.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 90 127 70.9 %
Date: 2024-02-28 12:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async implementation of WINBINDD_GETGROUPS
       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 "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */
      23             : #include "libcli/security/dom_sid.h"
      24             : 
      25             : struct winbindd_getgroups_state {
      26             :         struct tevent_context *ev;
      27             :         char *namespace;
      28             :         char *domname;
      29             :         char *username;
      30             :         struct dom_sid sid;
      31             :         enum lsa_SidType type;
      32             :         uint32_t num_sids;
      33             :         struct dom_sid *sids;
      34             :         uint32_t num_gids;
      35             :         gid_t *gids;
      36             : };
      37             : 
      38             : static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq);
      39             : static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq);
      40             : static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq);
      41             : 
      42        1970 : struct tevent_req *winbindd_getgroups_send(TALLOC_CTX *mem_ctx,
      43             :                                            struct tevent_context *ev,
      44             :                                            struct winbindd_cli_state *cli,
      45             :                                            struct winbindd_request *request)
      46             : {
      47           0 :         struct tevent_req *req, *subreq;
      48           0 :         struct winbindd_getgroups_state *state;
      49           0 :         char *domuser, *mapped_user;
      50           0 :         NTSTATUS status;
      51           0 :         bool ok;
      52             : 
      53        1970 :         req = tevent_req_create(mem_ctx, &state,
      54             :                                 struct winbindd_getgroups_state);
      55        1970 :         if (req == NULL) {
      56           0 :                 return NULL;
      57             :         }
      58        1970 :         state->ev = ev;
      59             : 
      60             :         /* Ensure null termination */
      61        1970 :         request->data.username[sizeof(request->data.username)-1]='\0';
      62             : 
      63        1970 :         D_NOTICE("[%s (%u)] Winbind external command GETGROUPS start.\n"
      64             :                  "Searching groups for username '%s'.\n",
      65             :                  cli->client_name,
      66             :                  (unsigned int)cli->pid,
      67             :                  request->data.username);
      68             : 
      69        1970 :         domuser = request->data.username;
      70             : 
      71        1970 :         status = normalize_name_unmap(state, domuser, &mapped_user);
      72             : 
      73        1970 :         if (NT_STATUS_IS_OK(status)
      74        1970 :             || NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
      75             :                 /* normalize_name_unmapped did something */
      76           0 :                 domuser = mapped_user;
      77             :         }
      78             : 
      79        1970 :         ok = parse_domain_user(state, domuser,
      80        1970 :                                &state->namespace,
      81        1970 :                                &state->domname,
      82        1970 :                                &state->username);
      83        1970 :         if (!ok) {
      84           0 :                 D_WARNING("Could not parse domain user: %s\n", domuser);
      85           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
      86           0 :                 return tevent_req_post(req, ev);
      87             :         }
      88             : 
      89        1970 :         subreq = wb_lookupname_send(state, ev,
      90        1970 :                                     state->namespace,
      91        1970 :                                     state->domname,
      92        1970 :                                     state->username,
      93             :                                     LOOKUP_NAME_NO_NSS);
      94        1970 :         if (tevent_req_nomem(subreq, req)) {
      95           0 :                 return tevent_req_post(req, ev);
      96             :         }
      97        1970 :         tevent_req_set_callback(subreq, winbindd_getgroups_lookupname_done,
      98             :                                 req);
      99        1970 :         return req;
     100             : }
     101             : 
     102        1970 : static void winbindd_getgroups_lookupname_done(struct tevent_req *subreq)
     103             : {
     104        1970 :         struct tevent_req *req = tevent_req_callback_data(
     105             :                 subreq, struct tevent_req);
     106        1970 :         struct winbindd_getgroups_state *state = tevent_req_data(
     107             :                 req, struct winbindd_getgroups_state);
     108           0 :         NTSTATUS status;
     109             : 
     110        1970 :         status = wb_lookupname_recv(subreq, &state->sid, &state->type);
     111        1970 :         TALLOC_FREE(subreq);
     112        1970 :         if (tevent_req_nterror(req, status)) {
     113           0 :                 return;
     114             :         }
     115             : 
     116        1970 :         subreq = wb_gettoken_send(state, state->ev, &state->sid, true);
     117        1970 :         if (tevent_req_nomem(subreq, req)) {
     118           0 :                 return;
     119             :         }
     120        1970 :         tevent_req_set_callback(subreq, winbindd_getgroups_gettoken_done, req);
     121             : }
     122             : 
     123        1970 : static void winbindd_getgroups_gettoken_done(struct tevent_req *subreq)
     124             : {
     125        1970 :         struct tevent_req *req = tevent_req_callback_data(
     126             :                 subreq, struct tevent_req);
     127        1970 :         struct winbindd_getgroups_state *state = tevent_req_data(
     128             :                 req, struct winbindd_getgroups_state);
     129           0 :         NTSTATUS status;
     130             : 
     131        1970 :         status = wb_gettoken_recv(subreq, state, &state->num_sids,
     132             :                                   &state->sids);
     133        1970 :         TALLOC_FREE(subreq);
     134        1970 :         if (tevent_req_nterror(req, status)) {
     135           0 :                 return;
     136             :         }
     137             : 
     138             :         /*
     139             :          * Convert the group SIDs to gids. state->sids[0] contains the user
     140             :          * sid. If the idmap backend uses ID_TYPE_BOTH, we might need the
     141             :          * the id of the user sid in the list of group sids, so map the
     142             :          * complete token.
     143             :          */
     144             : 
     145        1970 :         subreq = wb_sids2xids_send(state, state->ev,
     146        1970 :                                    state->sids, state->num_sids);
     147        1970 :         if (tevent_req_nomem(subreq, req)) {
     148           0 :                 return;
     149             :         }
     150        1970 :         tevent_req_set_callback(subreq, winbindd_getgroups_sid2gid_done, req);
     151             : }
     152             : 
     153        1970 : static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq)
     154             : {
     155        1970 :         struct tevent_req *req = tevent_req_callback_data(
     156             :                 subreq, struct tevent_req);
     157        1970 :         struct winbindd_getgroups_state *state = tevent_req_data(
     158             :                 req, struct winbindd_getgroups_state);
     159           0 :         NTSTATUS status;
     160           0 :         struct unixid *xids;
     161           0 :         uint32_t i;
     162             : 
     163        1970 :         xids = talloc_array(state, struct unixid, state->num_sids);
     164        1970 :         if (tevent_req_nomem(xids, req)) {
     165           0 :                 return;
     166             :         }
     167        6236 :         for (i=0; i < state->num_sids; i++) {
     168        4266 :                 xids[i].type = ID_TYPE_NOT_SPECIFIED;
     169        4266 :                 xids[i].id = UINT32_MAX;
     170             :         }
     171             : 
     172        1970 :         status = wb_sids2xids_recv(subreq, xids, state->num_sids);
     173        1970 :         TALLOC_FREE(subreq);
     174        1970 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED) ||
     175        1970 :             NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
     176             :         {
     177           0 :                 status = NT_STATUS_OK;
     178             :         }
     179        1970 :         if (tevent_req_nterror(req, status)) {
     180           0 :                 return;
     181             :         }
     182             : 
     183        1970 :         state->gids = talloc_array(state, gid_t, state->num_sids);
     184        1970 :         if (tevent_req_nomem(state->gids, req)) {
     185           0 :                 return;
     186             :         }
     187        1970 :         state->num_gids = 0;
     188             : 
     189        6236 :         for (i=0; i < state->num_sids; i++) {
     190        4266 :                 bool include_gid = false;
     191        4266 :                 const char *debug_missing = NULL;
     192             : 
     193        4266 :                 switch (xids[i].type) {
     194          14 :                 case ID_TYPE_NOT_SPECIFIED:
     195          14 :                         debug_missing = "not specified";
     196          14 :                         break;
     197        1970 :                 case ID_TYPE_UID:
     198        1970 :                         if (i != 0) {
     199           0 :                                 debug_missing = "uid";
     200             :                         }
     201        1970 :                         break;
     202        2282 :                 case ID_TYPE_GID:
     203             :                 case ID_TYPE_BOTH:
     204        2282 :                         include_gid = true;
     205        2282 :                         break;
     206           0 :                 case ID_TYPE_WB_REQUIRE_TYPE:
     207             :                         /*
     208             :                          * these are internal between winbindd
     209             :                          * parent and child.
     210             :                          */
     211           0 :                         smb_panic(__location__);
     212           0 :                         break;
     213             :                 }
     214             : 
     215        4266 :                 if (!include_gid) {
     216           0 :                         struct dom_sid_buf sidbuf;
     217             : 
     218        1984 :                         if (debug_missing == NULL) {
     219        1970 :                                 continue;
     220             :                         }
     221             : 
     222          14 :                         D_WARNING("WARNING: skipping unix id (%"PRIu32") for sid %s "
     223             :                                   "from group list because the idmap type "
     224             :                                   "is %s. "
     225             :                                   "This might be a security problem when ACLs "
     226             :                                   "contain DENY ACEs!\n",
     227             :                                   (unsigned)xids[i].id,
     228             :                                   dom_sid_str_buf(&state->sids[i], &sidbuf),
     229             :                                   debug_missing);
     230          14 :                         continue;
     231             :                 }
     232             : 
     233        2282 :                 state->gids[state->num_gids] = (gid_t)xids[i].id;
     234        2282 :                 state->num_gids += 1;
     235             :         }
     236             : 
     237             :         /*
     238             :          * This should not fail, as it does not do any reallocation,
     239             :          * just updating the talloc size.
     240             :          */
     241        1970 :         state->gids = talloc_realloc(state, state->gids, gid_t, state->num_gids);
     242        1970 :         if (tevent_req_nomem(state->gids, req)) {
     243           0 :                 return;
     244             :         }
     245             : 
     246        1970 :         tevent_req_done(req);
     247             : }
     248             : 
     249        1970 : NTSTATUS winbindd_getgroups_recv(struct tevent_req *req,
     250             :                                  struct winbindd_response *response)
     251             : {
     252        1970 :         struct winbindd_getgroups_state *state = tevent_req_data(
     253             :                 req, struct winbindd_getgroups_state);
     254           0 :         NTSTATUS status;
     255           0 :         uint32_t i;
     256             : 
     257        1970 :         if (tevent_req_is_nterror(req, &status)) {
     258           0 :                 struct dom_sid_buf buf;
     259           0 :                 D_WARNING("Could not convert sid %s: %s\n",
     260             :                           dom_sid_str_buf(&state->sid, &buf),
     261             :                           nt_errstr(status));
     262           0 :                 return status;
     263             :         }
     264             : 
     265        1970 :         response->data.num_entries = state->num_gids;
     266             : 
     267        1970 :         D_NOTICE("Winbind external command GETGROUPS end.\n"
     268             :                  "Received %"PRIu32" entries.\n",
     269             :                  response->data.num_entries);
     270        1970 :         if (CHECK_DEBUGLVL(DBGLVL_NOTICE)) {
     271           0 :                 for (i = 0; i < state->num_gids; i++) {
     272           0 :                         D_NOTICE("%"PRIu32": GID %u\n", i, state->gids[i]);
     273             :                 }
     274             :         }
     275             : 
     276        1970 :         if (state->num_gids > 0) {
     277        1970 :                 response->extra_data.data = talloc_move(response,
     278             :                                                         &state->gids);
     279        1970 :                 response->length += state->num_gids * sizeof(gid_t);
     280             :         }
     281             : 
     282        1970 :         return NT_STATUS_OK;
     283             : }

Generated by: LCOV version 1.14