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

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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