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