Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Rafal Szczesniak 2005
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 :
21 : #include "includes.h"
22 : #include "libnet/libnet.h"
23 : #include "libcli/composite/composite.h"
24 : #include "auth/credentials/credentials.h"
25 : #include "librpc/ndr/libndr.h"
26 : #include "librpc/gen_ndr/samr.h"
27 : #include "librpc/gen_ndr/ndr_samr_c.h"
28 : #include "librpc/gen_ndr/lsa.h"
29 : #include "librpc/gen_ndr/ndr_lsa_c.h"
30 : #include "libcli/security/security.h"
31 :
32 :
33 : struct create_user_state {
34 : struct libnet_CreateUser r;
35 : struct libnet_DomainOpen domain_open;
36 : struct libnet_rpc_useradd user_add;
37 : struct libnet_context *ctx;
38 :
39 : /* information about the progress */
40 : void (*monitor_fn)(struct monitor_msg *);
41 : };
42 :
43 :
44 : static void continue_rpc_useradd(struct composite_context *ctx);
45 : static void continue_domain_open_create(struct composite_context *ctx);
46 :
47 :
48 : /**
49 : * Sends request to create user account
50 : *
51 : * @param ctx initialised libnet context
52 : * @param mem_ctx memory context of this call
53 : * @param r pointer to a structure containing arguments and results of this call
54 : * @param monitor function pointer for receiving monitor messages
55 : * @return compostite context of this request
56 : */
57 1 : struct composite_context* libnet_CreateUser_send(struct libnet_context *ctx,
58 : TALLOC_CTX *mem_ctx,
59 : struct libnet_CreateUser *r,
60 : void (*monitor)(struct monitor_msg*))
61 : {
62 1 : struct composite_context *c;
63 1 : struct create_user_state *s;
64 1 : struct composite_context *create_req;
65 1 : bool prereq_met = false;
66 :
67 : /* composite context allocation and setup */
68 1 : c = composite_create(mem_ctx, ctx->event_ctx);
69 1 : if (c == NULL) return NULL;
70 :
71 1 : s = talloc_zero(c, struct create_user_state);
72 1 : if (composite_nomem(s, c)) return c;
73 :
74 1 : c->private_data = s;
75 :
76 : /* store arguments in the state structure */
77 1 : s->ctx = ctx;
78 1 : s->r = *r;
79 1 : ZERO_STRUCT(s->r.out);
80 :
81 : /* prerequisite: make sure the domain is opened */
82 1 : prereq_met = samr_domain_opened(ctx, c, s->r.in.domain_name, &c, &s->domain_open,
83 : continue_domain_open_create, monitor);
84 1 : if (!prereq_met) return c;
85 :
86 : /* prepare arguments for useradd call */
87 0 : s->user_add.in.username = r->in.user_name;
88 0 : s->user_add.in.domain_handle = ctx->samr.handle;
89 :
90 : /* send the request */
91 0 : create_req = libnet_rpc_useradd_send(s, s->ctx->event_ctx,
92 : ctx->samr.samr_handle,
93 : &s->user_add, monitor);
94 0 : if (composite_nomem(create_req, c)) return c;
95 :
96 : /* set the next stage */
97 0 : composite_continue(c, create_req, continue_rpc_useradd, c);
98 0 : return c;
99 : }
100 :
101 :
102 : /*
103 : * Stage 0.5 (optional): receive result of domain open request
104 : * and send useradd request
105 : */
106 1 : static void continue_domain_open_create(struct composite_context *ctx)
107 : {
108 1 : struct composite_context *c;
109 1 : struct create_user_state *s;
110 1 : struct composite_context *create_req;
111 1 : struct monitor_msg msg;
112 :
113 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
114 1 : s = talloc_get_type_abort(c->private_data, struct create_user_state);
115 :
116 : /* receive result of DomainOpen call */
117 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
118 1 : if (!composite_is_ok(c)) return;
119 :
120 : /* send monitor message */
121 1 : if (s->monitor_fn) s->monitor_fn(&msg);
122 :
123 : /* prepare arguments for useradd call */
124 1 : s->user_add.in.username = s->r.in.user_name;
125 1 : s->user_add.in.domain_handle = s->ctx->samr.handle;
126 :
127 : /* send the request */
128 1 : create_req = libnet_rpc_useradd_send(s, s->ctx->event_ctx,
129 0 : s->ctx->samr.samr_handle,
130 : &s->user_add, s->monitor_fn);
131 1 : if (composite_nomem(create_req, c)) return;
132 :
133 : /* set the next stage */
134 1 : composite_continue(c, create_req, continue_rpc_useradd, c);
135 : }
136 :
137 :
138 : /*
139 : * Stage 1: receive result of useradd call
140 : */
141 1 : static void continue_rpc_useradd(struct composite_context *ctx)
142 : {
143 1 : struct composite_context *c;
144 1 : struct create_user_state *s;
145 1 : struct monitor_msg msg;
146 :
147 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
148 1 : s = talloc_get_type_abort(c->private_data, struct create_user_state);
149 :
150 : /* receive result of the call */
151 1 : c->status = libnet_rpc_useradd_recv(ctx, c, &s->user_add);
152 1 : if (!composite_is_ok(c)) return;
153 :
154 : /* send monitor message */
155 1 : if (s->monitor_fn) s->monitor_fn(&msg);
156 :
157 : /* we're done */
158 1 : composite_done(c);
159 : }
160 :
161 :
162 : /**
163 : * Receive result of CreateUser call
164 : *
165 : * @param c composite context returned by send request routine
166 : * @param mem_ctx memory context of this call
167 : * @param r pointer to a structure containing arguments and result of this call
168 : * @return nt status
169 : */
170 1 : NTSTATUS libnet_CreateUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
171 : struct libnet_CreateUser *r)
172 : {
173 1 : NTSTATUS status;
174 :
175 1 : r->out.error_string = NULL;
176 :
177 : /* wait for result of async request and check status code */
178 1 : status = composite_wait(c);
179 1 : if (!NT_STATUS_IS_OK(status)) {
180 0 : r->out.error_string = talloc_strdup(mem_ctx, nt_errstr(status));
181 : }
182 :
183 1 : talloc_free(c);
184 1 : return status;
185 : }
186 :
187 :
188 : /**
189 : * Synchronous version of CreateUser call
190 : *
191 : * @param ctx initialised libnet context
192 : * @param mem_ctx memory context of this call
193 : * @param r pointer to a structure containing arguments and result of this call
194 : * @return nt status
195 : */
196 1 : NTSTATUS libnet_CreateUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
197 : struct libnet_CreateUser *r)
198 : {
199 1 : struct composite_context *c;
200 :
201 1 : c = libnet_CreateUser_send(ctx, mem_ctx, r, NULL);
202 1 : return libnet_CreateUser_recv(c, mem_ctx, r);
203 : }
204 :
205 :
206 : struct delete_user_state {
207 : struct libnet_DeleteUser r;
208 : struct libnet_context *ctx;
209 : struct libnet_DomainOpen domain_open;
210 : struct libnet_rpc_userdel user_del;
211 :
212 : /* information about the progress */
213 : void (*monitor_fn)(struct monitor_msg *);
214 : };
215 :
216 :
217 : static void continue_rpc_userdel(struct composite_context *ctx);
218 : static void continue_domain_open_delete(struct composite_context *ctx);
219 :
220 :
221 : /**
222 : * Sends request to delete user account
223 : *
224 : * @param ctx initialised libnet context
225 : * @param mem_ctx memory context of this call
226 : * @param r pointer to structure containing arguments and result of this call
227 : * @param monitor function pointer for receiving monitor messages
228 : */
229 1 : struct composite_context *libnet_DeleteUser_send(struct libnet_context *ctx,
230 : TALLOC_CTX *mem_ctx,
231 : struct libnet_DeleteUser *r,
232 : void (*monitor)(struct monitor_msg*))
233 : {
234 1 : struct composite_context *c;
235 1 : struct delete_user_state *s;
236 1 : struct composite_context *delete_req;
237 1 : bool prereq_met = false;
238 :
239 : /* composite context allocation and setup */
240 1 : c = composite_create(mem_ctx, ctx->event_ctx);
241 1 : if (c == NULL) return NULL;
242 :
243 1 : s = talloc_zero(c, struct delete_user_state);
244 1 : if (composite_nomem(s, c)) return c;
245 :
246 1 : c->private_data = s;
247 :
248 : /* store arguments in state structure */
249 1 : s->ctx = ctx;
250 1 : s->r = *r;
251 1 : ZERO_STRUCT(s->r.out);
252 :
253 : /* prerequisite: make sure the domain is opened before proceeding */
254 1 : prereq_met = samr_domain_opened(ctx, c, s->r.in.domain_name, &c, &s->domain_open,
255 : continue_domain_open_delete, monitor);
256 1 : if (!prereq_met) return c;
257 :
258 : /* prepare arguments for userdel call */
259 0 : s->user_del.in.username = r->in.user_name;
260 0 : s->user_del.in.domain_handle = ctx->samr.handle;
261 :
262 : /* send request */
263 0 : delete_req = libnet_rpc_userdel_send(s, s->ctx->event_ctx,
264 : ctx->samr.samr_handle,
265 : &s->user_del, monitor);
266 0 : if (composite_nomem(delete_req, c)) return c;
267 :
268 : /* set the next stage */
269 0 : composite_continue(c, delete_req, continue_rpc_userdel, c);
270 0 : return c;
271 : }
272 :
273 :
274 : /*
275 : * Stage 0.5 (optional): receive result of domain open request
276 : * and send useradd request
277 : */
278 1 : static void continue_domain_open_delete(struct composite_context *ctx)
279 : {
280 1 : struct composite_context *c;
281 1 : struct delete_user_state *s;
282 1 : struct composite_context *delete_req;
283 1 : struct monitor_msg msg;
284 :
285 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
286 1 : s = talloc_get_type_abort(c->private_data, struct delete_user_state);
287 :
288 : /* receive result of DomainOpen call */
289 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
290 1 : if (!composite_is_ok(c)) return;
291 :
292 : /* send monitor message */
293 1 : if (s->monitor_fn) s->monitor_fn(&msg);
294 :
295 : /* prepare arguments for userdel call */
296 1 : s->user_del.in.username = s->r.in.user_name;
297 1 : s->user_del.in.domain_handle = s->ctx->samr.handle;
298 :
299 : /* send request */
300 1 : delete_req = libnet_rpc_userdel_send(s, s->ctx->event_ctx,
301 0 : s->ctx->samr.samr_handle,
302 : &s->user_del, s->monitor_fn);
303 1 : if (composite_nomem(delete_req, c)) return;
304 :
305 : /* set the next stage */
306 1 : composite_continue(c, delete_req, continue_rpc_userdel, c);
307 : }
308 :
309 :
310 : /*
311 : * Stage 1: receive result of userdel call and finish the composite function
312 : */
313 1 : static void continue_rpc_userdel(struct composite_context *ctx)
314 : {
315 1 : struct composite_context *c;
316 1 : struct delete_user_state *s;
317 1 : struct monitor_msg msg;
318 :
319 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
320 1 : s = talloc_get_type_abort(c->private_data, struct delete_user_state);
321 :
322 : /* receive result of userdel call */
323 1 : c->status = libnet_rpc_userdel_recv(ctx, c, &s->user_del);
324 1 : if (!composite_is_ok(c)) return;
325 :
326 : /* send monitor message */
327 1 : if (s->monitor_fn) s->monitor_fn(&msg);
328 :
329 : /* we're done */
330 1 : composite_done(c);
331 : }
332 :
333 :
334 : /**
335 : * Receives result of asynchronous DeleteUser call
336 : *
337 : * @param c composite context returned by async DeleteUser call
338 : * @param mem_ctx memory context of this call
339 : * @param r pointer to structure containing arguments and result
340 : */
341 1 : NTSTATUS libnet_DeleteUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
342 : struct libnet_DeleteUser *r)
343 : {
344 1 : NTSTATUS status;
345 1 : struct delete_user_state *s;
346 :
347 1 : r->out.error_string = NULL;
348 :
349 : /* wait for result of async request and check status code */
350 1 : status = composite_wait(c);
351 1 : if (!NT_STATUS_IS_OK(status)) {
352 0 : s = talloc_get_type_abort(c->private_data, struct delete_user_state);
353 0 : r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
354 : }
355 :
356 1 : talloc_free(c);
357 1 : return status;
358 : }
359 :
360 :
361 : /**
362 : * Synchronous version of DeleteUser call
363 : *
364 : * @param ctx initialised libnet context
365 : * @param mem_ctx memory context of this call
366 : * @param r pointer to structure containing arguments and result
367 : */
368 1 : NTSTATUS libnet_DeleteUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
369 : struct libnet_DeleteUser *r)
370 : {
371 1 : struct composite_context *c;
372 :
373 1 : c = libnet_DeleteUser_send(ctx, mem_ctx, r, NULL);
374 1 : return libnet_DeleteUser_recv(c, mem_ctx, r);
375 : }
376 :
377 :
378 : struct modify_user_state {
379 : struct libnet_ModifyUser r;
380 : struct libnet_context *ctx;
381 : struct libnet_DomainOpen domain_open;
382 : struct libnet_rpc_userinfo user_info;
383 : struct libnet_rpc_usermod user_mod;
384 :
385 : void (*monitor_fn)(struct monitor_msg *);
386 : };
387 :
388 :
389 : static void continue_rpc_usermod(struct composite_context *ctx);
390 : static void continue_domain_open_modify(struct composite_context *ctx);
391 : static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
392 : struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r);
393 : static void continue_rpc_userinfo(struct composite_context *ctx);
394 :
395 :
396 : /**
397 : * Sends request to modify user account
398 : *
399 : * @param ctx initialised libnet context
400 : * @param mem_ctx memory context of this call
401 : * @param r pointer to structure containing arguments and result of this call
402 : * @param monitor function pointer for receiving monitor messages
403 : */
404 10 : struct composite_context *libnet_ModifyUser_send(struct libnet_context *ctx,
405 : TALLOC_CTX *mem_ctx,
406 : struct libnet_ModifyUser *r,
407 : void (*monitor)(struct monitor_msg*))
408 : {
409 10 : const uint16_t level = 21;
410 10 : struct composite_context *c;
411 10 : struct modify_user_state *s;
412 10 : struct composite_context *userinfo_req;
413 10 : bool prereq_met = false;
414 :
415 10 : c = composite_create(mem_ctx, ctx->event_ctx);
416 10 : if (c == NULL) return NULL;
417 :
418 10 : s = talloc_zero(c, struct modify_user_state);
419 10 : if (composite_nomem(s, c)) return c;
420 :
421 10 : c->private_data = s;
422 :
423 10 : s->ctx = ctx;
424 10 : s->r = *r;
425 :
426 10 : prereq_met = samr_domain_opened(ctx, c, s->r.in.domain_name, &c, &s->domain_open,
427 : continue_domain_open_modify, monitor);
428 10 : if (!prereq_met) return c;
429 :
430 9 : s->user_info.in.username = r->in.user_name;
431 9 : s->user_info.in.domain_handle = ctx->samr.handle;
432 9 : s->user_info.in.level = level;
433 :
434 9 : userinfo_req = libnet_rpc_userinfo_send(s, s->ctx->event_ctx,
435 : ctx->samr.samr_handle,
436 : &s->user_info, monitor);
437 9 : if (composite_nomem(userinfo_req, c)) return c;
438 :
439 9 : composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
440 9 : return c;
441 : }
442 :
443 :
444 : /*
445 : * Stage 0.5 (optional): receive result of domain open request
446 : * and send userinfo request
447 : */
448 1 : static void continue_domain_open_modify(struct composite_context *ctx)
449 : {
450 1 : const uint16_t level = 21;
451 1 : struct composite_context *c;
452 1 : struct modify_user_state *s;
453 1 : struct composite_context *userinfo_req;
454 1 : struct monitor_msg msg;
455 :
456 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
457 1 : s = talloc_get_type_abort(c->private_data, struct modify_user_state);
458 :
459 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
460 1 : if (!composite_is_ok(c)) return;
461 :
462 1 : if (s->monitor_fn) s->monitor_fn(&msg);
463 :
464 1 : s->user_info.in.domain_handle = s->ctx->samr.handle;
465 1 : s->user_info.in.username = s->r.in.user_name;
466 1 : s->user_info.in.level = level;
467 :
468 1 : userinfo_req = libnet_rpc_userinfo_send(s, s->ctx->event_ctx,
469 0 : s->ctx->samr.samr_handle,
470 : &s->user_info, s->monitor_fn);
471 1 : if (composite_nomem(userinfo_req, c)) return;
472 :
473 1 : composite_continue(c, userinfo_req, continue_rpc_userinfo, c);
474 : }
475 :
476 :
477 : /*
478 : * Stage 1: receive result of userinfo call, prepare user changes
479 : * (set the fields a caller required to change) and send usermod request
480 : */
481 10 : static void continue_rpc_userinfo(struct composite_context *ctx)
482 : {
483 10 : struct composite_context *c;
484 10 : struct modify_user_state *s;
485 10 : struct composite_context *usermod_req;
486 :
487 10 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
488 10 : s = talloc_get_type_abort(c->private_data, struct modify_user_state);
489 :
490 10 : c->status = libnet_rpc_userinfo_recv(ctx, c, &s->user_info);
491 10 : if (!composite_is_ok(c)) return;
492 :
493 10 : s->user_mod.in.domain_handle = s->ctx->samr.handle;
494 10 : s->user_mod.in.username = s->r.in.user_name;
495 :
496 10 : c->status = set_user_changes(c, &s->user_mod.in.change, &s->user_info, &s->r);
497 :
498 20 : usermod_req = libnet_rpc_usermod_send(s, s->ctx->event_ctx,
499 10 : s->ctx->samr.samr_handle,
500 : &s->user_mod, s->monitor_fn);
501 10 : if (composite_nomem(usermod_req, c)) return;
502 :
503 10 : composite_continue(c, usermod_req, continue_rpc_usermod, c);
504 : }
505 :
506 :
507 : /*
508 : * Prepare user changes: compare userinfo result to requested changes and
509 : * set the field values and flags accordingly for user modify call
510 : */
511 10 : static NTSTATUS set_user_changes(TALLOC_CTX *mem_ctx, struct usermod_change *mod,
512 : struct libnet_rpc_userinfo *info, struct libnet_ModifyUser *r)
513 : {
514 10 : struct samr_UserInfo21 *user;
515 :
516 10 : if (mod == NULL || info == NULL || r == NULL || info->in.level != 21) {
517 0 : return NT_STATUS_INVALID_PARAMETER;
518 : }
519 :
520 10 : user = &info->out.info.info21;
521 10 : mod->fields = 0; /* reset flag field before setting individual flags */
522 :
523 : /* account name change */
524 10 : SET_FIELD_LSA_STRING(r->in, user, mod, account_name, USERMOD_FIELD_ACCOUNT_NAME);
525 :
526 : /* full name change */
527 10 : SET_FIELD_LSA_STRING(r->in, user, mod, full_name, USERMOD_FIELD_FULL_NAME);
528 :
529 : /* description change */
530 10 : SET_FIELD_LSA_STRING(r->in, user, mod, description, USERMOD_FIELD_DESCRIPTION);
531 :
532 : /* comment change */
533 10 : SET_FIELD_LSA_STRING(r->in, user, mod, comment, USERMOD_FIELD_COMMENT);
534 :
535 : /* home directory change */
536 10 : SET_FIELD_LSA_STRING(r->in, user, mod, home_directory, USERMOD_FIELD_HOME_DIRECTORY);
537 :
538 : /* home drive change */
539 10 : SET_FIELD_LSA_STRING(r->in, user, mod, home_drive, USERMOD_FIELD_HOME_DRIVE);
540 :
541 : /* logon script change */
542 10 : SET_FIELD_LSA_STRING(r->in, user, mod, logon_script, USERMOD_FIELD_LOGON_SCRIPT);
543 :
544 : /* profile path change */
545 10 : SET_FIELD_LSA_STRING(r->in, user, mod, profile_path, USERMOD_FIELD_PROFILE_PATH);
546 :
547 : /* account expiry change */
548 10 : SET_FIELD_NTTIME(r->in, user, mod, acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
549 :
550 : /* account flags change */
551 10 : SET_FIELD_ACCT_FLAGS(r->in, user, mod, acct_flags, USERMOD_FIELD_ACCT_FLAGS);
552 :
553 10 : return NT_STATUS_OK;
554 : }
555 :
556 :
557 : /*
558 : * Stage 2: receive result of usermod request and finish the composite function
559 : */
560 10 : static void continue_rpc_usermod(struct composite_context *ctx)
561 : {
562 10 : struct composite_context *c;
563 10 : struct modify_user_state *s;
564 10 : struct monitor_msg msg;
565 :
566 10 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
567 10 : s = talloc_get_type_abort(c->private_data, struct modify_user_state);
568 :
569 10 : c->status = libnet_rpc_usermod_recv(ctx, c, &s->user_mod);
570 10 : if (!composite_is_ok(c)) return;
571 :
572 10 : if (s->monitor_fn) s->monitor_fn(&msg);
573 10 : composite_done(c);
574 : }
575 :
576 :
577 : /**
578 : * Receive result of ModifyUser call
579 : *
580 : * @param c composite context returned by send request routine
581 : * @param mem_ctx memory context of this call
582 : * @param r pointer to a structure containing arguments and result of this call
583 : * @return nt status
584 : */
585 10 : NTSTATUS libnet_ModifyUser_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
586 : struct libnet_ModifyUser *r)
587 : {
588 10 : NTSTATUS status = composite_wait(c);
589 :
590 10 : talloc_free(c);
591 10 : return status;
592 : }
593 :
594 :
595 : /**
596 : * Synchronous version of ModifyUser call
597 : *
598 : * @param ctx initialised libnet context
599 : * @param mem_ctx memory context of this call
600 : * @param r pointer to a structure containing arguments and result of this call
601 : * @return nt status
602 : */
603 10 : NTSTATUS libnet_ModifyUser(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
604 : struct libnet_ModifyUser *r)
605 : {
606 10 : struct composite_context *c;
607 :
608 10 : c = libnet_ModifyUser_send(ctx, mem_ctx, r, NULL);
609 10 : return libnet_ModifyUser_recv(c, mem_ctx, r);
610 : }
611 :
612 :
613 : struct user_info_state {
614 : struct libnet_context *ctx;
615 : const char *domain_name;
616 : enum libnet_UserInfo_level level;
617 : const char *user_name;
618 : const char *sid_string;
619 : struct libnet_LookupName lookup;
620 : struct libnet_DomainOpen domopen;
621 : struct libnet_rpc_userinfo userinfo;
622 :
623 : /* information about the progress */
624 : void (*monitor_fn)(struct monitor_msg *);
625 : };
626 :
627 :
628 : static void continue_name_found(struct composite_context *ctx);
629 : static void continue_domain_open_info(struct composite_context *ctx);
630 : static void continue_info_received(struct composite_context *ctx);
631 :
632 :
633 : /**
634 : * Sends request to get user account information
635 : *
636 : * @param ctx initialised libnet context
637 : * @param mem_ctx memory context of this call
638 : * @param r pointer to a structure containing arguments and results of this call
639 : * @param monitor function pointer for receiving monitor messages
640 : * @return compostite context of this request
641 : */
642 11 : struct composite_context* libnet_UserInfo_send(struct libnet_context *ctx,
643 : TALLOC_CTX *mem_ctx,
644 : struct libnet_UserInfo *r,
645 : void (*monitor)(struct monitor_msg*))
646 : {
647 11 : struct composite_context *c;
648 11 : struct user_info_state *s;
649 11 : struct composite_context *lookup_req, *info_req;
650 11 : bool prereq_met = false;
651 :
652 : /* composite context allocation and setup */
653 11 : c = composite_create(mem_ctx, ctx->event_ctx);
654 11 : if (c == NULL) return NULL;
655 :
656 11 : s = talloc_zero(c, struct user_info_state);
657 11 : if (composite_nomem(s, c)) return c;
658 :
659 11 : c->private_data = s;
660 :
661 : /* store arguments in the state structure */
662 11 : s->monitor_fn = monitor;
663 11 : s->ctx = ctx;
664 11 : s->domain_name = talloc_strdup(c, r->in.domain_name);
665 11 : s->level = r->in.level;
666 11 : switch (s->level) {
667 11 : case USER_INFO_BY_NAME:
668 11 : s->user_name = talloc_strdup(c, r->in.data.user_name);
669 11 : s->sid_string = NULL;
670 11 : break;
671 0 : case USER_INFO_BY_SID:
672 0 : s->user_name = NULL;
673 0 : s->sid_string = dom_sid_string(c, r->in.data.user_sid);
674 0 : break;
675 : }
676 :
677 : /* prerequisite: make sure the domain is opened */
678 11 : prereq_met = samr_domain_opened(ctx, c, s->domain_name, &c, &s->domopen,
679 : continue_domain_open_info, monitor);
680 11 : if (!prereq_met) return c;
681 :
682 10 : switch (s->level) {
683 10 : case USER_INFO_BY_NAME:
684 : /* prepare arguments for LookupName call */
685 10 : s->lookup.in.domain_name = s->domain_name;
686 10 : s->lookup.in.name = s->user_name;
687 :
688 : /* send the request */
689 10 : lookup_req = libnet_LookupName_send(ctx, c, &s->lookup,
690 : s->monitor_fn);
691 10 : if (composite_nomem(lookup_req, c)) return c;
692 :
693 : /* set the next stage */
694 10 : composite_continue(c, lookup_req, continue_name_found, c);
695 10 : break;
696 0 : case USER_INFO_BY_SID:
697 : /* prepare arguments for UserInfo call */
698 0 : s->userinfo.in.domain_handle = s->ctx->samr.handle;
699 0 : s->userinfo.in.sid = s->sid_string;
700 0 : s->userinfo.in.level = 21;
701 :
702 : /* send the request */
703 0 : info_req = libnet_rpc_userinfo_send(s, s->ctx->event_ctx,
704 0 : s->ctx->samr.samr_handle,
705 : &s->userinfo,
706 : s->monitor_fn);
707 0 : if (composite_nomem(info_req, c)) return c;
708 :
709 : /* set the next stage */
710 0 : composite_continue(c, info_req, continue_info_received, c);
711 0 : break;
712 : }
713 :
714 10 : return c;
715 : }
716 :
717 :
718 : /*
719 : * Stage 0.5 (optional): receive result of domain open request
720 : * and send LookupName request
721 : */
722 1 : static void continue_domain_open_info(struct composite_context *ctx)
723 : {
724 1 : struct composite_context *c;
725 1 : struct user_info_state *s;
726 1 : struct composite_context *lookup_req, *info_req;
727 1 : struct monitor_msg msg;
728 :
729 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
730 1 : s = talloc_get_type_abort(c->private_data, struct user_info_state);
731 :
732 : /* receive result of DomainOpen call */
733 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domopen);
734 1 : if (!composite_is_ok(c)) return;
735 :
736 : /* send monitor message */
737 1 : if (s->monitor_fn) s->monitor_fn(&msg);
738 :
739 1 : switch (s->level) {
740 1 : case USER_INFO_BY_NAME:
741 : /* prepare arguments for LookupName call */
742 1 : s->lookup.in.domain_name = s->domain_name;
743 1 : s->lookup.in.name = s->user_name;
744 :
745 : /* send the request */
746 1 : lookup_req = libnet_LookupName_send(s->ctx, c, &s->lookup, s->monitor_fn);
747 1 : if (composite_nomem(lookup_req, c)) return;
748 :
749 : /* set the next stage */
750 1 : composite_continue(c, lookup_req, continue_name_found, c);
751 1 : break;
752 :
753 0 : case USER_INFO_BY_SID:
754 : /* prepare arguments for UserInfo call */
755 0 : s->userinfo.in.domain_handle = s->ctx->samr.handle;
756 0 : s->userinfo.in.sid = s->sid_string;
757 0 : s->userinfo.in.level = 21;
758 :
759 : /* send the request */
760 0 : info_req = libnet_rpc_userinfo_send(s, s->ctx->event_ctx,
761 0 : s->ctx->samr.samr_handle,
762 : &s->userinfo,
763 : s->monitor_fn);
764 0 : if (composite_nomem(info_req, c)) return;
765 :
766 : /* set the next stage */
767 0 : composite_continue(c, info_req, continue_info_received, c);
768 0 : break;
769 : }
770 : }
771 :
772 :
773 : /*
774 : * Stage 1: receive the name (if found) and send userinfo request
775 : */
776 11 : static void continue_name_found(struct composite_context *ctx)
777 : {
778 11 : struct composite_context *c;
779 11 : struct user_info_state *s;
780 11 : struct composite_context *info_req;
781 :
782 11 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
783 11 : s = talloc_get_type_abort(c->private_data, struct user_info_state);
784 :
785 : /* receive result of LookupName call */
786 11 : c->status = libnet_LookupName_recv(ctx, c, &s->lookup);
787 11 : if (!composite_is_ok(c)) return;
788 :
789 : /* we're only interested in user accounts this time */
790 11 : if (s->lookup.out.sid_type != SID_NAME_USER) {
791 0 : composite_error(c, NT_STATUS_NO_SUCH_USER);
792 0 : return;
793 : }
794 :
795 : /* prepare arguments for UserInfo call */
796 11 : s->userinfo.in.domain_handle = s->ctx->samr.handle;
797 11 : s->userinfo.in.sid = s->lookup.out.sidstr;
798 11 : s->userinfo.in.level = 21;
799 :
800 : /* send the request */
801 11 : info_req = libnet_rpc_userinfo_send(s, s->ctx->event_ctx,
802 0 : s->ctx->samr.samr_handle,
803 : &s->userinfo, s->monitor_fn);
804 11 : if (composite_nomem(info_req, c)) return;
805 :
806 : /* set the next stage */
807 11 : composite_continue(c, info_req, continue_info_received, c);
808 : }
809 :
810 :
811 : /*
812 : * Stage 2: receive user account information and finish the composite function
813 : */
814 11 : static void continue_info_received(struct composite_context *ctx)
815 : {
816 11 : struct composite_context *c;
817 11 : struct user_info_state *s;
818 :
819 11 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
820 11 : s = talloc_get_type_abort(c->private_data, struct user_info_state);
821 :
822 : /* receive result of userinfo call */
823 11 : c->status = libnet_rpc_userinfo_recv(ctx, c, &s->userinfo);
824 11 : if (!composite_is_ok(c)) return;
825 :
826 11 : composite_done(c);
827 : }
828 :
829 :
830 : /**
831 : * Receive result of UserInfo call
832 : *
833 : * @param c composite context returned by send request routine
834 : * @param mem_ctx memory context of this call
835 : * @param r pointer to a structure containing arguments and result of this call
836 : * @return nt status
837 : */
838 11 : NTSTATUS libnet_UserInfo_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
839 : struct libnet_UserInfo *r)
840 : {
841 11 : NTSTATUS status;
842 11 : struct user_info_state *s;
843 :
844 11 : status = composite_wait(c);
845 :
846 11 : if (NT_STATUS_IS_OK(status) && r != NULL) {
847 11 : struct samr_UserInfo21 *info;
848 :
849 11 : s = talloc_get_type_abort(c->private_data, struct user_info_state);
850 11 : info = &s->userinfo.out.info.info21;
851 :
852 11 : r->out.user_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->rid);
853 11 : r->out.primary_group_sid = dom_sid_add_rid(mem_ctx, s->ctx->samr.sid, info->primary_gid);
854 :
855 : /* string fields */
856 11 : r->out.account_name = talloc_steal(mem_ctx, info->account_name.string);
857 11 : r->out.full_name = talloc_steal(mem_ctx, info->full_name.string);
858 11 : r->out.description = talloc_steal(mem_ctx, info->description.string);
859 11 : r->out.home_directory = talloc_steal(mem_ctx, info->home_directory.string);
860 11 : r->out.home_drive = talloc_steal(mem_ctx, info->home_drive.string);
861 11 : r->out.comment = talloc_steal(mem_ctx, info->comment.string);
862 11 : r->out.logon_script = talloc_steal(mem_ctx, info->logon_script.string);
863 11 : r->out.profile_path = talloc_steal(mem_ctx, info->profile_path.string);
864 :
865 : /* time fields (allocation) */
866 11 : r->out.acct_expiry = talloc(mem_ctx, struct timeval);
867 11 : r->out.allow_password_change = talloc(mem_ctx, struct timeval);
868 11 : r->out.force_password_change = talloc(mem_ctx, struct timeval);
869 11 : r->out.last_logon = talloc(mem_ctx, struct timeval);
870 11 : r->out.last_logoff = talloc(mem_ctx, struct timeval);
871 11 : r->out.last_password_change = talloc(mem_ctx, struct timeval);
872 :
873 : /* time fields (converting) */
874 11 : nttime_to_timeval(r->out.acct_expiry, info->acct_expiry);
875 11 : nttime_to_timeval(r->out.allow_password_change, info->allow_password_change);
876 11 : nttime_to_timeval(r->out.force_password_change, info->force_password_change);
877 11 : nttime_to_timeval(r->out.last_logon, info->last_logon);
878 11 : nttime_to_timeval(r->out.last_logoff, info->last_logoff);
879 11 : nttime_to_timeval(r->out.last_password_change, info->last_password_change);
880 :
881 : /* flag and number fields */
882 11 : r->out.acct_flags = info->acct_flags;
883 :
884 11 : r->out.error_string = talloc_strdup(mem_ctx, "Success");
885 :
886 : } else {
887 0 : r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
888 : }
889 :
890 11 : talloc_free(c);
891 11 : return status;
892 : }
893 :
894 :
895 : /**
896 : * Synchronous version of UserInfo call
897 : *
898 : * @param ctx initialised libnet context
899 : * @param mem_ctx memory context of this call
900 : * @param r pointer to a structure containing arguments and result of this call
901 : * @return nt status
902 : */
903 11 : NTSTATUS libnet_UserInfo(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
904 : struct libnet_UserInfo *r)
905 : {
906 11 : struct composite_context *c;
907 :
908 11 : c = libnet_UserInfo_send(ctx, mem_ctx, r, NULL);
909 11 : return libnet_UserInfo_recv(c, mem_ctx, r);
910 : }
911 :
912 :
913 : struct userlist_state {
914 : struct libnet_context *ctx;
915 : const char *domain_name;
916 : struct lsa_DomainInfo dominfo;
917 : int page_size;
918 : uint32_t resume_index;
919 : struct userlist *users;
920 : uint32_t count;
921 :
922 : struct libnet_DomainOpen domain_open;
923 : struct lsa_QueryInfoPolicy query_domain;
924 : struct samr_EnumDomainUsers user_list;
925 :
926 : void (*monitor_fn)(struct monitor_msg*);
927 : };
928 :
929 :
930 : static void continue_lsa_domain_opened(struct composite_context *ctx);
931 : static void continue_domain_queried(struct tevent_req *subreq);
932 : static void continue_samr_domain_opened(struct composite_context *ctx);
933 : static void continue_users_enumerated(struct tevent_req *subreq);
934 :
935 :
936 : /**
937 : * Sends request to list (enumerate) user accounts
938 : *
939 : * @param ctx initialised libnet context
940 : * @param mem_ctx memory context of this call
941 : * @param r pointer to structure containing arguments and results of this call
942 : * @param monitor function pointer for receiving monitor messages
943 : * @return compostite context of this request
944 : */
945 4 : struct composite_context* libnet_UserList_send(struct libnet_context *ctx,
946 : TALLOC_CTX *mem_ctx,
947 : struct libnet_UserList *r,
948 : void (*monitor)(struct monitor_msg*))
949 : {
950 4 : struct composite_context *c;
951 4 : struct userlist_state *s;
952 4 : struct tevent_req *subreq;
953 4 : bool prereq_met = false;
954 :
955 : /* composite context allocation and setup */
956 4 : c = composite_create(mem_ctx, ctx->event_ctx);
957 4 : if (c == NULL) return NULL;
958 :
959 4 : s = talloc_zero(c, struct userlist_state);
960 4 : if (composite_nomem(s, c)) return c;
961 :
962 4 : c->private_data = s;
963 :
964 : /* store the arguments in the state structure */
965 4 : s->ctx = ctx;
966 4 : s->page_size = r->in.page_size;
967 4 : s->resume_index = r->in.resume_index;
968 4 : s->domain_name = talloc_strdup(c, r->in.domain_name);
969 4 : s->monitor_fn = monitor;
970 :
971 : /* make sure we have lsa domain handle before doing anything */
972 4 : prereq_met = lsa_domain_opened(ctx, c, s->domain_name, &c, &s->domain_open,
973 : continue_lsa_domain_opened, monitor);
974 4 : if (!prereq_met) return c;
975 :
976 : /* prepare arguments of QueryDomainInfo call */
977 3 : s->query_domain.in.handle = &ctx->lsa.handle;
978 3 : s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
979 3 : s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *);
980 3 : if (composite_nomem(s->query_domain.out.info, c)) return c;
981 :
982 : /* send the request */
983 6 : subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
984 3 : ctx->lsa.pipe->binding_handle,
985 : &s->query_domain);
986 3 : if (composite_nomem(subreq, c)) return c;
987 :
988 3 : tevent_req_set_callback(subreq, continue_domain_queried, c);
989 3 : return c;
990 : }
991 :
992 :
993 : /*
994 : * Stage 0.5 (optional): receive lsa domain handle and send
995 : * request to query domain info
996 : */
997 1 : static void continue_lsa_domain_opened(struct composite_context *ctx)
998 : {
999 1 : struct composite_context *c;
1000 1 : struct userlist_state *s;
1001 1 : struct tevent_req *subreq;
1002 :
1003 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
1004 1 : s = talloc_get_type_abort(c->private_data, struct userlist_state);
1005 :
1006 : /* receive lsa domain handle */
1007 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
1008 1 : if (!composite_is_ok(c)) return;
1009 :
1010 : /* prepare arguments of QueryDomainInfo call */
1011 1 : s->query_domain.in.handle = &s->ctx->lsa.handle;
1012 1 : s->query_domain.in.level = LSA_POLICY_INFO_DOMAIN;
1013 1 : s->query_domain.out.info = talloc_zero(c, union lsa_PolicyInformation *);
1014 1 : if (composite_nomem(s->query_domain.out.info, c)) return;
1015 :
1016 : /* send the request */
1017 2 : subreq = dcerpc_lsa_QueryInfoPolicy_r_send(s, c->event_ctx,
1018 1 : s->ctx->lsa.pipe->binding_handle,
1019 : &s->query_domain);
1020 1 : if (composite_nomem(subreq, c)) return;
1021 :
1022 1 : tevent_req_set_callback(subreq, continue_domain_queried, c);
1023 : }
1024 :
1025 :
1026 : /*
1027 : * Stage 1: receive domain info and request to enum users,
1028 : * provided a valid samr handle is opened
1029 : */
1030 4 : static void continue_domain_queried(struct tevent_req *subreq)
1031 : {
1032 4 : struct composite_context *c;
1033 4 : struct userlist_state *s;
1034 4 : bool prereq_met = false;
1035 :
1036 4 : c = tevent_req_callback_data(subreq, struct composite_context);
1037 4 : s = talloc_get_type_abort(c->private_data, struct userlist_state);
1038 :
1039 : /* receive result of rpc request */
1040 4 : c->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, s);
1041 4 : TALLOC_FREE(subreq);
1042 5 : if (!composite_is_ok(c)) return;
1043 :
1044 : /* get the returned domain info */
1045 4 : s->dominfo = (*s->query_domain.out.info)->domain;
1046 :
1047 : /* make sure we have samr domain handle before continuing */
1048 4 : prereq_met = samr_domain_opened(s->ctx, c, s->domain_name, &c, &s->domain_open,
1049 : continue_samr_domain_opened, s->monitor_fn);
1050 4 : if (!prereq_met) return;
1051 :
1052 : /* prepare arguments of EnumDomainUsers call */
1053 3 : s->user_list.in.domain_handle = &s->ctx->samr.handle;
1054 3 : s->user_list.in.max_size = s->page_size;
1055 3 : s->user_list.in.resume_handle = &s->resume_index;
1056 3 : s->user_list.in.acct_flags = ACB_NORMAL;
1057 3 : s->user_list.out.resume_handle = &s->resume_index;
1058 3 : s->user_list.out.num_entries = talloc(s, uint32_t);
1059 3 : if (composite_nomem(s->user_list.out.num_entries, c)) return;
1060 3 : s->user_list.out.sam = talloc(s, struct samr_SamArray *);
1061 3 : if (composite_nomem(s->user_list.out.sam, c)) return;
1062 :
1063 : /* send the request */
1064 6 : subreq = dcerpc_samr_EnumDomainUsers_r_send(s, c->event_ctx,
1065 3 : s->ctx->samr.pipe->binding_handle,
1066 : &s->user_list);
1067 3 : if (composite_nomem(subreq, c)) return;
1068 :
1069 3 : tevent_req_set_callback(subreq, continue_users_enumerated, c);
1070 : }
1071 :
1072 :
1073 : /*
1074 : * Stage 1.5 (optional): receive samr domain handle
1075 : * and request to enumerate accounts
1076 : */
1077 1 : static void continue_samr_domain_opened(struct composite_context *ctx)
1078 : {
1079 1 : struct composite_context *c;
1080 1 : struct userlist_state *s;
1081 1 : struct tevent_req *subreq;
1082 :
1083 1 : c = talloc_get_type_abort(ctx->async.private_data, struct composite_context);
1084 1 : s = talloc_get_type_abort(c->private_data, struct userlist_state);
1085 :
1086 : /* receive samr domain handle */
1087 1 : c->status = libnet_DomainOpen_recv(ctx, s->ctx, c, &s->domain_open);
1088 1 : if (!composite_is_ok(c)) return;
1089 :
1090 : /* prepare arguments of EnumDomainUsers call */
1091 1 : s->user_list.in.domain_handle = &s->ctx->samr.handle;
1092 1 : s->user_list.in.max_size = s->page_size;
1093 1 : s->user_list.in.resume_handle = &s->resume_index;
1094 1 : s->user_list.in.acct_flags = ACB_NORMAL;
1095 1 : s->user_list.out.resume_handle = &s->resume_index;
1096 1 : s->user_list.out.sam = talloc(s, struct samr_SamArray *);
1097 1 : if (composite_nomem(s->user_list.out.sam, c)) return;
1098 1 : s->user_list.out.num_entries = talloc(s, uint32_t);
1099 1 : if (composite_nomem(s->user_list.out.num_entries, c)) return;
1100 :
1101 : /* send the request */
1102 2 : subreq = dcerpc_samr_EnumDomainUsers_r_send(s, c->event_ctx,
1103 1 : s->ctx->samr.pipe->binding_handle,
1104 : &s->user_list);
1105 1 : if (composite_nomem(subreq, c)) return;
1106 :
1107 1 : tevent_req_set_callback(subreq, continue_users_enumerated, c);
1108 : }
1109 :
1110 :
1111 : /*
1112 : * Stage 2: receive enumerated users and their rids
1113 : */
1114 4 : static void continue_users_enumerated(struct tevent_req *subreq)
1115 : {
1116 4 : struct composite_context *c;
1117 4 : struct userlist_state *s;
1118 4 : uint32_t i;
1119 :
1120 4 : c = tevent_req_callback_data(subreq, struct composite_context);
1121 4 : s = talloc_get_type_abort(c->private_data, struct userlist_state);
1122 :
1123 : /* receive result of rpc request */
1124 4 : c->status = dcerpc_samr_EnumDomainUsers_r_recv(subreq, s);
1125 4 : TALLOC_FREE(subreq);
1126 4 : if (!composite_is_ok(c)) return;
1127 :
1128 : /* get the actual status of the rpc call result
1129 : (instead of rpc layer status) */
1130 4 : c->status = s->user_list.out.result;
1131 :
1132 : /* we're interested in status "ok" as well as two
1133 : enum-specific status codes */
1134 4 : if (NT_STATUS_IS_OK(c->status) ||
1135 0 : NT_STATUS_EQUAL(c->status, STATUS_MORE_ENTRIES) ||
1136 0 : NT_STATUS_EQUAL(c->status, NT_STATUS_NO_MORE_ENTRIES)) {
1137 :
1138 : /* get enumerated accounts counter and resume handle (the latter allows
1139 : making subsequent call to continue enumeration) */
1140 4 : s->resume_index = *s->user_list.out.resume_handle;
1141 4 : s->count = *s->user_list.out.num_entries;
1142 :
1143 : /* prepare returned user accounts array */
1144 4 : s->users = talloc_array(c, struct userlist, (*s->user_list.out.sam)->count);
1145 4 : if (composite_nomem(s->users, c)) return;
1146 :
1147 16 : for (i = 0; i < (*s->user_list.out.sam)->count; i++) {
1148 12 : struct dom_sid *user_sid;
1149 12 : struct samr_SamEntry *entry = &(*s->user_list.out.sam)->entries[i];
1150 12 : struct dom_sid *domain_sid = (*s->query_domain.out.info)->domain.sid;
1151 :
1152 : /* construct user sid from returned rid and queried domain sid */
1153 12 : user_sid = dom_sid_add_rid(c, domain_sid, entry->idx);
1154 12 : if (composite_nomem(user_sid, c)) return;
1155 :
1156 : /* username */
1157 12 : s->users[i].username = talloc_strdup(s->users, entry->name.string);
1158 12 : if (composite_nomem(s->users[i].username, c)) return;
1159 :
1160 : /* sid string */
1161 12 : s->users[i].sid = dom_sid_string(s->users, user_sid);
1162 12 : if (composite_nomem(s->users[i].sid, c)) return;
1163 : }
1164 :
1165 : /* that's it */
1166 4 : composite_done(c);
1167 4 : return;
1168 :
1169 : } else {
1170 : /* something went wrong */
1171 0 : composite_error(c, c->status);
1172 0 : return;
1173 : }
1174 : }
1175 :
1176 :
1177 : /**
1178 : * Receive result of UserList call
1179 : *
1180 : * @param c composite context returned by send request routine
1181 : * @param mem_ctx memory context of this call
1182 : * @param r pointer to structure containing arguments and result of this call
1183 : * @return nt status
1184 : */
1185 4 : NTSTATUS libnet_UserList_recv(struct composite_context* c, TALLOC_CTX *mem_ctx,
1186 : struct libnet_UserList *r)
1187 : {
1188 4 : NTSTATUS status;
1189 4 : struct userlist_state *s;
1190 :
1191 4 : if (c == NULL || mem_ctx == NULL || r == NULL) {
1192 0 : talloc_free(c);
1193 0 : return NT_STATUS_INVALID_PARAMETER;
1194 : }
1195 :
1196 4 : status = composite_wait(c);
1197 4 : if (NT_STATUS_IS_OK(status) ||
1198 0 : NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) ||
1199 0 : NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES)) {
1200 :
1201 4 : s = talloc_get_type_abort(c->private_data, struct userlist_state);
1202 :
1203 : /* get results from composite context */
1204 4 : r->out.count = s->count;
1205 4 : r->out.resume_index = s->resume_index;
1206 4 : r->out.users = talloc_steal(mem_ctx, s->users);
1207 :
1208 4 : if (NT_STATUS_IS_OK(status)) {
1209 1 : r->out.error_string = talloc_strdup(mem_ctx, "Success");
1210 : } else {
1211 : /* success, but we're not done yet */
1212 3 : r->out.error_string = talloc_asprintf(mem_ctx, "Success (status: %s)",
1213 : nt_errstr(status));
1214 : }
1215 :
1216 : } else {
1217 0 : r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));
1218 : }
1219 :
1220 4 : talloc_free(c);
1221 4 : return status;
1222 : }
1223 :
1224 :
1225 : /**
1226 : * Synchronous version of UserList call
1227 : *
1228 : * @param ctx initialised libnet context
1229 : * @param mem_ctx memory context of this call
1230 : * @param r pointer to structure containing arguments and result of this call
1231 : * @return nt status
1232 : */
1233 4 : NTSTATUS libnet_UserList(struct libnet_context *ctx,
1234 : TALLOC_CTX *mem_ctx,
1235 : struct libnet_UserList *r)
1236 : {
1237 4 : struct composite_context *c;
1238 :
1239 4 : c = libnet_UserList_send(ctx, mem_ctx, r, NULL);
1240 4 : return libnet_UserList_recv(c, mem_ctx, r);
1241 : }
|