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 DEBUG(10, ("num_sids: %d\n", (int)state
->num_sids
));
83 state
->cached
= talloc_zero_array(state
, struct id_map
,
85 if (tevent_req_nomem(state
->cached
, req
)) {
86 return tevent_req_post(req
, ev
);
88 state
->non_cached
= talloc_array(state
, struct dom_sid
,
90 if (tevent_req_nomem(state
->non_cached
, req
)) {
91 return tevent_req_post(req
, ev
);
95 * Extract those sids that can not be resolved from cache
96 * into a separate list to be handed to id mapping, keeping
99 for (i
=0; i
<state
->num_sids
; i
++) {
101 DEBUG(10, ("SID %d: %s\n", (int)i
,
102 sid_string_dbg(&state
->sids
[i
])));
104 if (winbindd_sids_to_xids_in_cache(&state
->sids
[i
],
105 &state
->cached
[i
])) {
108 sid_copy(&state
->non_cached
[state
->num_non_cached
],
110 state
->num_non_cached
+= 1;
113 if (state
->num_non_cached
== 0) {
114 tevent_req_done(req
);
115 return tevent_req_post(req
, ev
);
118 subreq
= wb_lookupsids_send(state
, ev
, state
->non_cached
,
119 state
->num_non_cached
);
120 if (tevent_req_nomem(subreq
, req
)) {
121 return tevent_req_post(req
, ev
);
123 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_lookupsids_done
,
128 static bool winbindd_sids_to_xids_in_cache(struct dom_sid
*sid
,
134 if (!winbindd_use_idmap_cache()) {
137 if (idmap_cache_find_sid2unixid(sid
, &id
, &expired
)) {
138 if (expired
&& is_domain_online(find_our_domain())) {
143 map
->status
= ID_MAPPED
;
149 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
);
151 static void winbindd_sids_to_xids_lookupsids_done(struct tevent_req
*subreq
)
153 struct tevent_req
*req
= tevent_req_callback_data(
154 subreq
, struct tevent_req
);
155 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
156 req
, struct winbindd_sids_to_xids_state
);
157 struct winbindd_child
*child
;
161 status
= wb_lookupsids_recv(subreq
, state
, &state
->domains
,
164 if (tevent_req_nterror(req
, status
)) {
168 state
->ids
.num_ids
= state
->num_non_cached
;
169 state
->ids
.ids
= talloc_array(state
, struct wbint_TransID
,
170 state
->num_non_cached
);
171 if (tevent_req_nomem(state
->ids
.ids
, req
)) {
175 for (i
=0; i
<state
->num_non_cached
; i
++) {
176 struct lsa_TranslatedName
*n
= &state
->names
->names
[i
];
177 struct wbint_TransID
*t
= &state
->ids
.ids
[i
];
179 t
->type
= lsa_SidType_to_id_type(n
->sid_type
);
180 t
->domain_index
= n
->sid_index
;
181 sid_peek_rid(&state
->non_cached
[i
], &t
->rid
);
182 t
->unix_id
= (uint64_t)-1;
185 child
= idmap_child();
187 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
188 state
, state
->ev
, child
->binding_handle
, state
->domains
,
190 if (tevent_req_nomem(subreq
, req
)) {
193 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_done
, req
);
196 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
)
201 case SID_NAME_COMPUTER
:
205 case SID_NAME_DOM_GRP
:
207 case SID_NAME_WKN_GRP
:
211 type
= ID_TYPE_NOT_SPECIFIED
;
219 static void winbindd_sids_to_xids_done(struct tevent_req
*subreq
)
221 struct tevent_req
*req
= tevent_req_callback_data(
222 subreq
, struct tevent_req
);
223 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
224 req
, struct winbindd_sids_to_xids_state
);
225 NTSTATUS status
, result
;
227 status
= dcerpc_wbint_Sids2UnixIDs_recv(subreq
, state
, &result
);
229 if (any_nt_status_not_ok(status
, result
, &status
)) {
230 tevent_req_nterror(req
, status
);
233 tevent_req_done(req
);
236 NTSTATUS
winbindd_sids_to_xids_recv(struct tevent_req
*req
,
237 struct winbindd_response
*response
)
239 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
240 req
, struct winbindd_sids_to_xids_state
);
243 uint32_t i
, num_non_cached
;
245 if (tevent_req_is_nterror(req
, &status
)) {
246 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
250 result
= talloc_strdup(response
, "");
251 if (result
== NULL
) {
252 return NT_STATUS_NO_MEMORY
;
257 for (i
=0; i
<state
->num_sids
; i
++) {
264 if (state
->cached
[i
].sid
!= NULL
) {
265 xid
= state
->cached
[i
].xid
;
267 xid
.id
= state
->ids
.ids
[num_non_cached
].unix_id
;
268 xid
.type
= state
->ids
.ids
[num_non_cached
].type
;
270 idmap_cache_set_sid2unixid(
271 &state
->non_cached
[num_non_cached
],
292 if (xid
.id
== UINT32_MAX
) {
297 result
= talloc_asprintf_append_buffer(
298 result
, "%c%lu\n", type
,
299 (unsigned long)xid
.id
);
301 result
= talloc_asprintf_append_buffer(result
, "\n");
303 if (result
== NULL
) {
304 return NT_STATUS_NO_MEMORY
;
308 response
->extra_data
.data
= result
;
309 response
->length
+= talloc_get_size(result
);