2 Unix SMB/CIFS implementation.
4 Copyright (C) Rafal Szczesniak 2007
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 "libnet/libnet.h"
23 #include "libcli/composite/composite.h"
24 #include "librpc/gen_ndr/lsa.h"
25 #include "librpc/gen_ndr/ndr_lsa_c.h"
26 #include "librpc/gen_ndr/samr.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
28 #include "libcli/security/security.h"
31 struct create_group_state
{
32 struct libnet_context
*ctx
;
33 struct libnet_CreateGroup r
;
34 struct libnet_DomainOpen domain_open
;
35 struct libnet_rpc_groupadd group_add
;
37 /* information about the progress */
38 void (*monitor_fn
)(struct monitor_msg
*);
42 static void continue_domain_opened(struct composite_context
*ctx
);
43 static void continue_rpc_group_added(struct composite_context
*ctx
);
46 struct composite_context
* libnet_CreateGroup_send(struct libnet_context
*ctx
,
48 struct libnet_CreateGroup
*r
,
49 void (*monitor
)(struct monitor_msg
*))
51 struct composite_context
*c
;
52 struct create_group_state
*s
;
53 struct composite_context
*create_req
;
54 bool prereq_met
= false;
56 /* composite context allocation and setup */
57 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
58 if (c
== NULL
) return NULL
;
60 s
= talloc_zero(c
, struct create_group_state
);
61 if (composite_nomem(s
, c
)) return c
;
67 ZERO_STRUCT(s
->r
.out
);
69 /* prerequisite: make sure we have a valid samr domain handle */
70 prereq_met
= samr_domain_opened(ctx
, s
->r
.in
.domain_name
, &c
, &s
->domain_open
,
71 continue_domain_opened
, monitor
);
72 if (!prereq_met
) return c
;
74 /* prepare arguments of rpc group add call */
75 s
->group_add
.in
.groupname
= r
->in
.group_name
;
76 s
->group_add
.in
.domain_handle
= ctx
->samr
.handle
;
78 /* send the request */
79 create_req
= libnet_rpc_groupadd_send(ctx
->samr
.pipe
, &s
->group_add
, monitor
);
80 if (composite_nomem(create_req
, c
)) return c
;
82 composite_continue(c
, create_req
, continue_rpc_group_added
, c
);
87 static void continue_domain_opened(struct composite_context
*ctx
)
89 struct composite_context
*c
;
90 struct create_group_state
*s
;
91 struct composite_context
*create_req
;
93 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
94 s
= talloc_get_type_abort(c
->private_data
, struct create_group_state
);
96 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
97 if (!composite_is_ok(c
)) return;
99 /* prepare arguments of groupadd call */
100 s
->group_add
.in
.groupname
= s
->r
.in
.group_name
;
101 s
->group_add
.in
.domain_handle
= s
->ctx
->samr
.handle
;
103 /* send the request */
104 create_req
= libnet_rpc_groupadd_send(s
->ctx
->samr
.pipe
, &s
->group_add
,
106 if (composite_nomem(create_req
, c
)) return;
108 composite_continue(c
, create_req
, continue_rpc_group_added
, c
);
112 static void continue_rpc_group_added(struct composite_context
*ctx
)
114 struct composite_context
*c
;
115 struct create_group_state
*s
;
117 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
118 s
= talloc_get_type_abort(c
->private_data
, struct create_group_state
);
120 /* receive result of group add call */
121 c
->status
= libnet_rpc_groupadd_recv(ctx
, c
, &s
->group_add
);
122 if (!composite_is_ok(c
)) return;
130 * Receive result of CreateGroup call
132 * @param c composite context returned by send request routine
133 * @param mem_ctx memory context of this call
134 * @param r pointer to a structure containing arguments and result of this call
137 NTSTATUS
libnet_CreateGroup_recv(struct composite_context
*c
,
139 struct libnet_CreateGroup
*r
)
143 status
= composite_wait(c
);
144 if (!NT_STATUS_IS_OK(status
)) {
145 r
->out
.error_string
= talloc_strdup(mem_ctx
, nt_errstr(status
));
154 * Create domain group
156 * @param ctx initialised libnet context
157 * @param mem_ctx memory context of this call
158 * @param io pointer to structure containing arguments and result of this call
161 NTSTATUS
libnet_CreateGroup(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
162 struct libnet_CreateGroup
*io
)
164 struct composite_context
*c
;
166 c
= libnet_CreateGroup_send(ctx
, mem_ctx
, io
, NULL
);
167 return libnet_CreateGroup_recv(c
, mem_ctx
, io
);
171 struct group_info_state
{
172 struct libnet_context
*ctx
;
173 const char *domain_name
;
174 enum libnet_GroupInfo_level level
;
175 const char *group_name
;
176 const char *sid_string
;
177 struct libnet_LookupName lookup
;
178 struct libnet_DomainOpen domopen
;
179 struct libnet_rpc_groupinfo info
;
181 /* information about the progress */
182 void (*monitor_fn
)(struct monitor_msg
*);
186 static void continue_domain_open_info(struct composite_context
*ctx
);
187 static void continue_name_found(struct composite_context
*ctx
);
188 static void continue_group_info(struct composite_context
*ctx
);
191 * Sends request to get group information
193 * @param ctx initialised libnet context
194 * @param mem_ctx memory context of this call
195 * @param io pointer to structure containing arguments the call
196 * @param monitor function pointer for receiving monitor messages
197 * @return composite context of this request
199 struct composite_context
* libnet_GroupInfo_send(struct libnet_context
*ctx
,
201 struct libnet_GroupInfo
*io
,
202 void (*monitor
)(struct monitor_msg
*))
204 struct composite_context
*c
;
205 struct group_info_state
*s
;
206 bool prereq_met
= false;
207 struct composite_context
*lookup_req
, *info_req
;
209 /* composite context allocation and setup */
210 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
211 if (c
== NULL
) return NULL
;
213 s
= talloc_zero(c
, struct group_info_state
);
214 if (composite_nomem(s
, c
)) return c
;
218 /* store arguments in the state structure */
219 s
->monitor_fn
= monitor
;
221 s
->domain_name
= talloc_strdup(c
, io
->in
.domain_name
);
222 s
->level
= io
->in
.level
;
224 case GROUP_INFO_BY_NAME
:
225 s
->group_name
= talloc_strdup(c
, io
->in
.data
.group_name
);
226 s
->sid_string
= NULL
;
228 case GROUP_INFO_BY_SID
:
229 s
->group_name
= NULL
;
230 s
->sid_string
= dom_sid_string(c
, io
->in
.data
.group_sid
);
234 /* prerequisite: make sure the domain is opened */
235 prereq_met
= samr_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domopen
,
236 continue_domain_open_info
, monitor
);
237 if (!prereq_met
) return c
;
240 case GROUP_INFO_BY_NAME
:
241 /* prepare arguments for LookupName call */
242 s
->lookup
.in
.name
= s
->group_name
;
243 s
->lookup
.in
.domain_name
= s
->domain_name
;
245 /* send the request */
246 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
247 if (composite_nomem(lookup_req
, c
)) return c
;
249 /* set the next stage */
250 composite_continue(c
, lookup_req
, continue_name_found
, c
);
252 case GROUP_INFO_BY_SID
:
253 /* prepare arguments for groupinfo call */
254 s
->info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
255 s
->info
.in
.sid
= s
->sid_string
;
256 /* we're looking for all information available */
257 s
->info
.in
.level
= GROUPINFOALL
;
259 /* send the request */
260 info_req
= libnet_rpc_groupinfo_send(s
->ctx
->samr
.pipe
, &s
->info
, s
->monitor_fn
);
261 if (composite_nomem(info_req
, c
)) return c
;
263 /* set the next stage */
264 composite_continue(c
, info_req
, continue_group_info
, c
);
273 * Stage 0.5 (optional): receive opened domain and send lookup name request
275 static void continue_domain_open_info(struct composite_context
*ctx
)
277 struct composite_context
*c
;
278 struct group_info_state
*s
;
279 struct composite_context
*lookup_req
, *info_req
;
281 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
282 s
= talloc_get_type_abort(c
->private_data
, struct group_info_state
);
284 /* receive domain handle */
285 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domopen
);
286 if (!composite_is_ok(c
)) return;
289 case GROUP_INFO_BY_NAME
:
290 /* prepare arguments for LookupName call */
291 s
->lookup
.in
.name
= s
->group_name
;
292 s
->lookup
.in
.domain_name
= s
->domain_name
;
294 /* send the request */
295 lookup_req
= libnet_LookupName_send(s
->ctx
, c
, &s
->lookup
, s
->monitor_fn
);
296 if (composite_nomem(lookup_req
, c
)) return;
298 /* set the next stage */
299 composite_continue(c
, lookup_req
, continue_name_found
, c
);
301 case GROUP_INFO_BY_SID
:
302 /* prepare arguments for groupinfo call */
303 s
->info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
304 s
->info
.in
.sid
= s
->sid_string
;
305 /* we're looking for all information available */
306 s
->info
.in
.level
= GROUPINFOALL
;
308 /* send the request */
309 info_req
= libnet_rpc_groupinfo_send(s
->ctx
->samr
.pipe
, &s
->info
, s
->monitor_fn
);
310 if (composite_nomem(info_req
, c
)) return;
312 /* set the next stage */
313 composite_continue(c
, info_req
, continue_group_info
, c
);
321 * Stage 1: Receive SID found and send request for group info
323 static void continue_name_found(struct composite_context
*ctx
)
325 struct composite_context
*c
;
326 struct group_info_state
*s
;
327 struct composite_context
*info_req
;
329 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
330 s
= talloc_get_type_abort(c
->private_data
, struct group_info_state
);
332 /* receive SID assiociated with name found */
333 c
->status
= libnet_LookupName_recv(ctx
, c
, &s
->lookup
);
334 if (!composite_is_ok(c
)) return;
336 /* Is is a group SID actually ? */
337 if (s
->lookup
.out
.sid_type
!= SID_NAME_DOM_GRP
&&
338 s
->lookup
.out
.sid_type
!= SID_NAME_ALIAS
) {
339 composite_error(c
, NT_STATUS_NO_SUCH_GROUP
);
342 /* prepare arguments for groupinfo call */
343 s
->info
.in
.domain_handle
= s
->ctx
->samr
.handle
;
344 s
->info
.in
.groupname
= s
->group_name
;
345 s
->info
.in
.sid
= s
->lookup
.out
.sidstr
;
346 /* we're looking for all information available */
347 s
->info
.in
.level
= GROUPINFOALL
;
349 /* send the request */
350 info_req
= libnet_rpc_groupinfo_send(s
->ctx
->samr
.pipe
, &s
->info
, s
->monitor_fn
);
351 if (composite_nomem(info_req
, c
)) return;
353 /* set the next stage */
354 composite_continue(c
, info_req
, continue_group_info
, c
);
359 * Stage 2: Receive group information
361 static void continue_group_info(struct composite_context
*ctx
)
363 struct composite_context
*c
;
364 struct group_info_state
*s
;
366 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
367 s
= talloc_get_type_abort(c
->private_data
, struct group_info_state
);
369 /* receive group information */
370 c
->status
= libnet_rpc_groupinfo_recv(ctx
, c
, &s
->info
);
371 if (!composite_is_ok(c
)) return;
379 * Receive group information
381 * @param c composite context returned by libnet_GroupInfo_send
382 * @param mem_ctx memory context of this call
383 * @param io pointer to structure receiving results of the call
386 NTSTATUS
libnet_GroupInfo_recv(struct composite_context
* c
, TALLOC_CTX
*mem_ctx
,
387 struct libnet_GroupInfo
*io
)
390 struct group_info_state
*s
;
392 status
= composite_wait(c
);
393 if (NT_STATUS_IS_OK(status
)) {
394 /* put the results into io structure if everything went fine */
395 s
= talloc_get_type_abort(c
->private_data
, struct group_info_state
);
397 io
->out
.group_name
= talloc_steal(mem_ctx
,
398 s
->info
.out
.info
.all
.name
.string
);
399 io
->out
.group_sid
= talloc_steal(mem_ctx
, s
->lookup
.out
.sid
);
400 io
->out
.num_members
= s
->info
.out
.info
.all
.num_members
;
401 io
->out
.description
= talloc_steal(mem_ctx
, s
->info
.out
.info
.all
.description
.string
);
403 io
->out
.error_string
= talloc_strdup(mem_ctx
, "Success");
406 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
415 * Obtains specified group information
417 * @param ctx initialised libnet context
418 * @param mem_ctx memory context of the call
419 * @param io pointer to a structure containing arguments and results of the call
421 NTSTATUS
libnet_GroupInfo(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
422 struct libnet_GroupInfo
*io
)
424 struct composite_context
*c
= libnet_GroupInfo_send(ctx
, mem_ctx
,
426 return libnet_GroupInfo_recv(c
, mem_ctx
, io
);
430 struct grouplist_state
{
431 struct libnet_context
*ctx
;
432 const char *domain_name
;
433 struct lsa_DomainInfo dominfo
;
435 uint32_t resume_index
;
436 struct grouplist
*groups
;
439 struct libnet_DomainOpen domain_open
;
440 struct lsa_QueryInfoPolicy query_domain
;
441 struct samr_EnumDomainGroups group_list
;
443 void (*monitor_fn
)(struct monitor_msg
*);
447 static void continue_lsa_domain_opened(struct composite_context
*ctx
);
448 static void continue_domain_queried(struct tevent_req
*subreq
);
449 static void continue_samr_domain_opened(struct composite_context
*ctx
);
450 static void continue_groups_enumerated(struct tevent_req
*subreq
);
454 * Sends request to list (enumerate) group accounts
456 * @param ctx initialised libnet context
457 * @param mem_ctx memory context of this call
458 * @param io pointer to structure containing arguments and results of this call
459 * @param monitor function pointer for receiving monitor messages
460 * @return compostite context of this request
462 struct composite_context
*libnet_GroupList_send(struct libnet_context
*ctx
,
464 struct libnet_GroupList
*io
,
465 void (*monitor
)(struct monitor_msg
*))
467 struct composite_context
*c
;
468 struct grouplist_state
*s
;
469 struct tevent_req
*subreq
;
470 bool prereq_met
= false;
472 /* composite context allocation and setup */
473 c
= composite_create(mem_ctx
, ctx
->event_ctx
);
474 if (c
== NULL
) return NULL
;
476 s
= talloc_zero(c
, struct grouplist_state
);
477 if (composite_nomem(s
, c
)) return c
;
481 /* store the arguments in the state structure */
483 s
->page_size
= io
->in
.page_size
;
484 s
->resume_index
= io
->in
.resume_index
;
485 s
->domain_name
= talloc_strdup(c
, io
->in
.domain_name
);
486 s
->monitor_fn
= monitor
;
488 /* make sure we have lsa domain handle before doing anything */
489 prereq_met
= lsa_domain_opened(ctx
, s
->domain_name
, &c
, &s
->domain_open
,
490 continue_lsa_domain_opened
, monitor
);
491 if (!prereq_met
) return c
;
493 /* prepare arguments of QueryDomainInfo call */
494 s
->query_domain
.in
.handle
= &ctx
->lsa
.handle
;
495 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
496 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
497 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return c
;
499 /* send the request */
500 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
501 ctx
->lsa
.pipe
->binding_handle
,
503 if (composite_nomem(subreq
, c
)) return c
;
505 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
511 * Stage 0.5 (optional): receive lsa domain handle and send
512 * request to query domain info
514 static void continue_lsa_domain_opened(struct composite_context
*ctx
)
516 struct composite_context
*c
;
517 struct grouplist_state
*s
;
518 struct tevent_req
*subreq
;
520 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
521 s
= talloc_get_type_abort(c
->private_data
, struct grouplist_state
);
523 /* receive lsa domain handle */
524 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
525 if (!composite_is_ok(c
)) return;
527 /* prepare arguments of QueryDomainInfo call */
528 s
->query_domain
.in
.handle
= &s
->ctx
->lsa
.handle
;
529 s
->query_domain
.in
.level
= LSA_POLICY_INFO_DOMAIN
;
530 s
->query_domain
.out
.info
= talloc_zero(c
, union lsa_PolicyInformation
*);
531 if (composite_nomem(s
->query_domain
.out
.info
, c
)) return;
533 /* send the request */
534 subreq
= dcerpc_lsa_QueryInfoPolicy_r_send(s
, c
->event_ctx
,
535 s
->ctx
->lsa
.pipe
->binding_handle
,
537 if (composite_nomem(subreq
, c
)) return;
539 tevent_req_set_callback(subreq
, continue_domain_queried
, c
);
544 * Stage 1: receive domain info and request to enum groups
545 * provided a valid samr handle is opened
547 static void continue_domain_queried(struct tevent_req
*subreq
)
549 struct composite_context
*c
;
550 struct grouplist_state
*s
;
551 bool prereq_met
= false;
553 c
= tevent_req_callback_data(subreq
, struct composite_context
);
554 s
= talloc_get_type_abort(c
->private_data
, struct grouplist_state
);
556 /* receive result of rpc request */
557 c
->status
= dcerpc_lsa_QueryInfoPolicy_r_recv(subreq
, s
);
559 if (!composite_is_ok(c
)) return;
561 /* get the returned domain info */
562 s
->dominfo
= (*s
->query_domain
.out
.info
)->domain
;
564 /* make sure we have samr domain handle before continuing */
565 prereq_met
= samr_domain_opened(s
->ctx
, s
->domain_name
, &c
, &s
->domain_open
,
566 continue_samr_domain_opened
, s
->monitor_fn
);
567 if (!prereq_met
) return;
569 /* prepare arguments od EnumDomainGroups call */
570 s
->group_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
571 s
->group_list
.in
.max_size
= s
->page_size
;
572 s
->group_list
.in
.resume_handle
= &s
->resume_index
;
573 s
->group_list
.out
.resume_handle
= &s
->resume_index
;
574 s
->group_list
.out
.num_entries
= talloc(s
, uint32_t);
575 if (composite_nomem(s
->group_list
.out
.num_entries
, c
)) return;
576 s
->group_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
577 if (composite_nomem(s
->group_list
.out
.sam
, c
)) return;
579 /* send the request */
580 subreq
= dcerpc_samr_EnumDomainGroups_r_send(s
, c
->event_ctx
,
581 s
->ctx
->samr
.pipe
->binding_handle
,
583 if (composite_nomem(subreq
, c
)) return;
585 tevent_req_set_callback(subreq
, continue_groups_enumerated
, c
);
590 * Stage 1.5 (optional): receive samr domain handle
591 * and request to enumerate accounts
593 static void continue_samr_domain_opened(struct composite_context
*ctx
)
595 struct composite_context
*c
;
596 struct grouplist_state
*s
;
597 struct tevent_req
*subreq
;
599 c
= talloc_get_type_abort(ctx
->async
.private_data
, struct composite_context
);
600 s
= talloc_get_type_abort(c
->private_data
, struct grouplist_state
);
602 /* receive samr domain handle */
603 c
->status
= libnet_DomainOpen_recv(ctx
, s
->ctx
, c
, &s
->domain_open
);
604 if (!composite_is_ok(c
)) return;
606 /* prepare arguments of EnumDomainGroups call */
607 s
->group_list
.in
.domain_handle
= &s
->ctx
->samr
.handle
;
608 s
->group_list
.in
.max_size
= s
->page_size
;
609 s
->group_list
.in
.resume_handle
= &s
->resume_index
;
610 s
->group_list
.out
.resume_handle
= &s
->resume_index
;
611 s
->group_list
.out
.num_entries
= talloc(s
, uint32_t);
612 if (composite_nomem(s
->group_list
.out
.num_entries
, c
)) return;
613 s
->group_list
.out
.sam
= talloc(s
, struct samr_SamArray
*);
614 if (composite_nomem(s
->group_list
.out
.sam
, c
)) return;
616 /* send the request */
617 subreq
= dcerpc_samr_EnumDomainGroups_r_send(s
, c
->event_ctx
,
618 s
->ctx
->samr
.pipe
->binding_handle
,
620 if (composite_nomem(subreq
, c
)) return;
622 tevent_req_set_callback(subreq
, continue_groups_enumerated
, c
);
627 * Stage 2: receive enumerated groups and their rids
629 static void continue_groups_enumerated(struct tevent_req
*subreq
)
631 struct composite_context
*c
;
632 struct grouplist_state
*s
;
635 c
= tevent_req_callback_data(subreq
, struct composite_context
);
636 s
= talloc_get_type_abort(c
->private_data
, struct grouplist_state
);
638 /* receive result of rpc request */
639 c
->status
= dcerpc_samr_EnumDomainGroups_r_recv(subreq
, s
);
641 if (!composite_is_ok(c
)) return;
643 /* get the actual status of the rpc call result
644 (instead of rpc layer) */
645 c
->status
= s
->group_list
.out
.result
;
647 /* we're interested in status "ok" as well as two
648 enum-specific status codes */
649 if (NT_STATUS_IS_OK(c
->status
) ||
650 NT_STATUS_EQUAL(c
->status
, STATUS_MORE_ENTRIES
) ||
651 NT_STATUS_EQUAL(c
->status
, NT_STATUS_NO_MORE_ENTRIES
)) {
653 /* get enumerated accounts counter and resume handle (the latter allows
654 making subsequent call to continue enumeration) */
655 s
->resume_index
= *s
->group_list
.out
.resume_handle
;
656 s
->count
= *s
->group_list
.out
.num_entries
;
658 /* prepare returned group accounts array */
659 s
->groups
= talloc_array(c
, struct grouplist
, (*s
->group_list
.out
.sam
)->count
);
660 if (composite_nomem(s
->groups
, c
)) return;
662 for (i
= 0; i
< (*s
->group_list
.out
.sam
)->count
; i
++) {
663 struct dom_sid
*group_sid
;
664 struct samr_SamEntry
*entry
= &(*s
->group_list
.out
.sam
)->entries
[i
];
665 struct dom_sid
*domain_sid
= (*s
->query_domain
.out
.info
)->domain
.sid
;
667 /* construct group sid from returned rid and queried domain sid */
668 group_sid
= dom_sid_add_rid(c
, domain_sid
, entry
->idx
);
669 if (composite_nomem(group_sid
, c
)) return;
672 s
->groups
[i
].groupname
= talloc_strdup(s
->groups
, entry
->name
.string
);
673 if (composite_nomem(s
->groups
[i
].groupname
, c
)) return;
676 s
->groups
[i
].sid
= dom_sid_string(s
->groups
, group_sid
);
677 if (composite_nomem(s
->groups
[i
].sid
, c
)) return;
684 /* something went wrong */
685 composite_error(c
, c
->status
);
691 * Receive result of GroupList call
693 * @param c composite context returned by send request routine
694 * @param mem_ctx memory context of this call
695 * @param io pointer to structure containing arguments and result of this call
698 NTSTATUS
libnet_GroupList_recv(struct composite_context
*c
, TALLOC_CTX
*mem_ctx
,
699 struct libnet_GroupList
*io
)
702 struct grouplist_state
*s
;
704 if (c
== NULL
|| mem_ctx
== NULL
|| io
== NULL
) {
706 return NT_STATUS_INVALID_PARAMETER
;
709 status
= composite_wait(c
);
710 if (NT_STATUS_IS_OK(status
) ||
711 NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
) ||
712 NT_STATUS_EQUAL(status
, NT_STATUS_NO_MORE_ENTRIES
)) {
714 s
= talloc_get_type_abort(c
->private_data
, struct grouplist_state
);
716 /* get results from composite context */
717 io
->out
.count
= s
->count
;
718 io
->out
.resume_index
= s
->resume_index
;
719 io
->out
.groups
= talloc_steal(mem_ctx
, s
->groups
);
721 if (NT_STATUS_IS_OK(status
)) {
722 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success");
724 /* success, but we're not done yet */
725 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Success (status: %s)",
730 io
->out
.error_string
= talloc_asprintf(mem_ctx
, "Error: %s", nt_errstr(status
));
739 * Enumerate domain groups
741 * @param ctx initialised libnet context
742 * @param mem_ctx memory context of this call
743 * @param io pointer to structure containing arguments and result of this call
746 NTSTATUS
libnet_GroupList(struct libnet_context
*ctx
, TALLOC_CTX
*mem_ctx
,
747 struct libnet_GroupList
*io
)
749 struct composite_context
*c
;
751 c
= libnet_GroupList_send(ctx
, mem_ctx
, io
, NULL
);
752 return libnet_GroupList_recv(c
, mem_ctx
, io
);