~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libnet/userman.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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_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
 
 
46
static void continue_useradd_create(struct rpc_request *req);
 
47
 
 
48
 
 
49
/**
 
50
 * Stage 1 (and the only one for now): Create user account.
 
51
 */
 
52
static 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
 
 
97
struct 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
 
 
150
NTSTATUS 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
 
 
178
NTSTATUS 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
 
 
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;
 
200
 
 
201
        /* information about the progress */
 
202
        void (*monitor_fn)(struct monitor_msg *);
 
203
};
 
204
 
 
205
 
 
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);
 
209
 
 
210
 
 
211
/**
 
212
 * Stage 1: Lookup the user name and resolve it to rid
 
213
 */
 
214
static 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
 */
 
277
static 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
 */
 
326
static 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
 
 
366
struct 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
 
 
417
NTSTATUS 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
 
 
444
NTSTATUS 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
 
 
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);
 
461
 
 
462
 
 
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;
 
473
 
 
474
        /* information about the progress */
 
475
        void (*monitor_fn)(struct monitor_msg *);
 
476
};
 
477
 
 
478
 
 
479
/**
 
480
 * Step 1: Lookup user name
 
481
 */
 
482
static 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
 */
 
548
static 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
 
 
655
static 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
 */
 
709
static 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
 */
 
733
static 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
 */
 
776
static 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
 
 
814
struct 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
 
 
865
NTSTATUS 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
 
 
886
NTSTATUS 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
}