Add a test to show that zero-length EA's are never returned over SMB2.
[Samba/vl.git] / source4 / libnet / userman.c
blobc1ee0179902719c0fd5d588c5ef1dc447ecee667
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Rafal Szczesniak 2005
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 a composite functions for user management operations (add/del/chg)
24 #include "includes.h"
25 #include "libcli/composite/composite.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_samr_c.h"
30 * Composite USER ADD functionality
33 struct 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;
40 /* information about the progress */
41 void (*monitor_fn)(struct monitor_msg *);
45 static void continue_useradd_create(struct tevent_req *subreq);
48 /**
49 * Stage 1 (and the only one for now): Create user account.
51 static void continue_useradd_create(struct tevent_req *subreq)
53 struct composite_context *c;
54 struct useradd_state *s;
56 c = tevent_req_callback_data(subreq, struct composite_context);
57 s = talloc_get_type(c->private_data, struct useradd_state);
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;
64 /* check create user call status code */
65 c->status = s->createuser.out.result;
67 /* get created user account data */
68 s->user_handle = *s->createuser.out.user_handle;
69 s->user_rid = *s->createuser.out.rid;
71 /* issue a monitor message */
72 if (s->monitor_fn) {
73 struct monitor_msg msg;
74 struct msg_rpc_create_user rpc_create;
76 rpc_create.rid = *s->createuser.out.rid;
78 msg.type = mon_SamrCreateUser;
79 msg.data = (void*)&rpc_create;
80 msg.data_size = sizeof(rpc_create);
82 s->monitor_fn(&msg);
85 composite_done(c);
89 /**
90 * Sends asynchronous useradd request
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
97 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
98 TALLOC_CTX *mem_ctx,
99 struct libnet_rpc_useradd *io,
100 void (*monitor)(struct monitor_msg*))
102 struct composite_context *c;
103 struct useradd_state *s;
104 struct tevent_req *subreq;
106 if (!p || !io) return NULL;
108 /* composite allocation and setup */
109 c = composite_create(mem_ctx, dcerpc_event_context(p));
110 if (c == NULL) return NULL;
112 s = talloc_zero(c, struct useradd_state);
113 if (composite_nomem(s, c)) return c;
115 c->private_data = s;
117 /* put passed arguments to the state structure */
118 s->domain_handle = io->in.domain_handle;
119 s->pipe = p;
120 s->monitor_fn = monitor;
122 /* preparing parameters to send rpc request */
123 s->createuser.in.domain_handle = &io->in.domain_handle;
125 s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
126 if (composite_nomem(s->createuser.in.account_name, c)) return c;
128 s->createuser.in.account_name->string = talloc_strdup(c, io->in.username);
129 if (composite_nomem(s->createuser.in.account_name->string, c)) return c;
131 s->createuser.out.user_handle = &s->user_handle;
132 s->createuser.out.rid = &s->user_rid;
134 /* send the request */
135 subreq = dcerpc_samr_CreateUser_r_send(s, c->event_ctx,
136 p->binding_handle,
137 &s->createuser);
138 if (composite_nomem(subreq, c)) return c;
140 tevent_req_set_callback(subreq, continue_useradd_create, c);
141 return c;
146 * Waits for and receives result of asynchronous useradd call
148 * @param c composite context returned by asynchronous useradd call
149 * @param mem_ctx memory context of the call
150 * @param io pointer to results (and arguments) of the call
151 * @return nt status code of execution
154 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
155 struct libnet_rpc_useradd *io)
157 NTSTATUS status;
158 struct useradd_state *s;
160 status = composite_wait(c);
162 if (NT_STATUS_IS_OK(status) && io) {
163 /* get and return result of the call */
164 s = talloc_get_type(c->private_data, struct useradd_state);
165 io->out.user_handle = s->user_handle;
168 talloc_free(c);
169 return status;
174 * Synchronous version of useradd call
176 * @param pipe dce/rpc call pipe
177 * @param mem_ctx memory context for the call
178 * @param io arguments and results of the call
179 * @return nt status code of execution
182 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
183 TALLOC_CTX *mem_ctx,
184 struct libnet_rpc_useradd *io)
186 struct composite_context *c = libnet_rpc_useradd_send(p, mem_ctx, io, NULL);
187 return libnet_rpc_useradd_recv(c, mem_ctx, io);
193 * Composite USER DELETE functionality
197 struct userdel_state {
198 struct dcerpc_pipe *pipe;
199 struct policy_handle domain_handle;
200 struct policy_handle user_handle;
201 struct samr_LookupNames lookupname;
202 struct samr_OpenUser openuser;
203 struct samr_DeleteUser deleteuser;
205 /* information about the progress */
206 void (*monitor_fn)(struct monitor_msg *);
210 static void continue_userdel_name_found(struct tevent_req *subreq);
211 static void continue_userdel_user_opened(struct tevent_req *subreq);
212 static void continue_userdel_deleted(struct tevent_req *subreq);
216 * Stage 1: Lookup the user name and resolve it to rid
218 static void continue_userdel_name_found(struct tevent_req *subreq)
220 struct composite_context *c;
221 struct userdel_state *s;
222 struct monitor_msg msg;
224 c = tevent_req_callback_data(subreq, struct composite_context);
225 s = talloc_get_type(c->private_data, struct userdel_state);
227 /* receive samr_LookupNames result */
228 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
229 TALLOC_FREE(subreq);
230 if (!composite_is_ok(c)) return;
232 c->status = s->lookupname.out.result;
233 if (!NT_STATUS_IS_OK(c->status)) {
234 composite_error(c, c->status);
235 return;
238 /* what to do when there's no user account to delete
239 and what if there's more than one rid resolved */
240 if (!s->lookupname.out.rids->count) {
241 c->status = NT_STATUS_NO_SUCH_USER;
242 composite_error(c, c->status);
243 return;
245 } else if (!s->lookupname.out.rids->count > 1) {
246 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
247 composite_error(c, c->status);
248 return;
251 /* issue a monitor message */
252 if (s->monitor_fn) {
253 struct msg_rpc_lookup_name msg_lookup;
255 msg_lookup.rid = s->lookupname.out.rids->ids;
256 msg_lookup.count = s->lookupname.out.rids->count;
258 msg.type = mon_SamrLookupName;
259 msg.data = (void*)&msg_lookup;
260 msg.data_size = sizeof(msg_lookup);
261 s->monitor_fn(&msg);
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;
270 /* send rpc request */
271 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
272 s->pipe->binding_handle,
273 &s->openuser);
274 if (composite_nomem(subreq, c)) return;
276 tevent_req_set_callback(subreq, continue_userdel_user_opened, c);
281 * Stage 2: Open user account.
283 static void continue_userdel_user_opened(struct tevent_req *subreq)
285 struct composite_context *c;
286 struct userdel_state *s;
287 struct monitor_msg msg;
289 c = tevent_req_callback_data(subreq, struct composite_context);
290 s = talloc_get_type(c->private_data, struct userdel_state);
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;
297 c->status = s->openuser.out.result;
298 if (!NT_STATUS_IS_OK(c->status)) {
299 composite_error(c, c->status);
300 return;
303 /* issue a monitor message */
304 if (s->monitor_fn) {
305 struct msg_rpc_open_user msg_open;
307 msg_open.rid = s->openuser.in.rid;
308 msg_open.access_mask = s->openuser.in.access_mask;
310 msg.type = mon_SamrOpenUser;
311 msg.data = (void*)&msg_open;
312 msg.data_size = sizeof(msg_open);
313 s->monitor_fn(&msg);
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;
320 /* send rpc request */
321 subreq = dcerpc_samr_DeleteUser_r_send(s, c->event_ctx,
322 s->pipe->binding_handle,
323 &s->deleteuser);
324 if (composite_nomem(subreq, c)) return;
326 /* callback handler setup */
327 tevent_req_set_callback(subreq, continue_userdel_deleted, c);
332 * Stage 3: Delete user account
334 static void continue_userdel_deleted(struct tevent_req *subreq)
336 struct composite_context *c;
337 struct userdel_state *s;
338 struct monitor_msg msg;
340 c = tevent_req_callback_data(subreq, struct composite_context);
341 s = talloc_get_type(c->private_data, struct userdel_state);
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;
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;
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);
363 composite_done(c);
368 * Sends asynchronous userdel request
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
375 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
376 TALLOC_CTX *mem_ctx,
377 struct libnet_rpc_userdel *io,
378 void (*monitor)(struct monitor_msg*))
380 struct composite_context *c;
381 struct userdel_state *s;
382 struct tevent_req *subreq;
384 /* composite context allocation and setup */
385 c = composite_create(mem_ctx, dcerpc_event_context(p));
386 if (c == NULL) return NULL;
388 s = talloc_zero(c, struct userdel_state);
389 if (composite_nomem(s, c)) return c;
391 c->private_data = s;
393 /* store function parameters in the state structure */
394 s->pipe = p;
395 s->domain_handle = io->in.domain_handle;
396 s->monitor_fn = monitor;
398 /* preparing parameters to send rpc request */
399 s->lookupname.in.domain_handle = &io->in.domain_handle;
400 s->lookupname.in.num_names = 1;
401 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
402 s->lookupname.in.names->string = io->in.username;
403 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
404 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
405 if (composite_nomem(s->lookupname.out.rids, c)) return c;
406 if (composite_nomem(s->lookupname.out.types, c)) return c;
408 /* send the request */
409 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
410 p->binding_handle,
411 &s->lookupname);
412 if (composite_nomem(subreq, c)) return c;
414 /* set the next stage */
415 tevent_req_set_callback(subreq, continue_userdel_name_found, c);
416 return c;
421 * Waits for and receives results of asynchronous userdel call
423 * @param c composite context returned by asynchronous userdel call
424 * @param mem_ctx memory context of the call
425 * @param io pointer to results (and arguments) of the call
426 * @return nt status code of execution
429 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
430 struct libnet_rpc_userdel *io)
432 NTSTATUS status;
433 struct userdel_state *s;
435 status = composite_wait(c);
437 if (NT_STATUS_IS_OK(status) && io) {
438 s = talloc_get_type(c->private_data, struct userdel_state);
439 io->out.user_handle = s->user_handle;
442 talloc_free(c);
443 return status;
448 * Synchronous version of userdel call
450 * @param pipe dce/rpc call pipe
451 * @param mem_ctx memory context for the call
452 * @param io arguments and results of the call
453 * @return nt status code of execution
456 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
457 TALLOC_CTX *mem_ctx,
458 struct libnet_rpc_userdel *io)
460 struct composite_context *c = libnet_rpc_userdel_send(p, mem_ctx, io, NULL);
461 return libnet_rpc_userdel_recv(c, mem_ctx, io);
466 * USER MODIFY functionality
469 static void continue_usermod_name_found(struct tevent_req *subreq);
470 static void continue_usermod_user_opened(struct tevent_req *subreq);
471 static void continue_usermod_user_queried(struct tevent_req *subreq);
472 static void continue_usermod_user_changed(struct tevent_req *subreq);
475 struct usermod_state {
476 struct dcerpc_pipe *pipe;
477 struct policy_handle domain_handle;
478 struct policy_handle user_handle;
479 struct usermod_change change;
480 union samr_UserInfo info;
481 struct samr_LookupNames lookupname;
482 struct samr_OpenUser openuser;
483 struct samr_SetUserInfo setuser;
484 struct samr_QueryUserInfo queryuser;
486 /* information about the progress */
487 void (*monitor_fn)(struct monitor_msg *);
492 * Step 1: Lookup user name
494 static void continue_usermod_name_found(struct tevent_req *subreq)
496 struct composite_context *c;
497 struct usermod_state *s;
498 struct monitor_msg msg;
500 c = tevent_req_callback_data(subreq, struct composite_context);
501 s = talloc_get_type(c->private_data, struct usermod_state);
503 /* receive samr_LookupNames result */
504 c->status = dcerpc_samr_LookupNames_r_recv(subreq, s);
505 TALLOC_FREE(subreq);
506 if (!composite_is_ok(c)) return;
508 c->status = s->lookupname.out.result;
509 if (!NT_STATUS_IS_OK(c->status)) {
510 composite_error(c, c->status);
511 return;
514 /* what to do when there's no user account to delete
515 and what if there's more than one rid resolved */
516 if (!s->lookupname.out.rids->count) {
517 c->status = NT_STATUS_NO_SUCH_USER;
518 composite_error(c, c->status);
519 return;
521 } else if (!s->lookupname.out.rids->count > 1) {
522 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
523 composite_error(c, c->status);
524 return;
527 /* issue a monitor message */
528 if (s->monitor_fn) {
529 struct msg_rpc_lookup_name msg_lookup;
531 msg_lookup.rid = s->lookupname.out.rids->ids;
532 msg_lookup.count = s->lookupname.out.rids->count;
534 msg.type = mon_SamrLookupName;
535 msg.data = (void*)&msg_lookup;
536 msg.data_size = sizeof(msg_lookup);
537 s->monitor_fn(&msg);
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;
546 /* send the rpc request */
547 subreq = dcerpc_samr_OpenUser_r_send(s, c->event_ctx,
548 s->pipe->binding_handle,
549 &s->openuser);
550 if (composite_nomem(subreq, c)) return;
552 tevent_req_set_callback(subreq, continue_usermod_user_opened, c);
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.
562 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
563 union samr_UserInfo *i, bool queried)
565 if (s->change.fields == 0) return s->change.fields;
567 *level = 0;
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;
574 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
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;
582 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
585 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
586 (*level == 0 || *level == 13)) {
587 *level = 13;
588 i->info13.description.string = s->change.description;
590 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
593 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
594 (*level == 0 || *level == 2)) {
595 *level = 2;
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;
602 } else {
603 /* we need to query the user info before setting one field in it */
604 return false;
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;
613 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
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;
621 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
624 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
625 (*level == 0 || *level == 10)) {
626 *level = 10;
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;
636 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
637 (*level == 0 || *level == 10)) {
638 *level = 10;
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;
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);
653 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
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;
661 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
664 /* We're going to be here back again soon unless all fields have been set */
665 return true;
669 static NTSTATUS usermod_change(struct composite_context *c,
670 struct usermod_state *s)
672 bool do_set;
673 union samr_UserInfo *i = &s->info;
674 struct tevent_req *subreq;
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;
680 /* prepare UserInfo level and data based on bitmask field */
681 do_set = usermod_setfields(s, &level, i, false);
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;
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.
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;
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->pipe->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);
709 } else {
710 s->setuser.in.user_handle = &s->user_handle;
711 s->setuser.in.level = level;
712 s->setuser.in.info = i;
714 /* send set user info request after making required change */
715 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
716 s->pipe->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);
722 return NT_STATUS_OK;
727 * Stage 2: Open user account
729 static void continue_usermod_user_opened(struct tevent_req *subreq)
731 struct composite_context *c;
732 struct usermod_state *s;
734 c = tevent_req_callback_data(subreq, struct composite_context);
735 s = talloc_get_type(c->private_data, struct usermod_state);
737 c->status = dcerpc_samr_OpenUser_r_recv(subreq, s);
738 TALLOC_FREE(subreq);
739 if (!composite_is_ok(c)) return;
741 c->status = s->openuser.out.result;
742 if (!NT_STATUS_IS_OK(c->status)) {
743 composite_error(c, c->status);
744 return;
747 c->status = usermod_change(c, s);
752 * Stage 2a (optional): Query the user information
754 static void continue_usermod_user_queried(struct tevent_req *subreq)
756 struct composite_context *c;
757 struct usermod_state *s;
758 union samr_UserInfo *i;
759 uint16_t level;
761 c = tevent_req_callback_data(subreq, struct composite_context);
762 s = talloc_get_type(c->private_data, struct usermod_state);
764 i = &s->info;
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;
771 c->status = s->queryuser.out.result;
772 if (!NT_STATUS_IS_OK(c->status)) {
773 composite_error(c, c->status);
774 return;
777 /* get returned user data and make a change (potentially one
778 of many) */
779 s->info = *(*s->queryuser.out.info);
781 usermod_setfields(s, &level, i, true);
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;
788 /* send the rpc request */
789 subreq = dcerpc_samr_SetUserInfo_r_send(s, c->event_ctx,
790 s->pipe->binding_handle,
791 &s->setuser);
792 if (composite_nomem(subreq, c)) return;
793 tevent_req_set_callback(subreq, continue_usermod_user_changed, c);
798 * Stage 3: Set new user account data
800 static void continue_usermod_user_changed(struct tevent_req *subreq)
802 struct composite_context *c;
803 struct usermod_state *s;
805 c = tevent_req_callback_data(subreq, struct composite_context);
806 s = talloc_get_type(c->private_data, struct usermod_state);
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;
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;
820 if (s->change.fields == 0) {
821 /* all fields have been set - we're done */
822 composite_done(c);
824 } else {
825 /* something's still not changed - repeat the procedure */
826 c->status = usermod_change(c, s);
832 * Sends asynchronous usermod request
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
839 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
840 TALLOC_CTX *mem_ctx,
841 struct libnet_rpc_usermod *io,
842 void (*monitor)(struct monitor_msg*))
844 struct composite_context *c;
845 struct usermod_state *s;
846 struct tevent_req *subreq;
848 /* composite context allocation and setup */
849 c = composite_create(mem_ctx, dcerpc_event_context(p));
850 if (c == NULL) return NULL;
851 s = talloc_zero(c, struct usermod_state);
852 if (composite_nomem(s, c)) return c;
854 c->private_data = s;
856 /* store parameters in the call structure */
857 s->pipe = p;
858 s->domain_handle = io->in.domain_handle;
859 s->change = io->in.change;
860 s->monitor_fn = monitor;
862 /* prepare rpc call arguments */
863 s->lookupname.in.domain_handle = &io->in.domain_handle;
864 s->lookupname.in.num_names = 1;
865 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
866 s->lookupname.in.names->string = io->in.username;
867 s->lookupname.out.rids = talloc_zero(s, struct samr_Ids);
868 s->lookupname.out.types = talloc_zero(s, struct samr_Ids);
869 if (composite_nomem(s->lookupname.out.rids, c)) return c;
870 if (composite_nomem(s->lookupname.out.types, c)) return c;
872 /* send the rpc request */
873 subreq = dcerpc_samr_LookupNames_r_send(s, c->event_ctx,
874 p->binding_handle,
875 &s->lookupname);
876 if (composite_nomem(subreq, c)) return c;
878 /* callback handler setup */
879 tevent_req_set_callback(subreq, continue_usermod_name_found, c);
880 return c;
885 * Waits for and receives results of asynchronous usermod call
887 * @param c composite context returned by asynchronous usermod call
888 * @param mem_ctx memory context of the call
889 * @param io pointer to results (and arguments) of the call
890 * @return nt status code of execution
893 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
894 struct libnet_rpc_usermod *io)
896 NTSTATUS status;
898 status = composite_wait(c);
900 talloc_free(c);
901 return status;
906 * Synchronous version of usermod call
908 * @param pipe dce/rpc call pipe
909 * @param mem_ctx memory context for the call
910 * @param io arguments and results of the call
911 * @return nt status code of execution
914 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
915 TALLOC_CTX *mem_ctx,
916 struct libnet_rpc_usermod *io)
918 struct composite_context *c = libnet_rpc_usermod_send(p, mem_ctx, io, NULL);
919 return libnet_rpc_usermod_recv(c, mem_ctx, io);