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