2 Unix SMB/CIFS implementation.
3 async implementation of WINBINDD_SIDS_TO_XIDS
4 Copyright (C) Volker Lendecke 2011
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 "../libcli/security/security.h"
23 #include "librpc/gen_ndr/ndr_wbint_c.h"
24 #include "idmap_cache.h"
26 struct winbindd_sids_to_xids_state
{
27 struct tevent_context
*ev
;
31 struct id_map
*cached
;
33 struct dom_sid
*non_cached
;
34 uint32_t num_non_cached
;
36 struct lsa_RefDomainList
*domains
;
37 struct lsa_TransNameArray
*names
;
39 struct wbint_TransIDArray ids
;
42 static bool winbindd_sids_to_xids_in_cache(struct dom_sid
*sid
,
44 static void winbindd_sids_to_xids_lookupsids_done(struct tevent_req
*subreq
);
45 static void winbindd_sids_to_xids_done(struct tevent_req
*subreq
);
47 struct tevent_req
*winbindd_sids_to_xids_send(TALLOC_CTX
*mem_ctx
,
48 struct tevent_context
*ev
,
49 struct winbindd_cli_state
*cli
,
50 struct winbindd_request
*request
)
52 struct tevent_req
*req
, *subreq
;
53 struct winbindd_sids_to_xids_state
*state
;
56 req
= tevent_req_create(mem_ctx
, &state
,
57 struct winbindd_sids_to_xids_state
);
63 DEBUG(3, ("sids_to_xids\n"));
65 if (request
->extra_len
== 0) {
67 return tevent_req_post(req
, ev
);
69 if (request
->extra_data
.data
[request
->extra_len
-1] != '\0') {
70 DEBUG(10, ("Got invalid sids list\n"));
71 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
72 return tevent_req_post(req
, ev
);
74 if (!parse_sidlist(state
, request
->extra_data
.data
,
75 &state
->sids
, &state
->num_sids
)) {
76 DEBUG(10, ("parse_sidlist failed\n"));
77 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
78 return tevent_req_post(req
, ev
);
81 state
->cached
= TALLOC_ZERO_ARRAY(state
, struct id_map
,
83 if (tevent_req_nomem(state
->cached
, req
)) {
84 return tevent_req_post(req
, ev
);
86 state
->non_cached
= TALLOC_ARRAY(state
, struct dom_sid
,
88 if (tevent_req_nomem(state
->non_cached
, req
)) {
89 return tevent_req_post(req
, ev
);
92 for (i
=0; i
<state
->num_sids
; i
++) {
93 if (winbindd_sids_to_xids_in_cache(&state
->sids
[i
],
97 sid_copy(&state
->non_cached
[state
->num_non_cached
],
99 state
->num_non_cached
+= 1;
102 if (state
->num_non_cached
== 0) {
103 tevent_req_done(req
);
104 return tevent_req_post(req
, ev
);
107 subreq
= wb_lookupsids_send(state
, ev
, state
->non_cached
,
108 state
->num_non_cached
);
109 if (tevent_req_nomem(subreq
, req
)) {
110 return tevent_req_post(req
, ev
);
112 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_lookupsids_done
,
117 static bool winbindd_sids_to_xids_in_cache(struct dom_sid
*sid
,
124 if (!winbindd_use_idmap_cache()) {
128 * SIDS_TO_XIDS is primarily used to resolve the user's group
129 * sids. So we check groups before users.
131 if (idmap_cache_find_sid2gid(sid
, &gid
, &expired
)) {
132 if (expired
&& is_domain_offline(find_our_domain())) {
137 map
->xid
.type
= ID_TYPE_GID
;
138 map
->status
= ID_MAPPED
;
141 if (idmap_cache_find_sid2uid(sid
, &uid
, &expired
)) {
142 if (expired
&& is_domain_online(find_our_domain())) {
147 map
->xid
.type
= ID_TYPE_UID
;
148 map
->status
= ID_MAPPED
;
155 static void winbindd_sids_to_xids_lookupsids_done(struct tevent_req
*subreq
)
157 struct tevent_req
*req
= tevent_req_callback_data(
158 subreq
, struct tevent_req
);
159 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
160 req
, struct winbindd_sids_to_xids_state
);
161 struct winbindd_child
*child
;
165 status
= wb_lookupsids_recv(subreq
, state
, &state
->domains
,
168 if (!NT_STATUS_IS_OK(status
)) {
169 tevent_req_nterror(req
, status
);
173 state
->ids
.num_ids
= state
->num_non_cached
;
174 state
->ids
.ids
= TALLOC_ARRAY(state
, struct wbint_TransID
,
175 state
->num_non_cached
);
176 if (tevent_req_nomem(state
->ids
.ids
, req
)) {
180 for (i
=0; i
<state
->num_non_cached
; i
++) {
181 struct lsa_TranslatedName
*n
= &state
->names
->names
[i
];
182 struct wbint_TransID
*t
= &state
->ids
.ids
[i
];
184 switch (n
->sid_type
) {
186 case SID_NAME_COMPUTER
:
187 t
->type
= WBC_ID_TYPE_UID
;
189 case SID_NAME_DOM_GRP
:
191 case SID_NAME_WKN_GRP
:
192 t
->type
= WBC_ID_TYPE_GID
;
195 t
->type
= WBC_ID_TYPE_NOT_SPECIFIED
;
198 t
->domain_index
= n
->sid_index
;
199 sid_peek_rid(&state
->sids
[i
], &t
->rid
);
200 t
->unix_id
= (uint64_t)-1;
203 child
= idmap_child();
205 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
206 state
, state
->ev
, child
->binding_handle
, state
->domains
,
208 if (tevent_req_nomem(subreq
, req
)) {
211 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_done
, req
);
214 static void winbindd_sids_to_xids_done(struct tevent_req
*subreq
)
216 struct tevent_req
*req
= tevent_req_callback_data(
217 subreq
, struct tevent_req
);
218 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
219 req
, struct winbindd_sids_to_xids_state
);
220 NTSTATUS status
, result
;
222 status
= dcerpc_wbint_Sids2UnixIDs_recv(subreq
, state
, &result
);
224 if (any_nt_status_not_ok(status
, result
, &status
)) {
225 tevent_req_nterror(req
, status
);
228 tevent_req_done(req
);
231 NTSTATUS
winbindd_sids_to_xids_recv(struct tevent_req
*req
,
232 struct winbindd_response
*response
)
234 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
235 req
, struct winbindd_sids_to_xids_state
);
238 uint32_t i
, num_non_cached
;
240 if (tevent_req_is_nterror(req
, &status
)) {
241 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
245 result
= talloc_strdup(response
, "");
246 if (result
== NULL
) {
247 return NT_STATUS_NO_MEMORY
;
252 for (i
=0; i
<state
->num_sids
; i
++) {
254 uint64_t unix_id
= (uint64_t)-1;
257 if (state
->cached
[i
].sid
!= NULL
) {
258 unix_id
= state
->cached
[i
].xid
.id
;
259 if (state
->cached
[i
].xid
.type
== ID_TYPE_UID
) {
265 unix_id
= state
->ids
.ids
[num_non_cached
].unix_id
;
266 switch(state
->ids
.ids
[num_non_cached
].type
) {
267 case WBC_ID_TYPE_UID
:
269 idmap_cache_set_sid2uid(
270 &state
->non_cached
[num_non_cached
],
273 case WBC_ID_TYPE_GID
:
275 idmap_cache_set_sid2gid(
276 &state
->non_cached
[num_non_cached
],
286 result
= talloc_asprintf_append_buffer(
287 result
, "%c%lu\n", type
,
288 (unsigned long)unix_id
);
290 result
= talloc_asprintf_append_buffer(result
, "\n");
292 if (result
== NULL
) {
293 return NT_STATUS_NO_MEMORY
;
297 response
->extra_data
.data
= result
;
298 response
->length
+= talloc_get_size(result
);