2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2009
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.
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.
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/>.
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"
27 struct wb_getgrsid_state {
28 struct tevent_context *ev;
33 enum lsa_SidType type;
35 struct db_context *members;
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);
45 struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
46 struct tevent_context *ev,
47 const struct dom_sid *group_sid,
50 struct tevent_req *req, *subreq;
51 struct wb_getgrsid_state *state;
52 struct dom_sid_buf buf;
54 req = tevent_req_create(mem_ctx, &state, struct wb_getgrsid_state);
59 D_INFO("WB command getgrsid start.\nLooking up group SID %s.\n", dom_sid_str_buf(group_sid, &buf));
61 sid_copy(&state->sid, group_sid);
63 state->max_nesting = max_nesting;
65 if (dom_sid_in_domain(&global_sid_Unix_Groups, group_sid)) {
66 /* unmapped Unix groups must be resolved locally */
67 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
68 return tevent_req_post(req, ev);
71 subreq = wb_lookupsid_send(state, ev, &state->sid);
72 if (tevent_req_nomem(subreq, req)) {
73 return tevent_req_post(req, ev);
75 tevent_req_set_callback(subreq, wb_getgrsid_lookupsid_done, req);
79 static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq)
81 struct tevent_req *req = tevent_req_callback_data(
82 subreq, struct tevent_req);
83 struct wb_getgrsid_state *state = tevent_req_data(
84 req, struct wb_getgrsid_state);
87 status = wb_lookupsid_recv(subreq, state, &state->type,
88 &state->domname, &state->name);
90 if (tevent_req_nterror(req, status)) {
94 switch (state->type) {
95 case SID_NAME_DOM_GRP:
97 case SID_NAME_WKN_GRP:
99 * also treat user-type SIDS (they might map to ID_TYPE_BOTH)
102 case SID_NAME_COMPUTER:
105 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
109 subreq = wb_sids2xids_send(state, state->ev, &state->sid, 1);
110 if (tevent_req_nomem(subreq, req)) {
113 tevent_req_set_callback(subreq, wb_getgrsid_sid2gid_done, req);
116 static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
118 struct tevent_req *req = tevent_req_callback_data(
119 subreq, struct tevent_req);
120 struct wb_getgrsid_state *state = tevent_req_data(
121 req, struct wb_getgrsid_state);
123 struct unixid xids[1];
125 status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
127 if (tevent_req_nterror(req, status)) {
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.
137 if (!(xids[0].type == ID_TYPE_GID || xids[0].type == ID_TYPE_BOTH)) {
138 tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
142 state->gid = (gid_t)xids[0].id;
144 switch (state->type) {
146 case SID_NAME_COMPUTER: {
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
154 if (xids[0].type != ID_TYPE_BOTH) {
155 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
159 state->members = db_open_rbt(state);
160 if (tevent_req_nomem(state->members, req)) {
164 name = fill_domain_username_talloc(talloc_tos(),
167 true /* can_assume */);
168 if (tevent_req_nomem(name, req)) {
172 status = add_member_to_db(state->members, &state->sid, name);
173 if (!NT_STATUS_IS_OK(status)) {
174 tevent_req_nterror(req, status);
178 tevent_req_done(req);
182 subreq = wb_alias_members_send(state,
187 if (tevent_req_nomem(subreq, req)) {
190 /* Decrement the depth based on 'winbind expand groups' */
191 state->max_nesting--;
192 tevent_req_set_callback(subreq,
193 wb_getgrsid_got_alias_members,
196 case SID_NAME_DOM_GRP:
197 subreq = wb_group_members_send(state,
203 if (tevent_req_nomem(subreq, req)) {
206 tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
208 case SID_NAME_WKN_GRP:
209 state->members = db_open_rbt(state);
210 if (tevent_req_nomem(state->members, req)) {
213 tevent_req_done(req);
216 tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
221 static void wb_getgrsid_got_alias_members_names(struct tevent_req *subreq)
223 struct tevent_req *req =
224 tevent_req_callback_data(subreq, struct tevent_req);
225 struct wb_getgrsid_state *state =
226 tevent_req_data(req, struct wb_getgrsid_state);
227 struct lsa_RefDomainList *domains = NULL;
228 struct lsa_TransNameArray *names = NULL;
231 uint32_t num_sids = 0;
232 struct dom_sid *sids = NULL;
233 enum lsa_SidType *types = NULL;
235 status = wb_lookupsids_recv(subreq, state, &domains, &names);
238 if (tevent_req_nterror(req, status)) {
239 D_WARNING("Failed with %s.\n", nt_errstr(status));
243 if (domains == NULL) {
244 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
245 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
250 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
251 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
255 state->members = db_open_rbt(state);
256 if (tevent_req_nomem(state->members, req)) {
260 for (li = 0; li < state->num_sids; li++) {
261 struct lsa_TranslatedName *n = &names->names[li];
263 if (n->sid_type == SID_NAME_USER ||
264 n->sid_type == SID_NAME_COMPUTER) {
265 const char *name = fill_domain_username_talloc(
267 domains->domains[n->sid_index].name.string,
269 false /* can_assume */);
270 if (tevent_req_nomem(name, req)) {
274 status = add_member_to_db(state->members,
277 if (!NT_STATUS_IS_OK(status)) {
278 tevent_req_nterror(req, status);
281 } else if (n->sid_type == SID_NAME_DOM_GRP) {
282 sids = talloc_realloc(talloc_tos(),
286 if (tevent_req_nomem(sids, req)) {
289 sids[num_sids] = state->sids[li];
290 types = talloc_realloc(talloc_tos(),
294 if (tevent_req_nomem(types, req)) {
297 types[num_sids] = n->sid_type;
300 struct dom_sid_buf buf;
301 D_DEBUG("SID %s with sid_type=%d is ignored!\n",
302 dom_sid_str_buf(&state->sids[li], &buf),
308 TALLOC_FREE(domains);
311 tevent_req_done(req);
314 subreq = wb_group_members_send(state,
320 if (tevent_req_nomem(subreq, req)) {
323 tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
326 static void wb_getgrsid_got_alias_members(struct tevent_req *subreq)
328 struct tevent_req *req =
329 tevent_req_callback_data(subreq, struct tevent_req);
330 struct wb_getgrsid_state *state =
331 tevent_req_data(req, struct wb_getgrsid_state);
334 status = wb_alias_members_recv(subreq,
339 if (tevent_req_nterror(req, status)) {
343 subreq = wb_lookupsids_send(state,
347 if (tevent_req_nomem(subreq, req)) {
350 tevent_req_set_callback(subreq,
351 wb_getgrsid_got_alias_members_names,
355 static void wb_getgrsid_got_members(struct tevent_req *subreq)
357 struct tevent_req *req = tevent_req_callback_data(
358 subreq, struct tevent_req);
359 struct wb_getgrsid_state *state = tevent_req_data(
360 req, struct wb_getgrsid_state);
362 struct db_context *members_prev = state->members;
364 status = wb_group_members_recv(subreq, state, &state->members);
366 if (tevent_req_nterror(req, status)) {
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.
374 if (members_prev != NULL) {
375 status = dbwrap_merge_dbs(state->members,
378 if (tevent_req_nterror(req, status)) {
382 tevent_req_done(req);
385 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)
389 struct wb_getgrsid_state *state = tevent_req_data(
390 req, struct wb_getgrsid_state);
393 D_INFO("WB command getgrsid end.\n");
394 if (tevent_req_is_nterror(req, &status)) {
395 D_WARNING("Failed with %s.\n", nt_errstr(status));
398 *domname = talloc_move(mem_ctx, &state->domname);
399 *name = talloc_move(mem_ctx, &state->name);
401 *members = talloc_move(mem_ctx, &state->members);