source: vendor/current/source4/libnet/userman.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 25.1 KB
Line 
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 a composite functions for user management operations (add/del/chg)
22*/
23
24#include "includes.h"
25#include "libcli/composite/composite.h"
26#include "libnet/libnet.h"
27#include "librpc/gen_ndr/ndr_samr_c.h"
28
29/*
30 * Composite USER ADD functionality
31 */
32
33struct useradd_state {
34 struct dcerpc_binding_handle *binding_handle;
35 struct policy_handle domain_handle;
36 struct samr_CreateUser createuser;
37 struct policy_handle user_handle;
38 uint32_t user_rid;
39
40 /* information about the progress */
41 void (*monitor_fn)(struct monitor_msg *);
42};
43
44
45static void continue_useradd_create(struct tevent_req *subreq);
46
47
48/**
49 * Stage 1 (and the only one for now): Create user account.
50 */
51static void continue_useradd_create(struct tevent_req *subreq)
52{
53 struct composite_context *c;
54 struct useradd_state *s;
55
56 c = tevent_req_callback_data(subreq, struct composite_context);
57 s = talloc_get_type(c->private_data, struct useradd_state);
58
59 /* check rpc layer status code */
60 c->status = dcerpc_samr_CreateUser_r_recv(subreq, s);
61 TALLOC_FREE(subreq);
62 if (!composite_is_ok(c)) return;
63
64 /* check create user call status code */
65 c->status = s->createuser.out.result;
66
67 /* get created user account data */
68 s->user_handle = *s->createuser.out.user_handle;
69 s->user_rid = *s->createuser.out.rid;
70
71 /* issue a monitor message */
72 if (s->monitor_fn) {
73 struct monitor_msg msg;
74 struct msg_rpc_create_user rpc_create;
75
76 rpc_create.rid = *s->createuser.out.rid;
77
78 msg.type = mon_SamrCreateUser;
79 msg.data = (void*)&rpc_create;
80 msg.data_size = sizeof(rpc_create);
81
82 s->monitor_fn(&msg);
83 }
84
85 composite_done(c);
86}
87
88
89/**
90 * Sends asynchronous useradd request
91 *
92 * @param p dce/rpc call pipe
93 * @param io arguments and results of the call
94 * @param monitor monitor function for providing information about the progress
95 */
96
97struct composite_context *libnet_rpc_useradd_send(TALLOC_CTX *mem_ctx,
98 struct tevent_context *ev,
99 struct dcerpc_binding_handle *b,
100 struct libnet_rpc_useradd *io,
101 void (*monitor)(struct monitor_msg*))
102{
103 struct composite_context *c;
104 struct useradd_state *s;
105 struct tevent_req *subreq;
106
107 if (!b || !io) return NULL;
108
109 /* composite allocation and setup */
110 c = composite_create(mem_ctx, ev);
111 if (c == NULL) return NULL;
112
113 s = talloc_zero(c, struct useradd_state);
114 if (composite_nomem(s, c)) return c;
115
116 c->private_data = s;
117
118 /* put passed arguments to the state structure */
119 s->domain_handle = io->in.domain_handle;
120 s->binding_handle= b;
121 s->monitor_fn = monitor;
122
123 /* preparing parameters to send rpc request */
124 s->createuser.in.domain_handle = &io->in.domain_handle;
125
126 s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
127 if (composite_nomem(s->createuser.in.account_name, c)) return c;
128
129 s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
130 if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
131
132 s->createuser.out.user_handle = &s->user_handle;
133 s->createuser.out.rid = &s->user_rid;
134
135 /* send the request */
136 subreq = dcerpc_samr_CreateUser_r_send(s, c->event_ctx,
137 s->binding_handle,
138 &s->createuser);
139 if (composite_nomem(subreq, c)) return c;
140
141 tevent_req_set_callback(subreq, continue_useradd_create, c);
142 return c;
143}
144
145
146/**
147 * Waits for and receives result of asynchronous useradd call
148 *
149 * @param c composite context returned by asynchronous useradd call
150 * @param mem_ctx memory context of the call
151 * @param io pointer to results (and arguments) of the call
152 * @return nt status code of execution
153 */
154
155NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
156 struct libnet_rpc_useradd *io)
157{
158 NTSTATUS status;
159 struct useradd_state *s;
160
161 status = composite_wait(c);
162
163 if (NT_STATUS_IS_OK(status) && io) {
164 /* get and return result of the call */
165 s = talloc_get_type(c->private_data, struct useradd_state);
166 io->out.user_handle = s->user_handle;
167 }
168
169 talloc_free(c);
170 return status;
171}
172
173
174/**
175 * Synchronous version of useradd call
176 *
177 * @param pipe dce/rpc call pipe
178 * @param mem_ctx memory context for the call
179 * @param io arguments and results of the call
180 * @return nt status code of execution
181 */
182
183NTSTATUS libnet_rpc_useradd(struct tevent_context *ev,
184 struct dcerpc_binding_handle *b,
185 TALLOC_CTX *mem_ctx,
186 struct libnet_rpc_useradd *io)
187{
188 struct composite_context *c = libnet_rpc_useradd_send(mem_ctx, ev, b, io, NULL);
189 return libnet_rpc_useradd_recv(c, mem_ctx, io);
190}
191
192
193
194/*
195 * Composite USER DELETE functionality
196 */
197
198
199struct userdel_state {
200 struct dcerpc_binding_handle *binding_handle;
201 struct policy_handle domain_handle;
202 struct policy_handle user_handle;
203 struct samr_LookupNames lookupname;
204 struct samr_OpenUser openuser;
205 struct samr_DeleteUser deleteuser;
206
207 /* information about the progress */
208 void (*monitor_fn)(struct monitor_msg *);
209};
210
211
212static void continue_userdel_name_found(struct tevent_req *subreq);
213static void continue_userdel_user_opened(struct tevent_req *subreq);
214static void continue_userdel_deleted(struct tevent_req *subreq);
215
216
217/**
218 * Stage 1: Lookup the user name and resolve it to rid
219 */
220static void continue_userdel_name_found(struct tevent_req *subreq)
221{
222 struct composite_context *c;
223 struct userdel_state *s;
224 struct monitor_msg msg;
225
226 c = tevent_req_callback_data(subreq, struct composite_context);
227 s = talloc_get_type(c->private_data, struct userdel_state);
228
229 /* receive samr_LookupNames result */
230 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
231 TALLOC_FREE(subreq);
232 if (!composite_is_ok(c)) return;
233
234 c->status = s->lookupname.out.result;
235 if (!NT_STATUS_IS_OK(c->status)) {
236 composite_error(c, c->status);
237 return;
238 }
239
240 /* what to do when there's no user account to delete
241 and what if there's more than one rid resolved */
242 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
243 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
244 return;
245 }
246 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
247 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
248 return;
249 }
250
251 /* issue a monitor message */
252 if (s->monitor_fn) {
253 struct msg_rpc_lookup_name msg_lookup;
254
255 msg_lookup.rid = s->lookupname.out.rids->ids;
256 msg_lookup.count = s->lookupname.out.rids->count;
257
258 msg.type = mon_SamrLookupName;
259 msg.data = (void*)&msg_lookup;
260 msg.data_size = sizeof(msg_lookup);
261 s->monitor_fn(&msg);
262 }
263
264 /* prepare the arguments for rpc call */
265 s->openuser.in.domain_handle = &s->domain_handle;
266 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
267 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
268 s->openuser.out.user_handle = &s->user_handle;
269
270 /* send rpc request */
271 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
272 s->binding_handle,
273 &s->openuser);
274 if (composite_nomem(subreq, c)) return;
275
276 tevent_req_set_callback(subreq, continue_userdel_user_opened, c);
277}
278
279
280/**
281 * Stage 2: Open user account.
282 */
283static void continue_userdel_user_opened(struct tevent_req *subreq)
284{
285 struct composite_context *c;
286 struct userdel_state *s;
287 struct monitor_msg msg;
288
289 c = tevent_req_callback_data(subreq, struct composite_context);
290 s = talloc_get_type(c->private_data, struct userdel_state);
291
292 /* receive samr_OpenUser result */
293 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
294 TALLOC_FREE(subreq);
295 if (!composite_is_ok(c)) return;
296
297 c->status = s->openuser.out.result;
298 if (!NT_STATUS_IS_OK(c->status)) {
299 composite_error(c, c->status);
300 return;
301 }
302
303 /* issue a monitor message */
304 if (s->monitor_fn) {
305 struct msg_rpc_open_user msg_open;
306
307 msg_open.rid = s->openuser.in.rid;
308 msg_open.access_mask = s->openuser.in.access_mask;
309
310 msg.type = mon_SamrOpenUser;
311 msg.data = (void*)&msg_open;
312 msg.data_size = sizeof(msg_open);
313 s->monitor_fn(&msg);
314 }
315
316 /* prepare the final rpc call arguments */
317 s->deleteuser.in.user_handle = &s->user_handle;
318 s->deleteuser.out.user_handle = &s->user_handle;
319
320 /* send rpc request */
321 subreq = dcerpc_samr_DeleteUser_r_send(s, c->event_ctx,
322 s->binding_handle,
323 &s->deleteuser);
324 if (composite_nomem(subreq, c)) return;
325
326 /* callback handler setup */
327 tevent_req_set_callback(subreq, continue_userdel_deleted, c);
328}
329
330
331/**
332 * Stage 3: Delete user account
333 */
334static void continue_userdel_deleted(struct tevent_req *subreq)
335{
336 struct composite_context *c;
337 struct userdel_state *s;
338 struct monitor_msg msg;
339
340 c = tevent_req_callback_data(subreq, struct composite_context);
341 s = talloc_get_type(c->private_data, struct userdel_state);
342
343 /* receive samr_DeleteUser result */
344 c->status = dcerpc_samr_DeleteUser_r_recv(subreq, s);
345 TALLOC_FREE(subreq);
346 if (!composite_is_ok(c)) return;
347
348 /* return the actual function call status */
349 c->status = s->deleteuser.out.result;
350 if (!NT_STATUS_IS_OK(c->status)) {
351 composite_error(c, c->status);
352 return;
353 }
354
355 /* issue a monitor message */
356 if (s->monitor_fn) {
357 msg.type = mon_SamrDeleteUser;
358 msg.data = NULL;
359 msg.data_size = 0;
360 s->monitor_fn(&msg);
361 }
362
363 composite_done(c);
364}
365
366
367/**
368 * Sends asynchronous userdel request
369 *
370 * @param p dce/rpc call pipe
371 * @param io arguments and results of the call
372 * @param monitor monitor function for providing information about the progress
373 */
374
375struct composite_context *libnet_rpc_userdel_send(TALLOC_CTX *mem_ctx,
376 struct tevent_context *ev,
377 struct dcerpc_binding_handle *b,
378 struct libnet_rpc_userdel *io,
379 void (*monitor)(struct monitor_msg*))
380{
381 struct composite_context *c;
382 struct userdel_state *s;
383 struct tevent_req *subreq;
384
385 /* composite context allocation and setup */
386 c = composite_create(mem_ctx, ev);
387 if (c == NULL) return NULL;
388
389 s = talloc_zero(c, struct userdel_state);
390 if (composite_nomem(s, c)) return c;
391
392 c->private_data = s;
393
394 /* store function parameters in the state structure */
395 s->binding_handle= b;
396 s->domain_handle = io->in.domain_handle;
397 s->monitor_fn = monitor;
398
399 /* preparing parameters to send rpc request */
400 s->lookupname.in.domain_handle = &io->in.domain_handle;
401 s->lookupname.in.num_names = 1;
402 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
403 s->lookupname.in.names->string = io->in.username;
404 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
405 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
406 if (composite_nomem(s->lookupname.out.rids, c)) return c;
407 if (composite_nomem(s->lookupname.out.types, c)) return c;
408
409 /* send the request */
410 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
411 s->binding_handle,
412 &s->lookupname);
413 if (composite_nomem(subreq, c)) return c;
414
415 /* set the next stage */
416 tevent_req_set_callback(subreq, continue_userdel_name_found, c);
417 return c;
418}
419
420
421/**
422 * Waits for and receives results of asynchronous userdel call
423 *
424 * @param c composite context returned by asynchronous userdel call
425 * @param mem_ctx memory context of the call
426 * @param io pointer to results (and arguments) of the call
427 * @return nt status code of execution
428 */
429
430NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
431 struct libnet_rpc_userdel *io)
432{
433 NTSTATUS status;
434 struct userdel_state *s;
435
436 status = composite_wait(c);
437
438 if (NT_STATUS_IS_OK(status) && io) {
439 s = talloc_get_type(c->private_data, struct userdel_state);
440 io->out.user_handle = s->user_handle;
441 }
442
443 talloc_free(c);
444 return status;
445}
446
447
448/**
449 * Synchronous version of userdel call
450 *
451 * @param pipe dce/rpc call pipe
452 * @param mem_ctx memory context for the call
453 * @param io arguments and results of the call
454 * @return nt status code of execution
455 */
456
457NTSTATUS libnet_rpc_userdel(struct tevent_context *ev,
458 struct dcerpc_binding_handle *b,
459 TALLOC_CTX *mem_ctx,
460 struct libnet_rpc_userdel *io)
461{
462 struct composite_context *c = libnet_rpc_userdel_send(mem_ctx, ev, b, io, NULL);
463 return libnet_rpc_userdel_recv(c, mem_ctx, io);
464}
465
466
467/*
468 * USER MODIFY functionality
469 */
470
471static void continue_usermod_name_found(struct tevent_req *subreq);
472static void continue_usermod_user_opened(struct tevent_req *subreq);
473static void continue_usermod_user_queried(struct tevent_req *subreq);
474static void continue_usermod_user_changed(struct tevent_req *subreq);
475
476
477struct usermod_state {
478 struct dcerpc_binding_handle *binding_handle;
479 struct policy_handle domain_handle;
480 struct policy_handle user_handle;
481 struct usermod_change change;
482 union samr_UserInfo info;
483 struct samr_LookupNames lookupname;
484 struct samr_OpenUser openuser;
485 struct samr_SetUserInfo setuser;
486 struct samr_QueryUserInfo queryuser;
487
488 /* information about the progress */
489 void (*monitor_fn)(struct monitor_msg *);
490};
491
492
493/**
494 * Step 1: Lookup user name
495 */
496static void continue_usermod_name_found(struct tevent_req *subreq)
497{
498 struct composite_context *c;
499 struct usermod_state *s;
500 struct monitor_msg msg;
501
502 c = tevent_req_callback_data(subreq, struct composite_context);
503 s = talloc_get_type(c->private_data, struct usermod_state);
504
505 /* receive samr_LookupNames result */
506 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
507 TALLOC_FREE(subreq);
508 if (!composite_is_ok(c)) return;
509
510 c->status = s->lookupname.out.result;
511 if (!NT_STATUS_IS_OK(c->status)) {
512 composite_error(c, c->status);
513 return;
514 }
515
516 /* what to do when there's no user account to delete
517 and what if there's more than one rid resolved */
518 if (s->lookupname.out.rids->count != s->lookupname.in.num_names) {
519 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
520 return;
521 }
522 if (s->lookupname.out.types->count != s->lookupname.in.num_names) {
523 composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
524 return;
525 }
526
527 /* issue a monitor message */
528 if (s->monitor_fn) {
529 struct msg_rpc_lookup_name msg_lookup;
530
531 msg_lookup.rid = s->lookupname.out.rids->ids;
532 msg_lookup.count = s->lookupname.out.rids->count;
533
534 msg.type = mon_SamrLookupName;
535 msg.data = (void*)&msg_lookup;
536 msg.data_size = sizeof(msg_lookup);
537 s->monitor_fn(&msg);
538 }
539
540 /* prepare the next rpc call */
541 s->openuser.in.domain_handle = &s->domain_handle;
542 s->openuser.in.rid = s->lookupname.out.rids->ids[0];
543 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
544 s->openuser.out.user_handle = &s->user_handle;
545
546 /* send the rpc request */
547 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
548 s->binding_handle,
549 &s->openuser);
550 if (composite_nomem(subreq, c)) return;
551
552 tevent_req_set_callback(subreq, continue_usermod_user_opened, c);
553}
554
555
556/**
557 * Choose a proper level of samr_UserInfo structure depending on required
558 * change specified by means of flags field. Subsequent calls of this
559 * function are made until there's no flags set meaning that all of the
560 * changes have been made.
561 */
562static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
563 union samr_UserInfo *i, bool queried)
564{
565 if (s->change.fields == 0) return s->change.fields;
566
567 *level = 0;
568
569 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
570 (*level == 0 || *level == 7)) {
571 *level = 7;
572 i->info7.account_name.string = s->change.account_name;
573
574 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
575 }
576
577 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
578 (*level == 0 || *level == 8)) {
579 *level = 8;
580 i->info8.full_name.string = s->change.full_name;
581
582 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
583 }
584
585 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
586 (*level == 0 || *level == 13)) {
587 *level = 13;
588 i->info13.description.string = s->change.description;
589
590 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
591 }
592
593 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
594 (*level == 0 || *level == 2)) {
595 *level = 2;
596
597 if (queried) {
598 /* the user info is obtained, so now set the required field */
599 i->info2.comment.string = s->change.comment;
600 s->change.fields ^= USERMOD_FIELD_COMMENT;
601
602 } else {
603 /* we need to query the user info before setting one field in it */
604 return false;
605 }
606 }
607
608 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
609 (*level == 0 || *level == 11)) {
610 *level = 11;
611 i->info11.logon_script.string = s->change.logon_script;
612
613 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
614 }
615
616 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
617 (*level == 0 || *level == 12)) {
618 *level = 12;
619 i->info12.profile_path.string = s->change.profile_path;
620
621 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
622 }
623
624 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
625 (*level == 0 || *level == 10)) {
626 *level = 10;
627
628 if (queried) {
629 i->info10.home_directory.string = s->change.home_directory;
630 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
631 } else {
632 return false;
633 }
634 }
635
636 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
637 (*level == 0 || *level == 10)) {
638 *level = 10;
639
640 if (queried) {
641 i->info10.home_drive.string = s->change.home_drive;
642 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
643 } else {
644 return false;
645 }
646 }
647
648 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
649 (*level == 0 || *level == 17)) {
650 *level = 17;
651 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
652
653 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
654 }
655
656 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
657 (*level == 0 || *level == 16)) {
658 *level = 16;
659 i->info16.acct_flags = s->change.acct_flags;
660
661 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
662 }
663
664 /* We're going to be here back again soon unless all fields have been set */
665 return true;
666}
667
668
669static NTSTATUS usermod_change(struct composite_context *c,
670 struct usermod_state *s)
671{
672 bool do_set;
673 union samr_UserInfo *i = &s->info;
674 struct tevent_req *subreq;
675
676 /* set the level to invalid value, so that unless setfields routine
677 gives it a valid value we report the error correctly */
678 uint16_t level = 27;
679
680 /* prepare UserInfo level and data based on bitmask field */
681 do_set = usermod_setfields(s, &level, i, false);
682
683 if (level < 1 || level > 26) {
684 /* apparently there's a field that the setfields routine
685 does not know how to set */
686 return NT_STATUS_INVALID_PARAMETER;
687 }
688
689 /* If some specific level is used to set user account data and the change
690 itself does not cover all fields then we need to query the user info
691 first, right before changing the data. Otherwise we could set required
692 fields and accidentally reset the others.
693 */
694 if (!do_set) {
695 s->queryuser.in.user_handle = &s->user_handle;
696 s->queryuser.in.level = level;
697 s->queryuser.out.info = talloc(s, union samr_UserInfo *);
698 if (composite_nomem(s->queryuser.out.info, c)) return NT_STATUS_NO_MEMORY;
699
700
701 /* send query user info request to retrieve complete data of
702 a particular info level */
703 subreq = dcerpc_samr_QueryUserInfo_r_send(s, c->event_ctx,
704 s->binding_handle,
705 &s->queryuser);
706 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
707 tevent_req_set_callback(subreq, continue_usermod_user_queried, c);
708
709 } else {
710 s->setuser.in.user_handle = &s->user_handle;
711 s->setuser.in.level = level;
712 s->setuser.in.info = i;
713
714 /* send set user info request after making required change */
715 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
716 s->binding_handle,
717 &s->setuser);
718 if (composite_nomem(subreq, c)) return NT_STATUS_NO_MEMORY;
719 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
720 }
721
722 return NT_STATUS_OK;
723}
724
725
726/**
727 * Stage 2: Open user account
728 */
729static void continue_usermod_user_opened(struct tevent_req *subreq)
730{
731 struct composite_context *c;
732 struct usermod_state *s;
733
734 c = tevent_req_callback_data(subreq, struct composite_context);
735 s = talloc_get_type(c->private_data, struct usermod_state);
736
737 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
738 TALLOC_FREE(subreq);
739 if (!composite_is_ok(c)) return;
740
741 c->status = s->openuser.out.result;
742 if (!NT_STATUS_IS_OK(c->status)) {
743 composite_error(c, c->status);
744 return;
745 }
746
747 c->status = usermod_change(c, s);
748}
749
750
751/**
752 * Stage 2a (optional): Query the user information
753 */
754static void continue_usermod_user_queried(struct tevent_req *subreq)
755{
756 struct composite_context *c;
757 struct usermod_state *s;
758 union samr_UserInfo *i;
759 uint16_t level = 0;
760
761 c = tevent_req_callback_data(subreq, struct composite_context);
762 s = talloc_get_type(c->private_data, struct usermod_state);
763
764 i = &s->info;
765
766 /* receive samr_QueryUserInfo result */
767 c->status = dcerpc_samr_QueryUserInfo_r_recv(subreq, s);
768 TALLOC_FREE(subreq);
769 if (!composite_is_ok(c)) return;
770
771 c->status = s->queryuser.out.result;
772 if (!NT_STATUS_IS_OK(c->status)) {
773 composite_error(c, c->status);
774 return;
775 }
776
777 /* get returned user data and make a change (potentially one
778 of many) */
779 s->info = *(*s->queryuser.out.info);
780
781 usermod_setfields(s, &level, i, true);
782
783 /* prepare rpc call arguments */
784 s->setuser.in.user_handle = &s->user_handle;
785 s->setuser.in.level = level;
786 s->setuser.in.info = i;
787
788 /* send the rpc request */
789 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
790 s->binding_handle,
791 &s->setuser);
792 if (composite_nomem(subreq, c)) return;
793 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
794}
795
796
797/**
798 * Stage 3: Set new user account data
799 */
800static void continue_usermod_user_changed(struct tevent_req *subreq)
801{
802 struct composite_context *c;
803 struct usermod_state *s;
804
805 c = tevent_req_callback_data(subreq, struct composite_context);
806 s = talloc_get_type(c->private_data, struct usermod_state);
807
808 /* receive samr_SetUserInfo result */
809 c->status = dcerpc_samr_SetUserInfo_r_recv(subreq, s);
810 TALLOC_FREE(subreq);
811 if (!composite_is_ok(c)) return;
812
813 /* return the actual function call status */
814 c->status = s->setuser.out.result;
815 if (!NT_STATUS_IS_OK(c->status)) {
816 composite_error(c, c->status);
817 return;
818 }
819
820 if (s->change.fields == 0) {
821 /* all fields have been set - we're done */
822 composite_done(c);
823
824 } else {
825 /* something's still not changed - repeat the procedure */
826 c->status = usermod_change(c, s);
827 }
828}
829
830
831/**
832 * Sends asynchronous usermod request
833 *
834 * @param p dce/rpc call pipe
835 * @param io arguments and results of the call
836 * @param monitor monitor function for providing information about the progress
837 */
838
839struct composite_context *libnet_rpc_usermod_send(TALLOC_CTX *mem_ctx,
840 struct tevent_context *ev,
841 struct dcerpc_binding_handle *b,
842 struct libnet_rpc_usermod *io,
843 void (*monitor)(struct monitor_msg*))
844{
845 struct composite_context *c;
846 struct usermod_state *s;
847 struct tevent_req *subreq;
848
849 /* composite context allocation and setup */
850 c = composite_create(mem_ctx, ev);
851 if (c == NULL) return NULL;
852 s = talloc_zero(c, struct usermod_state);
853 if (composite_nomem(s, c)) return c;
854
855 c->private_data = s;
856
857 /* store parameters in the call structure */
858 s->binding_handle= b;
859 s->domain_handle = io->in.domain_handle;
860 s->change = io->in.change;
861 s->monitor_fn = monitor;
862
863 /* prepare rpc call arguments */
864 s->lookupname.in.domain_handle = &io->in.domain_handle;
865 s->lookupname.in.num_names = 1;
866 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
867 s->lookupname.in.names->string = io->in.username;
868 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
869 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
870 if (composite_nomem(s->lookupname.out.rids, c)) return c;
871 if (composite_nomem(s->lookupname.out.types, c)) return c;
872
873 /* send the rpc request */
874 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
875 s->binding_handle,
876 &s->lookupname);
877 if (composite_nomem(subreq, c)) return c;
878
879 /* callback handler setup */
880 tevent_req_set_callback(subreq, continue_usermod_name_found, c);
881 return c;
882}
883
884
885/**
886 * Waits for and receives results of asynchronous usermod call
887 *
888 * @param c composite context returned by asynchronous usermod call
889 * @param mem_ctx memory context of the call
890 * @param io pointer to results (and arguments) of the call
891 * @return nt status code of execution
892 */
893
894NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
895 struct libnet_rpc_usermod *io)
896{
897 NTSTATUS status;
898
899 status = composite_wait(c);
900
901 talloc_free(c);
902 return status;
903}
904
905
906/**
907 * Synchronous version of usermod call
908 *
909 * @param pipe dce/rpc call pipe
910 * @param mem_ctx memory context for the call
911 * @param io arguments and results of the call
912 * @return nt status code of execution
913 */
914
915NTSTATUS libnet_rpc_usermod(struct tevent_context *ev,
916 struct dcerpc_binding_handle *b,
917 TALLOC_CTX *mem_ctx,
918 struct libnet_rpc_usermod *io)
919{
920 struct composite_context *c = libnet_rpc_usermod_send(mem_ctx, ev, b, io, NULL);
921 return libnet_rpc_usermod_recv(c, mem_ctx, io);
922}
Note: See TracBrowser for help on using the repository browser.