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
);