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)
25 #include "libcli/composite/composite.h"
26 #include "libnet/composite.h"
27 #include "libnet/userman.h"
28 #include "libnet/userinfo.h"
29 #include "librpc/gen_ndr/ndr_samr_c.h"
32 * Composite USER ADD functionality
35 struct useradd_state {
36 struct dcerpc_pipe *pipe;
37 struct rpc_request *req;
38 struct policy_handle domain_handle;
39 struct samr_CreateUser createuser;
40 struct policy_handle user_handle;
43 /* information about the progress */
44 void (*monitor_fn)(struct monitor_msg *);
48 static void continue_useradd_create(struct rpc_request *req);
52 * Stage 1 (and the only one for now): Create user account.
54 static void continue_useradd_create(struct rpc_request *req)
56 struct composite_context *c;
57 struct useradd_state *s;
59 c = talloc_get_type(req->async.private_data, struct composite_context);
60 s = talloc_get_type(c->private_data, struct useradd_state);
62 /* check rpc layer status code */
63 c->status = dcerpc_ndr_request_recv(s->req);
64 if (!composite_is_ok(c)) return;
66 /* check create user call status code */
67 c->status = s->createuser.out.result;
69 /* get created user account data */
70 s->user_handle = *s->createuser.out.user_handle;
71 s->user_rid = *s->createuser.out.rid;
73 /* issue a monitor message */
75 struct monitor_msg msg;
76 struct msg_rpc_create_user rpc_create;
78 rpc_create.rid = *s->createuser.out.rid;
80 msg.type = mon_SamrCreateUser;
81 msg.data = (void*)&rpc_create;
82 msg.data_size = sizeof(rpc_create);
92 * Sends asynchronous useradd request
94 * @param p dce/rpc call pipe
95 * @param io arguments and results of the call
96 * @param monitor monitor function for providing information about the progress
99 struct composite_context *libnet_rpc_useradd_send(struct dcerpc_pipe *p,
100 struct libnet_rpc_useradd *io,
101 void (*monitor)(struct monitor_msg*))
103 struct composite_context *c;
104 struct useradd_state *s;
106 if (!p || !io) return NULL;
108 /* composite allocation and setup */
109 c = composite_create(p, 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;
117 /* put passed arguments to the state structure */
118 s->domain_handle = io->in.domain_handle;
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 s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
136 if (composite_nomem(s->req, c)) return c;
138 composite_continue_rpc(c, s->req, continue_useradd_create, c);
144 * Waits for and receives result of asynchronous useradd call
146 * @param c composite context returned by asynchronous useradd call
147 * @param mem_ctx memory context of the call
148 * @param io pointer to results (and arguments) of the call
149 * @return nt status code of execution
152 NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
153 struct libnet_rpc_useradd *io)
156 struct useradd_state *s;
158 status = composite_wait(c);
160 if (NT_STATUS_IS_OK(status) && io) {
161 /* get and return result of the call */
162 s = talloc_get_type(c->private_data, struct useradd_state);
163 io->out.user_handle = s->user_handle;
172 * Synchronous version of useradd call
174 * @param pipe dce/rpc call pipe
175 * @param mem_ctx memory context for the call
176 * @param io arguments and results of the call
177 * @return nt status code of execution
180 NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
182 struct libnet_rpc_useradd *io)
184 struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
185 return libnet_rpc_useradd_recv(c, mem_ctx, io);
191 * Composite USER DELETE functionality
195 struct userdel_state {
196 struct dcerpc_pipe *pipe;
197 struct policy_handle domain_handle;
198 struct policy_handle user_handle;
199 struct samr_LookupNames lookupname;
200 struct samr_OpenUser openuser;
201 struct samr_DeleteUser deleteuser;
203 /* information about the progress */
204 void (*monitor_fn)(struct monitor_msg *);
208 static void continue_userdel_name_found(struct rpc_request *req);
209 static void continue_userdel_user_opened(struct rpc_request* req);
210 static void continue_userdel_deleted(struct rpc_request *req);
214 * Stage 1: Lookup the user name and resolve it to rid
216 static void continue_userdel_name_found(struct rpc_request *req)
218 struct composite_context *c;
219 struct userdel_state *s;
220 struct rpc_request *openuser_req;
221 struct monitor_msg msg;
223 c = talloc_get_type(req->async.private_data, struct composite_context);
224 s = talloc_get_type(c->private_data, struct userdel_state);
226 /* receive samr_LookupNames result */
227 c->status = dcerpc_ndr_request_recv(req);
228 if (!composite_is_ok(c)) return;
230 c->status = s->lookupname.out.result;
231 if (!NT_STATUS_IS_OK(c->status)) {
232 composite_error(c, c->status);
236 /* what to do when there's no user account to delete
237 and what if there's more than one rid resolved */
238 if (!s->lookupname.out.rids.count) {
239 c->status = NT_STATUS_NO_SUCH_USER;
240 composite_error(c, c->status);
243 } else if (!s->lookupname.out.rids.count > 1) {
244 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
245 composite_error(c, c->status);
249 /* issue a monitor message */
251 struct msg_rpc_lookup_name msg_lookup;
253 msg_lookup.rid = s->lookupname.out.rids.ids;
254 msg_lookup.count = s->lookupname.out.rids.count;
256 msg.type = mon_SamrLookupName;
257 msg.data = (void*)&msg_lookup;
258 msg.data_size = sizeof(msg_lookup);
262 /* prepare the arguments for rpc call */
263 s->openuser.in.domain_handle = &s->domain_handle;
264 s->openuser.in.rid = s->lookupname.out.rids.ids[0];
265 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
266 s->openuser.out.user_handle = &s->user_handle;
268 /* send rpc request */
269 openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
270 if (composite_nomem(openuser_req, c)) return;
272 composite_continue_rpc(c, openuser_req, continue_userdel_user_opened, c);
277 * Stage 2: Open user account.
279 static void continue_userdel_user_opened(struct rpc_request* req)
281 struct composite_context *c;
282 struct userdel_state *s;
283 struct rpc_request *deluser_req;
284 struct monitor_msg msg;
286 c = talloc_get_type(req->async.private_data, struct composite_context);
287 s = talloc_get_type(c->private_data, struct userdel_state);
289 /* receive samr_OpenUser result */
290 c->status = dcerpc_ndr_request_recv(req);
291 if (!composite_is_ok(c)) return;
293 c->status = s->openuser.out.result;
294 if (!NT_STATUS_IS_OK(c->status)) {
295 composite_error(c, c->status);
299 /* issue a monitor message */
301 struct msg_rpc_open_user msg_open;
303 msg_open.rid = s->openuser.in.rid;
304 msg_open.access_mask = s->openuser.in.access_mask;
306 msg.type = mon_SamrOpenUser;
307 msg.data = (void*)&msg_open;
308 msg.data_size = sizeof(msg_open);
312 /* prepare the final rpc call arguments */
313 s->deleteuser.in.user_handle = &s->user_handle;
314 s->deleteuser.out.user_handle = &s->user_handle;
316 /* send rpc request */
317 deluser_req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
318 if (composite_nomem(deluser_req, c)) return;
320 /* callback handler setup */
321 composite_continue_rpc(c, deluser_req, continue_userdel_deleted, c);
326 * Stage 3: Delete user account
328 static void continue_userdel_deleted(struct rpc_request *req)
330 struct composite_context *c;
331 struct userdel_state *s;
332 struct monitor_msg msg;
334 c = talloc_get_type(req->async.private_data, struct composite_context);
335 s = talloc_get_type(c->private_data, struct userdel_state);
337 /* receive samr_DeleteUser result */
338 c->status = dcerpc_ndr_request_recv(req);
339 if (!composite_is_ok(c)) return;
341 /* return the actual function call status */
342 c->status = s->deleteuser.out.result;
343 if (!NT_STATUS_IS_OK(c->status)) {
344 composite_error(c, c->status);
348 /* issue a monitor message */
350 msg.type = mon_SamrDeleteUser;
361 * Sends asynchronous userdel request
363 * @param p dce/rpc call pipe
364 * @param io arguments and results of the call
365 * @param monitor monitor function for providing information about the progress
368 struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
369 struct libnet_rpc_userdel *io,
370 void (*monitor)(struct monitor_msg*))
372 struct composite_context *c;
373 struct userdel_state *s;
374 struct rpc_request *lookup_req;
376 /* composite context allocation and setup */
377 c = composite_create(p, dcerpc_event_context(p));
378 if (c == NULL) return NULL;
380 s = talloc_zero(c, struct userdel_state);
381 if (composite_nomem(s, c)) return c;
385 /* store function parameters in the state structure */
387 s->domain_handle = io->in.domain_handle;
388 s->monitor_fn = monitor;
390 /* preparing parameters to send rpc request */
391 s->lookupname.in.domain_handle = &io->in.domain_handle;
392 s->lookupname.in.num_names = 1;
393 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
394 s->lookupname.in.names->string = io->in.username;
396 /* send the request */
397 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
398 if (composite_nomem(lookup_req, c)) return c;
400 /* set the next stage */
401 composite_continue_rpc(c, lookup_req, continue_userdel_name_found, c);
407 * Waits for and receives results of asynchronous userdel call
409 * @param c composite context returned by asynchronous userdel call
410 * @param mem_ctx memory context of the call
411 * @param io pointer to results (and arguments) of the call
412 * @return nt status code of execution
415 NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
416 struct libnet_rpc_userdel *io)
419 struct userdel_state *s;
421 status = composite_wait(c);
423 if (NT_STATUS_IS_OK(status) && io) {
424 s = talloc_get_type(c->private_data, struct userdel_state);
425 io->out.user_handle = s->user_handle;
434 * Synchronous version of userdel call
436 * @param pipe dce/rpc call pipe
437 * @param mem_ctx memory context for the call
438 * @param io arguments and results of the call
439 * @return nt status code of execution
442 NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
444 struct libnet_rpc_userdel *io)
446 struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
447 return libnet_rpc_userdel_recv(c, mem_ctx, io);
452 * USER MODIFY functionality
455 static void continue_usermod_name_found(struct rpc_request *req);
456 static void continue_usermod_user_opened(struct rpc_request *req);
457 static void continue_usermod_user_queried(struct rpc_request *req);
458 static void continue_usermod_user_changed(struct rpc_request *req);
461 struct usermod_state {
462 struct dcerpc_pipe *pipe;
463 struct policy_handle domain_handle;
464 struct policy_handle user_handle;
465 struct usermod_change change;
466 union samr_UserInfo info;
467 struct samr_LookupNames lookupname;
468 struct samr_OpenUser openuser;
469 struct samr_SetUserInfo setuser;
470 struct samr_QueryUserInfo queryuser;
472 /* information about the progress */
473 void (*monitor_fn)(struct monitor_msg *);
478 * Step 1: Lookup user name
480 static void continue_usermod_name_found(struct rpc_request *req)
482 struct composite_context *c;
483 struct usermod_state *s;
484 struct rpc_request *openuser_req;
485 struct monitor_msg msg;
487 c = talloc_get_type(req->async.private_data, struct composite_context);
488 s = talloc_get_type(c->private_data, struct usermod_state);
490 /* receive samr_LookupNames result */
491 c->status = dcerpc_ndr_request_recv(req);
492 if (!composite_is_ok(c)) return;
494 c->status = s->lookupname.out.result;
495 if (!NT_STATUS_IS_OK(c->status)) {
496 composite_error(c, c->status);
500 /* what to do when there's no user account to delete
501 and what if there's more than one rid resolved */
502 if (!s->lookupname.out.rids.count) {
503 c->status = NT_STATUS_NO_SUCH_USER;
504 composite_error(c, c->status);
507 } else if (!s->lookupname.out.rids.count > 1) {
508 c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
509 composite_error(c, c->status);
513 /* issue a monitor message */
515 struct msg_rpc_lookup_name msg_lookup;
517 msg_lookup.rid = s->lookupname.out.rids.ids;
518 msg_lookup.count = s->lookupname.out.rids.count;
520 msg.type = mon_SamrLookupName;
521 msg.data = (void*)&msg_lookup;
522 msg.data_size = sizeof(msg_lookup);
526 /* prepare the next rpc call */
527 s->openuser.in.domain_handle = &s->domain_handle;
528 s->openuser.in.rid = s->lookupname.out.rids.ids[0];
529 s->openuser.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
530 s->openuser.out.user_handle = &s->user_handle;
532 /* send the rpc request */
533 openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
534 if (composite_nomem(openuser_req, c)) return;
536 composite_continue_rpc(c, openuser_req, continue_usermod_user_opened, c);
541 * Choose a proper level of samr_UserInfo structure depending on required
542 * change specified by means of flags field. Subsequent calls of this
543 * function are made until there's no flags set meaning that all of the
544 * changes have been made.
546 static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
547 union samr_UserInfo *i, bool queried)
549 if (s->change.fields == 0) return s->change.fields;
553 if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
554 (*level == 0 || *level == 7)) {
556 i->info7.account_name.string = s->change.account_name;
558 s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
561 if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
562 (*level == 0 || *level == 8)) {
564 i->info8.full_name.string = s->change.full_name;
566 s->change.fields ^= USERMOD_FIELD_FULL_NAME;
569 if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
570 (*level == 0 || *level == 13)) {
572 i->info13.description.string = s->change.description;
574 s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
577 if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
578 (*level == 0 || *level == 2)) {
582 /* the user info is obtained, so now set the required field */
583 i->info2.comment.string = s->change.comment;
584 s->change.fields ^= USERMOD_FIELD_COMMENT;
587 /* we need to query the user info before setting one field in it */
592 if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
593 (*level == 0 || *level == 11)) {
595 i->info11.logon_script.string = s->change.logon_script;
597 s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
600 if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
601 (*level == 0 || *level == 12)) {
603 i->info12.profile_path.string = s->change.profile_path;
605 s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
608 if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
609 (*level == 0 || *level == 10)) {
613 i->info10.home_directory.string = s->change.home_directory;
614 s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
620 if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
621 (*level == 0 || *level == 10)) {
625 i->info10.home_drive.string = s->change.home_drive;
626 s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
632 if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
633 (*level == 0 || *level == 17)) {
635 i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
637 s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
640 if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
641 (*level == 0 || *level == 16)) {
643 i->info16.acct_flags = s->change.acct_flags;
645 s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
648 /* We're going to be here back again soon unless all fields have been set */
653 static NTSTATUS usermod_change(struct composite_context *c,
654 struct usermod_state *s)
656 struct rpc_request *query_req, *setuser_req;
658 union samr_UserInfo *i = &s->info;
660 /* set the level to invalid value, so that unless setfields routine
661 gives it a valid value we report the error correctly */
664 /* prepare UserInfo level and data based on bitmask field */
665 do_set = usermod_setfields(s, &level, i, false);
667 if (level < 1 || level > 26) {
668 /* apparently there's a field that the setfields routine
669 does not know how to set */
670 return NT_STATUS_INVALID_PARAMETER;
673 /* If some specific level is used to set user account data and the change
674 itself does not cover all fields then we need to query the user info
675 first, right before changing the data. Otherwise we could set required
676 fields and accidentally reset the others.
679 s->queryuser.in.user_handle = &s->user_handle;
680 s->queryuser.in.level = level;
682 /* send query user info request to retrieve complete data of
683 a particular info level */
684 query_req = dcerpc_samr_QueryUserInfo_send(s->pipe, c, &s->queryuser);
685 composite_continue_rpc(c, query_req, continue_usermod_user_queried, c);
688 s->setuser.in.user_handle = &s->user_handle;
689 s->setuser.in.level = level;
690 s->setuser.in.info = i;
692 /* send set user info request after making required change */
693 setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
694 composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
702 * Stage 2: Open user account
704 static void continue_usermod_user_opened(struct rpc_request *req)
706 struct composite_context *c;
707 struct usermod_state *s;
709 c = talloc_get_type(req->async.private_data, struct composite_context);
710 s = talloc_get_type(c->private_data, struct usermod_state);
712 c->status = dcerpc_ndr_request_recv(req);
713 if (!composite_is_ok(c)) return;
715 c->status = s->openuser.out.result;
716 if (!NT_STATUS_IS_OK(c->status)) {
717 composite_error(c, c->status);
721 c->status = usermod_change(c, s);
726 * Stage 2a (optional): Query the user information
728 static void continue_usermod_user_queried(struct rpc_request *req)
730 struct composite_context *c;
731 struct usermod_state *s;
732 union samr_UserInfo *i;
734 struct rpc_request *setuser_req;
736 c = talloc_get_type(req->async.private_data, struct composite_context);
737 s = talloc_get_type(c->private_data, struct usermod_state);
741 /* receive samr_QueryUserInfo result */
742 c->status = dcerpc_ndr_request_recv(req);
743 if (!composite_is_ok(c)) return;
745 c->status = s->queryuser.out.result;
746 if (!NT_STATUS_IS_OK(c->status)) {
747 composite_error(c, c->status);
751 /* get returned user data and make a change (potentially one
753 s->info = *s->queryuser.out.info;
755 usermod_setfields(s, &level, i, true);
757 /* prepare rpc call arguments */
758 s->setuser.in.user_handle = &s->user_handle;
759 s->setuser.in.level = level;
760 s->setuser.in.info = i;
762 /* send the rpc request */
763 setuser_req = dcerpc_samr_SetUserInfo_send(s->pipe, c, &s->setuser);
764 composite_continue_rpc(c, setuser_req, continue_usermod_user_changed, c);
769 * Stage 3: Set new user account data
771 static void continue_usermod_user_changed(struct rpc_request *req)
773 struct composite_context *c;
774 struct usermod_state *s;
776 c = talloc_get_type(req->async.private_data, struct composite_context);
777 s = talloc_get_type(c->private_data, struct usermod_state);
779 /* receive samr_SetUserInfo result */
780 c->status = dcerpc_ndr_request_recv(req);
781 if (!composite_is_ok(c)) return;
783 /* return the actual function call status */
784 c->status = s->setuser.out.result;
785 if (!NT_STATUS_IS_OK(c->status)) {
786 composite_error(c, c->status);
790 if (s->change.fields == 0) {
791 /* all fields have been set - we're done */
795 /* something's still not changed - repeat the procedure */
796 c->status = usermod_change(c, s);
802 * Sends asynchronous usermod request
804 * @param p dce/rpc call pipe
805 * @param io arguments and results of the call
806 * @param monitor monitor function for providing information about the progress
809 struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
810 struct libnet_rpc_usermod *io,
811 void (*monitor)(struct monitor_msg*))
813 struct composite_context *c;
814 struct usermod_state *s;
815 struct rpc_request *lookup_req;
817 /* composite context allocation and setup */
818 c = composite_create(p, dcerpc_event_context(p));
819 if (c == NULL) return NULL;
820 s = talloc_zero(c, struct usermod_state);
821 if (composite_nomem(s, c)) return c;
825 /* store parameters in the call structure */
827 s->domain_handle = io->in.domain_handle;
828 s->change = io->in.change;
829 s->monitor_fn = monitor;
831 /* prepare rpc call arguments */
832 s->lookupname.in.domain_handle = &io->in.domain_handle;
833 s->lookupname.in.num_names = 1;
834 s->lookupname.in.names = talloc_zero(s, struct lsa_String);
835 s->lookupname.in.names->string = io->in.username;
837 /* send the rpc request */
838 lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
839 if (composite_nomem(lookup_req, c)) return c;
841 /* callback handler setup */
842 composite_continue_rpc(c, lookup_req, continue_usermod_name_found, c);
848 * Waits for and receives results of asynchronous usermod call
850 * @param c composite context returned by asynchronous usermod call
851 * @param mem_ctx memory context of the call
852 * @param io pointer to results (and arguments) of the call
853 * @return nt status code of execution
856 NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
857 struct libnet_rpc_usermod *io)
861 status = composite_wait(c);
869 * Synchronous version of usermod call
871 * @param pipe dce/rpc call pipe
872 * @param mem_ctx memory context for the call
873 * @param io arguments and results of the call
874 * @return nt status code of execution
877 NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
879 struct libnet_rpc_usermod *io)
881 struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
882 return libnet_rpc_usermod_recv(c, mem_ctx, io);