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/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 rpc_request *req;
36
struct policy_handle domain_handle;
37
struct samr_CreateUser createuser;
38
struct policy_handle user_handle;
41
/* information about the progress */
42
void (*monitor_fn)(struct monitor_msg *);
46
static void continue_useradd_create(struct rpc_request *req);
50
* Stage 1 (and the only one for now): Create user account.
52
static void continue_useradd_create(struct rpc_request *req)
54
struct composite_context *c;
55
struct useradd_state *s;
57
c = talloc_get_type(req->async.private_data, struct composite_context);
58
s = talloc_get_type(c->private_data, struct useradd_state);
60
/* check rpc layer status code */
61
c->status = dcerpc_ndr_request_recv(s->req);
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 */
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);
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
struct libnet_rpc_useradd *io,
99
void (*monitor)(struct monitor_msg*))
101
struct composite_context *c;
102
struct useradd_state *s;
104
if (!p || !io) return NULL;
106
/* composite allocation and setup */
107
c = composite_create(p, dcerpc_event_context(p));
108
if (c == NULL) return NULL;
110
s = talloc_zero(c, struct useradd_state);
111
if (composite_nomem(s, c)) return c;
115
/* put passed arguments to the state structure */
116
s->domain_handle = io->in.domain_handle;
118
s->monitor_fn = monitor;
120
/* preparing parameters to send rpc request */
121
s->createuser.in.domain_handle = &io->in.domain_handle;
123
s->createuser.in.account_name = talloc_zero(c, struct lsa_String);
124
if (composite_nomem(s->createuser.in.account_name, c)) return c;
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;
129
s->createuser.out.user_handle = &s->user_handle;
130
s->createuser.out.rid = &s->user_rid;
132
/* send the request */
133
s->req = dcerpc_samr_CreateUser_send(p, c, &s->createuser);
134
if (composite_nomem(s->req, c)) return c;
136
composite_continue_rpc(c, s->req, continue_useradd_create, c);
142
* Waits for and receives result of asynchronous useradd call
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
150
NTSTATUS libnet_rpc_useradd_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
151
struct libnet_rpc_useradd *io)
154
struct useradd_state *s;
156
status = composite_wait(c);
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;
170
* Synchronous version of useradd call
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
178
NTSTATUS libnet_rpc_useradd(struct dcerpc_pipe *p,
180
struct libnet_rpc_useradd *io)
182
struct composite_context *c = libnet_rpc_useradd_send(p, io, NULL);
183
return libnet_rpc_useradd_recv(c, mem_ctx, io);
189
* Composite USER DELETE functionality
193
struct 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;
201
/* information about the progress */
202
void (*monitor_fn)(struct monitor_msg *);
206
static void continue_userdel_name_found(struct rpc_request *req);
207
static void continue_userdel_user_opened(struct rpc_request* req);
208
static void continue_userdel_deleted(struct rpc_request *req);
212
* Stage 1: Lookup the user name and resolve it to rid
214
static void continue_userdel_name_found(struct rpc_request *req)
216
struct composite_context *c;
217
struct userdel_state *s;
218
struct rpc_request *openuser_req;
219
struct monitor_msg msg;
221
c = talloc_get_type(req->async.private_data, struct composite_context);
222
s = talloc_get_type(c->private_data, struct userdel_state);
224
/* receive samr_LookupNames result */
225
c->status = dcerpc_ndr_request_recv(req);
226
if (!composite_is_ok(c)) return;
228
c->status = s->lookupname.out.result;
229
if (!NT_STATUS_IS_OK(c->status)) {
230
composite_error(c, c->status);
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);
241
} else if (!s->lookupname.out.rids->count > 1) {
242
c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
243
composite_error(c, c->status);
247
/* issue a monitor message */
249
struct msg_rpc_lookup_name msg_lookup;
251
msg_lookup.rid = s->lookupname.out.rids->ids;
252
msg_lookup.count = s->lookupname.out.rids->count;
254
msg.type = mon_SamrLookupName;
255
msg.data = (void*)&msg_lookup;
256
msg.data_size = sizeof(msg_lookup);
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;
266
/* send rpc request */
267
openuser_req = dcerpc_samr_OpenUser_send(s->pipe, c, &s->openuser);
268
if (composite_nomem(openuser_req, c)) return;
270
composite_continue_rpc(c, openuser_req, continue_userdel_user_opened, c);
275
* Stage 2: Open user account.
277
static void continue_userdel_user_opened(struct rpc_request* req)
279
struct composite_context *c;
280
struct userdel_state *s;
281
struct rpc_request *deluser_req;
282
struct monitor_msg msg;
284
c = talloc_get_type(req->async.private_data, struct composite_context);
285
s = talloc_get_type(c->private_data, struct userdel_state);
287
/* receive samr_OpenUser result */
288
c->status = dcerpc_ndr_request_recv(req);
289
if (!composite_is_ok(c)) return;
291
c->status = s->openuser.out.result;
292
if (!NT_STATUS_IS_OK(c->status)) {
293
composite_error(c, c->status);
297
/* issue a monitor message */
299
struct msg_rpc_open_user msg_open;
301
msg_open.rid = s->openuser.in.rid;
302
msg_open.access_mask = s->openuser.in.access_mask;
304
msg.type = mon_SamrOpenUser;
305
msg.data = (void*)&msg_open;
306
msg.data_size = sizeof(msg_open);
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;
314
/* send rpc request */
315
deluser_req = dcerpc_samr_DeleteUser_send(s->pipe, c, &s->deleteuser);
316
if (composite_nomem(deluser_req, c)) return;
318
/* callback handler setup */
319
composite_continue_rpc(c, deluser_req, continue_userdel_deleted, c);
324
* Stage 3: Delete user account
326
static void continue_userdel_deleted(struct rpc_request *req)
328
struct composite_context *c;
329
struct userdel_state *s;
330
struct monitor_msg msg;
332
c = talloc_get_type(req->async.private_data, struct composite_context);
333
s = talloc_get_type(c->private_data, struct userdel_state);
335
/* receive samr_DeleteUser result */
336
c->status = dcerpc_ndr_request_recv(req);
337
if (!composite_is_ok(c)) return;
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);
346
/* issue a monitor message */
348
msg.type = mon_SamrDeleteUser;
359
* Sends asynchronous userdel request
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
366
struct composite_context *libnet_rpc_userdel_send(struct dcerpc_pipe *p,
367
struct libnet_rpc_userdel *io,
368
void (*monitor)(struct monitor_msg*))
370
struct composite_context *c;
371
struct userdel_state *s;
372
struct rpc_request *lookup_req;
374
/* composite context allocation and setup */
375
c = composite_create(p, dcerpc_event_context(p));
376
if (c == NULL) return NULL;
378
s = talloc_zero(c, struct userdel_state);
379
if (composite_nomem(s, c)) return c;
383
/* store function parameters in the state structure */
385
s->domain_handle = io->in.domain_handle;
386
s->monitor_fn = monitor;
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;
398
/* send the request */
399
lookup_req = dcerpc_samr_LookupNames_send(p, c, &s->lookupname);
400
if (composite_nomem(lookup_req, c)) return c;
402
/* set the next stage */
403
composite_continue_rpc(c, lookup_req, continue_userdel_name_found, c);
409
* Waits for and receives results of asynchronous userdel call
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
417
NTSTATUS libnet_rpc_userdel_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
418
struct libnet_rpc_userdel *io)
421
struct userdel_state *s;
423
status = composite_wait(c);
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;
436
* Synchronous version of userdel call
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
444
NTSTATUS libnet_rpc_userdel(struct dcerpc_pipe *p,
446
struct libnet_rpc_userdel *io)
448
struct composite_context *c = libnet_rpc_userdel_send(p, io, NULL);
449
return libnet_rpc_userdel_recv(c, mem_ctx, io);
454
* USER MODIFY functionality
457
static void continue_usermod_name_found(struct rpc_request *req);
458
static void continue_usermod_user_opened(struct rpc_request *req);
459
static void continue_usermod_user_queried(struct rpc_request *req);
460
static void continue_usermod_user_changed(struct rpc_request *req);
463
struct 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;
474
/* information about the progress */
475
void (*monitor_fn)(struct monitor_msg *);
480
* Step 1: Lookup user name
482
static void continue_usermod_name_found(struct rpc_request *req)
484
struct composite_context *c;
485
struct usermod_state *s;
486
struct rpc_request *openuser_req;
487
struct monitor_msg msg;
489
c = talloc_get_type(req->async.private_data, struct composite_context);
490
s = talloc_get_type(c->private_data, struct usermod_state);
492
/* receive samr_LookupNames result */
493
c->status = dcerpc_ndr_request_recv(req);
494
if (!composite_is_ok(c)) return;
496
c->status = s->lookupname.out.result;
497
if (!NT_STATUS_IS_OK(c->status)) {
498
composite_error(c, c->status);
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);
509
} else if (!s->lookupname.out.rids->count > 1) {
510
c->status = NT_STATUS_INVALID_ACCOUNT_NAME;
511
composite_error(c, c->status);
515
/* issue a monitor message */
517
struct msg_rpc_lookup_name msg_lookup;
519
msg_lookup.rid = s->lookupname.out.rids->ids;
520
msg_lookup.count = s->lookupname.out.rids->count;
522
msg.type = mon_SamrLookupName;
523
msg.data = (void*)&msg_lookup;
524
msg.data_size = sizeof(msg_lookup);
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;
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;
538
composite_continue_rpc(c, openuser_req, continue_usermod_user_opened, c);
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.
548
static bool usermod_setfields(struct usermod_state *s, uint16_t *level,
549
union samr_UserInfo *i, bool queried)
551
if (s->change.fields == 0) return s->change.fields;
555
if ((s->change.fields & USERMOD_FIELD_ACCOUNT_NAME) &&
556
(*level == 0 || *level == 7)) {
558
i->info7.account_name.string = s->change.account_name;
560
s->change.fields ^= USERMOD_FIELD_ACCOUNT_NAME;
563
if ((s->change.fields & USERMOD_FIELD_FULL_NAME) &&
564
(*level == 0 || *level == 8)) {
566
i->info8.full_name.string = s->change.full_name;
568
s->change.fields ^= USERMOD_FIELD_FULL_NAME;
571
if ((s->change.fields & USERMOD_FIELD_DESCRIPTION) &&
572
(*level == 0 || *level == 13)) {
574
i->info13.description.string = s->change.description;
576
s->change.fields ^= USERMOD_FIELD_DESCRIPTION;
579
if ((s->change.fields & USERMOD_FIELD_COMMENT) &&
580
(*level == 0 || *level == 2)) {
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;
589
/* we need to query the user info before setting one field in it */
594
if ((s->change.fields & USERMOD_FIELD_LOGON_SCRIPT) &&
595
(*level == 0 || *level == 11)) {
597
i->info11.logon_script.string = s->change.logon_script;
599
s->change.fields ^= USERMOD_FIELD_LOGON_SCRIPT;
602
if ((s->change.fields & USERMOD_FIELD_PROFILE_PATH) &&
603
(*level == 0 || *level == 12)) {
605
i->info12.profile_path.string = s->change.profile_path;
607
s->change.fields ^= USERMOD_FIELD_PROFILE_PATH;
610
if ((s->change.fields & USERMOD_FIELD_HOME_DIRECTORY) &&
611
(*level == 0 || *level == 10)) {
615
i->info10.home_directory.string = s->change.home_directory;
616
s->change.fields ^= USERMOD_FIELD_HOME_DIRECTORY;
622
if ((s->change.fields & USERMOD_FIELD_HOME_DRIVE) &&
623
(*level == 0 || *level == 10)) {
627
i->info10.home_drive.string = s->change.home_drive;
628
s->change.fields ^= USERMOD_FIELD_HOME_DRIVE;
634
if ((s->change.fields & USERMOD_FIELD_ACCT_EXPIRY) &&
635
(*level == 0 || *level == 17)) {
637
i->info17.acct_expiry = timeval_to_nttime(s->change.acct_expiry);
639
s->change.fields ^= USERMOD_FIELD_ACCT_EXPIRY;
642
if ((s->change.fields & USERMOD_FIELD_ACCT_FLAGS) &&
643
(*level == 0 || *level == 16)) {
645
i->info16.acct_flags = s->change.acct_flags;
647
s->change.fields ^= USERMOD_FIELD_ACCT_FLAGS;
650
/* We're going to be here back again soon unless all fields have been set */
655
static NTSTATUS usermod_change(struct composite_context *c,
656
struct usermod_state *s)
658
struct rpc_request *query_req, *setuser_req;
660
union samr_UserInfo *i = &s->info;
662
/* set the level to invalid value, so that unless setfields routine
663
gives it a valid value we report the error correctly */
666
/* prepare UserInfo level and data based on bitmask field */
667
do_set = usermod_setfields(s, &level, i, false);
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;
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.
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;
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);
693
s->setuser.in.user_handle = &s->user_handle;
694
s->setuser.in.level = level;
695
s->setuser.in.info = i;
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);
707
* Stage 2: Open user account
709
static void continue_usermod_user_opened(struct rpc_request *req)
711
struct composite_context *c;
712
struct usermod_state *s;
714
c = talloc_get_type(req->async.private_data, struct composite_context);
715
s = talloc_get_type(c->private_data, struct usermod_state);
717
c->status = dcerpc_ndr_request_recv(req);
718
if (!composite_is_ok(c)) return;
720
c->status = s->openuser.out.result;
721
if (!NT_STATUS_IS_OK(c->status)) {
722
composite_error(c, c->status);
726
c->status = usermod_change(c, s);
731
* Stage 2a (optional): Query the user information
733
static void continue_usermod_user_queried(struct rpc_request *req)
735
struct composite_context *c;
736
struct usermod_state *s;
737
union samr_UserInfo *i;
739
struct rpc_request *setuser_req;
741
c = talloc_get_type(req->async.private_data, struct composite_context);
742
s = talloc_get_type(c->private_data, struct usermod_state);
746
/* receive samr_QueryUserInfo result */
747
c->status = dcerpc_ndr_request_recv(req);
748
if (!composite_is_ok(c)) return;
750
c->status = s->queryuser.out.result;
751
if (!NT_STATUS_IS_OK(c->status)) {
752
composite_error(c, c->status);
756
/* get returned user data and make a change (potentially one
758
s->info = *(*s->queryuser.out.info);
760
usermod_setfields(s, &level, i, true);
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;
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);
774
* Stage 3: Set new user account data
776
static void continue_usermod_user_changed(struct rpc_request *req)
778
struct composite_context *c;
779
struct usermod_state *s;
781
c = talloc_get_type(req->async.private_data, struct composite_context);
782
s = talloc_get_type(c->private_data, struct usermod_state);
784
/* receive samr_SetUserInfo result */
785
c->status = dcerpc_ndr_request_recv(req);
786
if (!composite_is_ok(c)) return;
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);
795
if (s->change.fields == 0) {
796
/* all fields have been set - we're done */
800
/* something's still not changed - repeat the procedure */
801
c->status = usermod_change(c, s);
807
* Sends asynchronous usermod request
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
814
struct composite_context *libnet_rpc_usermod_send(struct dcerpc_pipe *p,
815
struct libnet_rpc_usermod *io,
816
void (*monitor)(struct monitor_msg*))
818
struct composite_context *c;
819
struct usermod_state *s;
820
struct rpc_request *lookup_req;
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;
830
/* store parameters in the call structure */
832
s->domain_handle = io->in.domain_handle;
833
s->change = io->in.change;
834
s->monitor_fn = monitor;
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;
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;
850
/* callback handler setup */
851
composite_continue_rpc(c, lookup_req, continue_usermod_name_found, c);
857
* Waits for and receives results of asynchronous usermod call
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
865
NTSTATUS libnet_rpc_usermod_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
866
struct libnet_rpc_usermod *io)
870
status = composite_wait(c);
878
* Synchronous version of usermod call
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
886
NTSTATUS libnet_rpc_usermod(struct dcerpc_pipe *p,
888
struct libnet_rpc_usermod *io)
890
struct composite_context *c = libnet_rpc_usermod_send(p, io, NULL);
891
return libnet_rpc_usermod_recv(c, mem_ctx, io);