r17484: Make last version of the function generating random set of changes
[abartlet/samba.git/.git] / source4 / torture / libnet / libnet_user.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Test suite for libnet calls.
4
5    Copyright (C) Rafal Szczesniak 2005
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "system/time.h"
24 #include "lib/cmdline/popt_common.h"
25 #include "libnet/libnet.h"
26 #include "librpc/gen_ndr/ndr_samr_c.h"
27 #include "torture/torture.h"
28 #include "torture/rpc/rpc.h"
29
30
31 #define TEST_USERNAME        "libnetusertest"
32
33 static BOOL test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
34                          struct policy_handle *domain_handle, const char *username)
35 {
36         NTSTATUS status;
37         struct samr_LookupNames r1;
38         struct samr_OpenUser r2;
39         struct samr_DeleteUser r3;
40         struct samr_Close r4;
41         struct lsa_String names[2];
42         uint32_t rid;
43         struct policy_handle user_handle;
44
45         names[0].string = username;
46
47         r1.in.domain_handle  = domain_handle;
48         r1.in.num_names      = 1;
49         r1.in.names          = names;
50         
51         printf("user account lookup '%s'\n", username);
52
53         status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
54         if (!NT_STATUS_IS_OK(status)) {
55                 printf("LookupNames failed - %s\n", nt_errstr(status));
56                 return False;
57         }
58
59         rid = r1.out.rids.ids[0];
60         
61         r2.in.domain_handle  = domain_handle;
62         r2.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
63         r2.in.rid            = rid;
64         r2.out.user_handle   = &user_handle;
65
66         printf("opening user account\n");
67
68         status = dcerpc_samr_OpenUser(p, mem_ctx, &r2);
69         if (!NT_STATUS_IS_OK(status)) {
70                 printf("OpenUser failed - %s\n", nt_errstr(status));
71                 return False;
72         }
73
74         r3.in.user_handle  = &user_handle;
75         r3.out.user_handle = &user_handle;
76
77         printf("deleting user account\n");
78         
79         status = dcerpc_samr_DeleteUser(p, mem_ctx, &r3);
80         if (!NT_STATUS_IS_OK(status)) {
81                 printf("DeleteUser failed - %s\n", nt_errstr(status));
82                 return False;
83         }
84
85         r4.in.handle = domain_handle;
86         r4.out.handle = domain_handle;
87
88         status = dcerpc_samr_Close(p, mem_ctx, &r4);
89         if (!NT_STATUS_IS_OK(status)) {
90                 printf("Close failed - %s\n", nt_errstr(status));
91                 return False;
92         }
93         
94         return True;
95 }
96
97
98 static BOOL test_opendomain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
99                             struct policy_handle *handle, struct lsa_String *domname)
100 {
101         NTSTATUS status;
102         struct policy_handle h, domain_handle;
103         struct samr_Connect r1;
104         struct samr_LookupDomain r2;
105         struct samr_OpenDomain r3;
106         
107         printf("connecting\n");
108         
109         r1.in.system_name = 0;
110         r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
111         r1.out.connect_handle = &h;
112         
113         status = dcerpc_samr_Connect(p, mem_ctx, &r1);
114         if (!NT_STATUS_IS_OK(status)) {
115                 printf("Connect failed - %s\n", nt_errstr(status));
116                 return False;
117         }
118         
119         r2.in.connect_handle = &h;
120         r2.in.domain_name = domname;
121
122         printf("domain lookup on %s\n", domname->string);
123
124         status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
125         if (!NT_STATUS_IS_OK(status)) {
126                 printf("LookupDomain failed - %s\n", nt_errstr(status));
127                 return False;
128         }
129
130         r3.in.connect_handle = &h;
131         r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
132         r3.in.sid = r2.out.sid;
133         r3.out.domain_handle = &domain_handle;
134
135         printf("opening domain\n");
136
137         status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
138         if (!NT_STATUS_IS_OK(status)) {
139                 printf("OpenDomain failed - %s\n", nt_errstr(status));
140                 return False;
141         } else {
142                 *handle = domain_handle;
143         }
144
145         return True;
146 }
147
148
149 static BOOL test_createuser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
150                             struct policy_handle *handle, const char* user)
151 {
152         NTSTATUS status;
153         struct policy_handle user_handle;
154         struct lsa_String username;
155         struct samr_CreateUser r1;
156         struct samr_Close r2;
157         uint32_t user_rid;
158
159         username.string = user;
160         
161         r1.in.domain_handle = handle;
162         r1.in.account_name = &username;
163         r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
164         r1.out.user_handle = &user_handle;
165         r1.out.rid = &user_rid;
166
167         printf("creating user '%s'\n", username.string);
168         
169         status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
170         if (!NT_STATUS_IS_OK(status)) {
171                 printf("CreateUser failed - %s\n", nt_errstr(status));
172
173                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
174                         printf("User (%s) already exists - attempting to delete and recreate account again\n", user);
175                         if (!test_cleanup(p, mem_ctx, handle, TEST_USERNAME)) {
176                                 return False;
177                         }
178
179                         printf("creating user account\n");
180                         
181                         status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
182                         if (!NT_STATUS_IS_OK(status)) {
183                                 printf("CreateUser failed - %s\n", nt_errstr(status));
184                                 return False;
185                         }
186                         return True;
187                 }               
188                 return False;
189         }
190
191         r2.in.handle = &user_handle;
192         r2.out.handle = &user_handle;
193         
194         printf("closing user '%s'\n", username.string);
195
196         status = dcerpc_samr_Close(p, mem_ctx, &r2);
197         if (!NT_STATUS_IS_OK(status)) {
198                 printf("Close failed - %s\n", nt_errstr(status));
199                 return False;
200         }
201
202         return True;
203 }
204
205
206 BOOL torture_createuser(struct torture_context *torture)
207 {
208         NTSTATUS status;
209         const char *binding;
210         TALLOC_CTX *mem_ctx;
211         struct libnet_context *ctx;
212         struct libnet_CreateUser req;
213
214         mem_ctx = talloc_init("test_createuser");
215         binding = lp_parm_string(-1, "torture", "binding");
216
217         ctx = libnet_context_init(NULL);
218         ctx->cred = cmdline_credentials;
219
220         req.in.user_name = TEST_USERNAME;
221         req.in.domain_name = lp_workgroup();
222         req.out.error_string = NULL;
223
224         status = libnet_CreateUser(ctx, mem_ctx, &req);
225         if (!NT_STATUS_IS_OK(status)) {
226                 printf("libnet_CreateUser call failed: %s\n", nt_errstr(status));
227                 return False;
228         }
229
230         if (!test_cleanup(ctx->samr_pipe, mem_ctx, &ctx->domain.handle, TEST_USERNAME)) {
231                 printf("cleanup failed\n");
232                 return False;
233         }
234
235         return True;
236 }
237
238
239 BOOL torture_deleteuser(struct torture_context *torture)
240 {
241         NTSTATUS status;
242         const char *binding;
243         struct dcerpc_pipe *p;
244         TALLOC_CTX *prep_mem_ctx, *mem_ctx;
245         struct policy_handle h;
246         struct lsa_String domain_name;
247         const char *name = TEST_USERNAME;
248         struct libnet_context *ctx;
249         struct libnet_DeleteUser req;
250         BOOL ret = True;
251
252         prep_mem_ctx = talloc_init("prepare test_deleteuser");
253         binding = lp_parm_string(-1, "torture", "binding");
254
255         ctx = libnet_context_init(NULL);
256         ctx->cred = cmdline_credentials;
257
258         req.in.user_name = TEST_USERNAME;
259         req.in.domain_name = lp_workgroup();
260
261         status = torture_rpc_connection(prep_mem_ctx,
262                                         &p,
263                                         &dcerpc_table_samr);
264         if (!NT_STATUS_IS_OK(status)) {
265                 return False;
266         }
267
268         domain_name.string = lp_workgroup();
269         if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
270                 ret = False;
271                 goto done;
272         }
273
274         if (!test_createuser(p, prep_mem_ctx, &h, name)) {
275                 ret = False;
276                 goto done;
277         }
278
279         mem_ctx = talloc_init("test_deleteuser");
280
281         status = libnet_DeleteUser(ctx, mem_ctx, &req);
282         if (!NT_STATUS_IS_OK(status)) {
283                 printf("libnet_DeleteUser call failed: %s\n", nt_errstr(status));
284                 return False;
285         }
286
287 done:
288         talloc_free(prep_mem_ctx);
289         talloc_free(mem_ctx);
290         return ret;
291 }
292
293
294 /*
295   Generate testing set of random changes
296 */
297
298 #define TEST_CHG_ACCOUNTNAME   "newlibnetusertest%02d"
299 #define TEST_CHG_DESCRIPTION   "Sample description %ld"
300 #define TEST_CHG_FULLNAME      "First%04x Last%04x"
301 #define TEST_CHG_COMMENT       "Comment[%04lu%04lu]"
302 #define TEST_CHG_PROFILEPATH   "\\\\srv%04ld\\profile%02u\\prof"
303
304 #define continue_if_field_set(field) \
305         if (field != 0) { \
306                 i--; \
307                 continue; \
308         }
309
310 void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r, int num_changes)
311 {
312         enum fields { account_name = 0, full_name, description, home_directory, home_drive,
313                       comment, logon_script, profile_path, acct_expiry, allow_password_change,
314                       force_password_change, last_logon, last_logoff, last_password_change };
315         const int num_fields = 14;
316
317         const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
318         const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
319         const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
320         const char *homedir, *homedrive, *logonscript;
321         struct timeval now;
322         int i, randval;
323
324         srandom((unsigned)time(NULL));
325
326         printf("Fields to change: [");
327
328         for (i = 0; i < num_changes && i < num_fields; i++) {
329                 const char *fldname;
330                 randval = random() % num_fields;
331
332                 /* get one in case we hit time field this time */
333                 gettimeofday(&now, NULL);
334                 
335                 switch (randval) {
336                 case account_name:
337                         continue_if_field_set(r->in.account_name);
338                         r->in.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
339                                                              (int)random());
340                         fldname = "account_name";
341                         break;
342
343                 case full_name:
344                         continue_if_field_set(r->in.full_name);
345                         r->in.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
346                                                           (unsigned int)random(), (unsigned int)random());
347                         fldname = "full_name";
348                         break;
349
350                 case description:
351                         continue_if_field_set(r->in.description);
352                         r->in.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
353                                                             (long)random());
354                         fldname = "description";
355                         break;
356
357                 case home_directory:
358                         continue_if_field_set(r->in.home_directory);
359                         homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))];
360                         r->in.home_directory = talloc_strdup(mem_ctx, homedir);
361                         fldname = "home_dir";
362                         break;
363
364                 case home_drive:
365                         continue_if_field_set(r->in.home_drive);
366                         homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))];
367                         r->in.home_drive = talloc_strdup(mem_ctx, homedrive);
368                         fldname = "home_drive";
369                         break;
370
371                 case comment:
372                         continue_if_field_set(r->in.comment);
373                         r->in.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
374                                                         (unsigned long)random(), (unsigned long)random());
375                         fldname = "comment";
376                         break;
377
378                 case logon_script:
379                         continue_if_field_set(r->in.logon_script);
380                         logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))];
381                         r->in.logon_script = talloc_strdup(mem_ctx, logonscript);
382                         fldname = "logon_script";
383                         break;
384                         
385                 case profile_path:
386                         continue_if_field_set(r->in.profile_path);
387                         r->in.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
388                                                              (unsigned long)random(), (unsigned int)random());
389                         fldname = "profile_path";
390                         break;
391
392                 case acct_expiry:
393                         continue_if_field_set(r->in.acct_expiry);
394                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
395                         r->in.acct_expiry = talloc_memdup(mem_ctx, &now, sizeof(now));
396                         fldname = "acct_expiry";
397                         break;
398
399                 case allow_password_change:
400                         continue_if_field_set(r->in.allow_password_change);
401                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
402                         r->in.allow_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
403                         fldname = "allow_password_change";
404                         break;
405
406                 case force_password_change:
407                         continue_if_field_set(r->in.force_password_change);
408                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
409                         r->in.force_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
410                         fldname = "force_password_change";
411                         break;
412
413                 case last_logon:
414                         continue_if_field_set(r->in.last_logon);
415                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
416                         r->in.last_logon = talloc_memdup(mem_ctx, &now, sizeof(now));
417                         fldname = "last_logon";
418                         break;
419
420                 case last_logoff:
421                         continue_if_field_set(r->in.last_logoff);
422                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
423                         r->in.last_logoff = talloc_memdup(mem_ctx, &now, sizeof(now));
424                         fldname = "last_logoff";
425                         break;
426
427                 case last_password_change:
428                         continue_if_field_set(r->in.last_password_change);
429                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
430                         r->in.last_password_change = talloc_memdup(mem_ctx, &now, sizeof(now));
431                         fldname = "last_password_change";
432                         break;
433                 }
434                 
435                 printf(((i < num_changes - 1) ? "%s," : "%s"), fldname);
436         }
437
438         printf("]\n");
439 }
440
441
442 BOOL torture_modifyuser(struct torture_context *torture)
443 {
444         NTSTATUS status;
445         const char *binding;
446         struct dcerpc_binding *bind;
447         struct dcerpc_pipe *p;
448         TALLOC_CTX *prep_mem_ctx, *mem_ctx;
449         struct policy_handle h;
450         struct lsa_String domain_name;
451         const char *name = TEST_USERNAME;
452         struct libnet_context *ctx;
453         struct libnet_ModifyUser req;
454         BOOL ret = True;
455
456         prep_mem_ctx = talloc_init("prepare test_deleteuser");
457         binding = lp_parm_string(-1, "torture", "binding");
458
459         ctx = libnet_context_init(NULL);
460         ctx->cred = cmdline_credentials;
461
462         status = torture_rpc_connection(prep_mem_ctx,
463                                         &p,
464                                         &dcerpc_table_samr);
465         if (!NT_STATUS_IS_OK(status)) {
466                 return False;
467         }
468
469         domain_name.string = lp_workgroup();
470         if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
471                 ret = False;
472                 goto done;
473         }
474
475         if (!test_createuser(p, prep_mem_ctx, &h, name)) {
476                 ret = False;
477                 goto done;
478         }
479
480         mem_ctx = talloc_init("test_modifyuser");
481
482         status = dcerpc_parse_binding(mem_ctx, binding, &bind);
483         if (!NT_STATUS_IS_OK(status)) {
484                 ret = False;
485                 goto done;
486         }
487
488         ZERO_STRUCT(req);
489         req.in.user_name = TEST_USERNAME;
490         req.in.domain_name = lp_workgroup();
491
492         printf("Testing change of a single field\n");
493         set_test_changes(mem_ctx, &req, 1);
494
495         status = libnet_ModifyUser(ctx, mem_ctx, &req);
496         if (!NT_STATUS_IS_OK(status)) {
497                 printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
498                 return False;
499         }
500
501         if (!test_cleanup(ctx->samr_pipe, mem_ctx, &ctx->domain.handle, TEST_USERNAME)) {
502                 printf("cleanup failed\n");
503                 return False;
504         }
505
506 done:
507         talloc_free(prep_mem_ctx);
508         talloc_free(mem_ctx);
509         return ret;
510 }