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
);
94 for (i
=0; i
<state
->num_sids
; i
++) {
96 DEBUG(10, ("SID %d: %s\n", (int)i
,
97 sid_string_dbg(&state
->sids
[i
])));
99 if (winbindd_sids_to_xids_in_cache(&state
->sids
[i
],
100 &state
->cached
[i
])) {
103 sid_copy(&state
->non_cached
[state
->num_non_cached
],
105 state
->num_non_cached
+= 1;
108 if (state
->num_non_cached
== 0) {
109 tevent_req_done(req
);
110 return tevent_req_post(req
, ev
);
113 subreq
= wb_lookupsids_send(state
, ev
, state
->non_cached
,
114 state
->num_non_cached
);
115 if (tevent_req_nomem(subreq
, req
)) {
116 return tevent_req_post(req
, ev
);
118 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_lookupsids_done
,
123 static bool winbindd_sids_to_xids_in_cache(struct dom_sid
*sid
,
129 if (!winbindd_use_idmap_cache()) {
132 if (idmap_cache_find_sid2unixid(sid
, &id
, &expired
)) {
133 if (expired
&& is_domain_online(find_our_domain())) {
138 map
->status
= ID_MAPPED
;
145 static void winbindd_sids_to_xids_lookupsids_done(struct tevent_req
*subreq
)
147 struct tevent_req
*req
= tevent_req_callback_data(
148 subreq
, struct tevent_req
);
149 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
150 req
, struct winbindd_sids_to_xids_state
);
151 struct winbindd_child
*child
;
155 status
= wb_lookupsids_recv(subreq
, state
, &state
->domains
,
158 if (tevent_req_nterror(req
, status
)) {
162 state
->ids
.num_ids
= state
->num_non_cached
;
163 state
->ids
.ids
= talloc_array(state
, struct wbint_TransID
,
164 state
->num_non_cached
);
165 if (tevent_req_nomem(state
->ids
.ids
, req
)) {
169 for (i
=0; i
<state
->num_non_cached
; i
++) {
170 struct lsa_TranslatedName
*n
= &state
->names
->names
[i
];
171 struct wbint_TransID
*t
= &state
->ids
.ids
[i
];
173 switch (n
->sid_type
) {
175 case SID_NAME_COMPUTER
:
176 t
->type
= ID_TYPE_UID
;
178 case SID_NAME_DOM_GRP
:
180 case SID_NAME_WKN_GRP
:
181 t
->type
= ID_TYPE_GID
;
184 t
->type
= ID_TYPE_NOT_SPECIFIED
;
187 t
->domain_index
= n
->sid_index
;
188 sid_peek_rid(&state
->non_cached
[i
], &t
->rid
);
189 t
->unix_id
= (uint64_t)-1;
192 child
= idmap_child();
194 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
195 state
, state
->ev
, child
->binding_handle
, state
->domains
,
197 if (tevent_req_nomem(subreq
, req
)) {
200 tevent_req_set_callback(subreq
, winbindd_sids_to_xids_done
, req
);
203 static void winbindd_sids_to_xids_done(struct tevent_req
*subreq
)
205 struct tevent_req
*req
= tevent_req_callback_data(
206 subreq
, struct tevent_req
);
207 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
208 req
, struct winbindd_sids_to_xids_state
);
209 NTSTATUS status
, result
;
211 status
= dcerpc_wbint_Sids2UnixIDs_recv(subreq
, state
, &result
);
213 if (any_nt_status_not_ok(status
, result
, &status
)) {
214 tevent_req_nterror(req
, status
);
217 tevent_req_done(req
);
220 NTSTATUS
winbindd_sids_to_xids_recv(struct tevent_req
*req
,
221 struct winbindd_response
*response
)
223 struct winbindd_sids_to_xids_state
*state
= tevent_req_data(
224 req
, struct winbindd_sids_to_xids_state
);
227 uint32_t i
, num_non_cached
;
229 if (tevent_req_is_nterror(req
, &status
)) {
230 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
234 result
= talloc_strdup(response
, "");
235 if (result
== NULL
) {
236 return NT_STATUS_NO_MEMORY
;
241 for (i
=0; i
<state
->num_sids
; i
++) {
243 uint32_t unix_id
= UINT32_MAX
;
246 if (state
->cached
[i
].sid
!= NULL
) {
247 unix_id
= state
->cached
[i
].xid
.id
;
249 switch (state
->cached
[i
].xid
.type
) {
266 unix_id
= state
->ids
.ids
[num_non_cached
].unix_id
;
269 id
.type
= state
->ids
.ids
[num_non_cached
].type
;
270 idmap_cache_set_sid2unixid(
271 &state
->non_cached
[num_non_cached
],
291 if (unix_id
== UINT32_MAX
) {
296 result
= talloc_asprintf_append_buffer(
297 result
, "%c%lu\n", type
,
298 (unsigned long)unix_id
);
300 result
= talloc_asprintf_append_buffer(result
, "\n");
302 if (result
== NULL
) {
303 return NT_STATUS_NO_MEMORY
;
307 response
->extra_data
.data
= result
;
308 response
->length
+= talloc_get_size(result
);