source: branches/samba-3.5.x/source4/libnet/userman.c@ 836

Last change on this file since 836 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 24.1 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Copyright (C) Rafal Szczesniak 2005
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/*
21 a composite functions for user management operations (add/del/chg)
22*/
23
24#include "includes.h"
25#include "libcli/composite/composite.h"
26#include "libnet/libnet.h"
27#include "librpc/gen_ndr/ndr_samr_c.h"
28
29/*
30 * Composite USER ADD functionality
31 */
32
33struct useradd_state {
34 struct dcerpc_pipe *pipe;
35 struct 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}
Note: See TracBrowser for help on using the repository browser.