source: trunk/server/source4/libnet/userman.c@ 874

Last change on this file since 874 was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

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