2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2005
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/>.
20 a composite API for finding a DC and its name
25 #include "libcli/composite/composite.h"
26 #include "winbind/wb_async_helpers.h"
28 #include "libcli/security/security.h"
29 #include "librpc/gen_ndr/ndr_lsa_c.h"
30 #include "librpc/gen_ndr/ndr_samr_c.h"
32 #include "winbind/wb_helper.h"
35 struct lsa_lookupsids_state
{
36 struct composite_context
*ctx
;
38 struct lsa_LookupSids r
;
39 struct lsa_SidArray sids
;
40 struct lsa_TransNameArray names
;
41 struct lsa_RefDomainList
*domains
;
43 struct wb_sid_object
**result
;
46 static void lsa_lookupsids_recv_names(struct tevent_req
*subreq
);
48 struct composite_context
*wb_lsa_lookupsids_send(TALLOC_CTX
*mem_ctx
,
49 struct dcerpc_pipe
*lsa_pipe
,
50 struct policy_handle
*handle
,
52 const struct dom_sid
**sids
)
54 struct composite_context
*result
;
55 struct lsa_lookupsids_state
*state
;
57 struct tevent_req
*subreq
;
59 result
= composite_create(mem_ctx
, lsa_pipe
->conn
->event_ctx
);
60 if (result
== NULL
) goto failed
;
62 state
= talloc(result
, struct lsa_lookupsids_state
);
63 if (state
== NULL
) goto failed
;
64 result
->private_data
= state
;
67 state
->sids
.num_sids
= num_sids
;
68 state
->sids
.sids
= talloc_array(state
, struct lsa_SidPtr
, num_sids
);
69 if (state
->sids
.sids
== NULL
) goto failed
;
71 for (i
=0; i
<num_sids
; i
++) {
72 state
->sids
.sids
[i
].sid
= dom_sid_dup(state
->sids
.sids
,
74 if (state
->sids
.sids
[i
].sid
== NULL
) goto failed
;
77 state
->domains
= talloc(state
, struct lsa_RefDomainList
);
78 if (state
->domains
== NULL
) goto failed
;
81 state
->num_sids
= num_sids
;
82 state
->names
.count
= 0;
83 state
->names
.names
= NULL
;
85 state
->r
.in
.handle
= handle
;
86 state
->r
.in
.sids
= &state
->sids
;
87 state
->r
.in
.names
= &state
->names
;
88 state
->r
.in
.level
= 1;
89 state
->r
.in
.count
= &state
->count
;
90 state
->r
.out
.names
= &state
->names
;
91 state
->r
.out
.count
= &state
->count
;
92 state
->r
.out
.domains
= &state
->domains
;
94 subreq
= dcerpc_lsa_LookupSids_r_send(state
,
96 lsa_pipe
->binding_handle
,
98 if (subreq
== NULL
) goto failed
;
99 tevent_req_set_callback(subreq
, lsa_lookupsids_recv_names
, state
);
108 static void lsa_lookupsids_recv_names(struct tevent_req
*subreq
)
110 struct lsa_lookupsids_state
*state
=
111 tevent_req_callback_data(subreq
,
112 struct lsa_lookupsids_state
);
115 state
->ctx
->status
= dcerpc_lsa_LookupSids_r_recv(subreq
, state
);
117 if (!composite_is_ok(state
->ctx
)) return;
118 state
->ctx
->status
= state
->r
.out
.result
;
119 if (!NT_STATUS_IS_OK(state
->ctx
->status
) &&
120 !NT_STATUS_EQUAL(state
->ctx
->status
, STATUS_SOME_UNMAPPED
)) {
121 composite_error(state
->ctx
, state
->ctx
->status
);
125 if (state
->names
.count
!= state
->num_sids
) {
126 composite_error(state
->ctx
,
127 NT_STATUS_INVALID_NETWORK_RESPONSE
);
131 state
->result
= talloc_array(state
, struct wb_sid_object
*,
133 if (composite_nomem(state
->result
, state
->ctx
)) return;
135 for (i
=0; i
<state
->num_sids
; i
++) {
136 struct lsa_TranslatedName
*name
=
137 &state
->r
.out
.names
->names
[i
];
138 struct lsa_DomainInfo
*dom
;
139 struct lsa_RefDomainList
*domains
=
142 state
->result
[i
] = talloc_zero(state
->result
,
143 struct wb_sid_object
);
144 if (composite_nomem(state
->result
[i
], state
->ctx
)) return;
146 state
->result
[i
]->type
= name
->sid_type
;
147 if (state
->result
[i
]->type
== SID_NAME_UNKNOWN
) {
151 if (domains
== NULL
) {
152 composite_error(state
->ctx
,
153 NT_STATUS_INVALID_NETWORK_RESPONSE
);
156 if (name
->sid_index
>= domains
->count
) {
157 composite_error(state
->ctx
,
158 NT_STATUS_INVALID_NETWORK_RESPONSE
);
162 dom
= &domains
->domains
[name
->sid_index
];
163 state
->result
[i
]->domain
= talloc_reference(state
->result
[i
],
165 if ((name
->sid_type
== SID_NAME_DOMAIN
) ||
166 (name
->name
.string
== NULL
)) {
167 state
->result
[i
]->name
=
168 talloc_strdup(state
->result
[i
], "");
170 state
->result
[i
]->name
=
171 talloc_steal(state
->result
[i
],
175 if (composite_nomem(state
->result
[i
]->name
, state
->ctx
)) {
180 composite_done(state
->ctx
);
183 NTSTATUS
wb_lsa_lookupsids_recv(struct composite_context
*c
,
185 struct wb_sid_object
***names
)
187 NTSTATUS status
= composite_wait(c
);
188 if (NT_STATUS_IS_OK(status
)) {
189 struct lsa_lookupsids_state
*state
=
190 talloc_get_type(c
->private_data
,
191 struct lsa_lookupsids_state
);
192 *names
= talloc_steal(mem_ctx
, state
->result
);
199 struct lsa_lookupnames_state
{
200 struct composite_context
*ctx
;
202 struct lsa_LookupNames r
;
203 struct lsa_TransSidArray sids
;
204 struct lsa_RefDomainList
*domains
;
206 struct wb_sid_object
**result
;
209 static void lsa_lookupnames_recv_sids(struct tevent_req
*subreq
);
211 struct composite_context
*wb_lsa_lookupnames_send(TALLOC_CTX
*mem_ctx
,
212 struct dcerpc_pipe
*lsa_pipe
,
213 struct policy_handle
*handle
,
217 struct composite_context
*result
;
218 struct lsa_lookupnames_state
*state
;
219 struct tevent_req
*subreq
;
221 struct lsa_String
*lsa_names
;
224 result
= composite_create(mem_ctx
, lsa_pipe
->conn
->event_ctx
);
225 if (result
== NULL
) goto failed
;
227 state
= talloc(result
, struct lsa_lookupnames_state
);
228 if (state
== NULL
) goto failed
;
229 result
->private_data
= state
;
232 state
->sids
.count
= 0;
233 state
->sids
.sids
= NULL
;
234 state
->num_names
= num_names
;
237 lsa_names
= talloc_array(state
, struct lsa_String
, num_names
);
238 if (lsa_names
== NULL
) goto failed
;
240 for (i
=0; i
<num_names
; i
++) {
241 lsa_names
[i
].string
= names
[i
];
244 state
->domains
= talloc(state
, struct lsa_RefDomainList
);
245 if (state
->domains
== NULL
) goto failed
;
247 state
->r
.in
.handle
= handle
;
248 state
->r
.in
.num_names
= num_names
;
249 state
->r
.in
.names
= lsa_names
;
250 state
->r
.in
.sids
= &state
->sids
;
251 state
->r
.in
.level
= 1;
252 state
->r
.in
.count
= &state
->count
;
253 state
->r
.out
.count
= &state
->count
;
254 state
->r
.out
.sids
= &state
->sids
;
255 state
->r
.out
.domains
= &state
->domains
;
257 subreq
= dcerpc_lsa_LookupNames_r_send(state
,
259 lsa_pipe
->binding_handle
,
261 if (subreq
== NULL
) goto failed
;
262 tevent_req_set_callback(subreq
, lsa_lookupnames_recv_sids
, state
);
271 static void lsa_lookupnames_recv_sids(struct tevent_req
*subreq
)
273 struct lsa_lookupnames_state
*state
=
274 tevent_req_callback_data(subreq
,
275 struct lsa_lookupnames_state
);
278 state
->ctx
->status
= dcerpc_lsa_LookupNames_r_recv(subreq
, state
);
280 if (!composite_is_ok(state
->ctx
)) return;
281 state
->ctx
->status
= state
->r
.out
.result
;
282 if (!NT_STATUS_IS_OK(state
->ctx
->status
) &&
283 !NT_STATUS_EQUAL(state
->ctx
->status
, STATUS_SOME_UNMAPPED
)) {
284 composite_error(state
->ctx
, state
->ctx
->status
);
288 if (state
->sids
.count
!= state
->num_names
) {
289 composite_error(state
->ctx
,
290 NT_STATUS_INVALID_NETWORK_RESPONSE
);
294 state
->result
= talloc_array(state
, struct wb_sid_object
*,
296 if (composite_nomem(state
->result
, state
->ctx
)) return;
298 for (i
=0; i
<state
->num_names
; i
++) {
299 struct lsa_TranslatedSid
*sid
= &state
->r
.out
.sids
->sids
[i
];
300 struct lsa_RefDomainList
*domains
= state
->domains
;
301 struct lsa_DomainInfo
*dom
;
303 state
->result
[i
] = talloc_zero(state
->result
,
304 struct wb_sid_object
);
305 if (composite_nomem(state
->result
[i
], state
->ctx
)) return;
307 state
->result
[i
]->type
= sid
->sid_type
;
308 if (state
->result
[i
]->type
== SID_NAME_UNKNOWN
) {
312 if (domains
== NULL
) {
313 composite_error(state
->ctx
,
314 NT_STATUS_INVALID_NETWORK_RESPONSE
);
317 if (sid
->sid_index
>= domains
->count
) {
318 composite_error(state
->ctx
,
319 NT_STATUS_INVALID_NETWORK_RESPONSE
);
323 dom
= &domains
->domains
[sid
->sid_index
];
325 state
->result
[i
]->sid
= dom_sid_add_rid(state
->result
[i
],
329 composite_done(state
->ctx
);
332 NTSTATUS
wb_lsa_lookupnames_recv(struct composite_context
*c
,
334 struct wb_sid_object
***sids
)
336 NTSTATUS status
= composite_wait(c
);
337 if (NT_STATUS_IS_OK(status
)) {
338 struct lsa_lookupnames_state
*state
=
339 talloc_get_type(c
->private_data
,
340 struct lsa_lookupnames_state
);
341 *sids
= talloc_steal(mem_ctx
, state
->result
);
346 struct samr_getuserdomgroups_state
{
347 struct composite_context
*ctx
;
348 struct dcerpc_pipe
*samr_pipe
;
353 struct samr_RidWithAttributeArray
*rid_array
;
355 struct policy_handle
*user_handle
;
356 struct samr_OpenUser o
;
357 struct samr_GetGroupsForUser g
;
361 static void samr_usergroups_recv_open(struct tevent_req
*subreq
);
362 static void samr_usergroups_recv_groups(struct tevent_req
*subreq
);
363 static void samr_usergroups_recv_close(struct tevent_req
*subreq
);
365 struct composite_context
*wb_samr_userdomgroups_send(TALLOC_CTX
*mem_ctx
,
366 struct dcerpc_pipe
*samr_pipe
,
367 struct policy_handle
*domain_handle
,
370 struct composite_context
*result
;
371 struct samr_getuserdomgroups_state
*state
;
372 struct tevent_req
*subreq
;
374 result
= composite_create(mem_ctx
, samr_pipe
->conn
->event_ctx
);
375 if (result
== NULL
) goto failed
;
377 state
= talloc(result
, struct samr_getuserdomgroups_state
);
378 if (state
== NULL
) goto failed
;
379 result
->private_data
= state
;
382 state
->samr_pipe
= samr_pipe
;
384 state
->user_handle
= talloc(state
, struct policy_handle
);
385 if (state
->user_handle
== NULL
) goto failed
;
387 state
->o
.in
.domain_handle
= domain_handle
;
388 state
->o
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
389 state
->o
.in
.rid
= rid
;
390 state
->o
.out
.user_handle
= state
->user_handle
;
392 subreq
= dcerpc_samr_OpenUser_r_send(state
,
394 state
->samr_pipe
->binding_handle
,
396 if (subreq
== NULL
) goto failed
;
397 tevent_req_set_callback(subreq
, samr_usergroups_recv_open
, state
);
406 static void samr_usergroups_recv_open(struct tevent_req
*subreq
)
408 struct samr_getuserdomgroups_state
*state
=
409 tevent_req_callback_data(subreq
,
410 struct samr_getuserdomgroups_state
);
412 state
->ctx
->status
= dcerpc_samr_OpenUser_r_recv(subreq
, state
);
414 if (!composite_is_ok(state
->ctx
)) return;
415 state
->ctx
->status
= state
->o
.out
.result
;
416 if (!composite_is_ok(state
->ctx
)) return;
418 state
->g
.in
.user_handle
= state
->user_handle
;
419 state
->g
.out
.rids
= &state
->rid_array
;
421 subreq
= dcerpc_samr_GetGroupsForUser_r_send(state
,
422 state
->ctx
->event_ctx
,
423 state
->samr_pipe
->binding_handle
,
425 if (composite_nomem(subreq
, state
->ctx
)) return;
426 tevent_req_set_callback(subreq
, samr_usergroups_recv_groups
, state
);
429 static void samr_usergroups_recv_groups(struct tevent_req
*subreq
)
431 struct samr_getuserdomgroups_state
*state
=
432 tevent_req_callback_data(subreq
,
433 struct samr_getuserdomgroups_state
);
435 state
->ctx
->status
= dcerpc_samr_GetGroupsForUser_r_recv(subreq
, state
);
437 if (!composite_is_ok(state
->ctx
)) return;
438 state
->ctx
->status
= state
->g
.out
.result
;
439 if (!composite_is_ok(state
->ctx
)) return;
441 state
->c
.in
.handle
= state
->user_handle
;
442 state
->c
.out
.handle
= state
->user_handle
;
444 subreq
= dcerpc_samr_Close_r_send(state
,
445 state
->ctx
->event_ctx
,
446 state
->samr_pipe
->binding_handle
,
448 if (composite_nomem(subreq
, state
->ctx
)) return;
449 tevent_req_set_callback(subreq
, samr_usergroups_recv_close
, state
);
452 static void samr_usergroups_recv_close(struct tevent_req
*subreq
)
454 struct samr_getuserdomgroups_state
*state
=
455 tevent_req_callback_data(subreq
,
456 struct samr_getuserdomgroups_state
);
458 state
->ctx
->status
= dcerpc_samr_Close_r_recv(subreq
, state
);
460 if (!composite_is_ok(state
->ctx
)) return;
461 state
->ctx
->status
= state
->c
.out
.result
;
462 if (!composite_is_ok(state
->ctx
)) return;
464 composite_done(state
->ctx
);
467 NTSTATUS
wb_samr_userdomgroups_recv(struct composite_context
*ctx
,
469 uint32_t *num_rids
, uint32_t **rids
)
471 struct samr_getuserdomgroups_state
*state
=
472 talloc_get_type(ctx
->private_data
,
473 struct samr_getuserdomgroups_state
);
476 NTSTATUS status
= composite_wait(ctx
);
477 if (!NT_STATUS_IS_OK(status
)) goto done
;
479 *num_rids
= state
->rid_array
->count
;
480 *rids
= talloc_array(mem_ctx
, uint32_t, *num_rids
);
482 status
= NT_STATUS_NO_MEMORY
;
486 for (i
=0; i
<*num_rids
; i
++) {
487 (*rids
)[i
] = state
->rid_array
->rids
[i
].rid
;