c60a5ebcaaa31bf9af1366d0f2f55654640610e2
[samba.git] / source4 / torture / libnet / userman.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 "torture/rpc/rpc.h"
24 #include "torture/libnet/usertest.h"
25 #include "libnet/libnet.h"
26 #include "librpc/gen_ndr/ndr_samr_c.h"
27
28
29 static BOOL test_opendomain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
30                             struct policy_handle *handle, struct lsa_String *domname)
31 {
32         NTSTATUS status;
33         struct policy_handle h, domain_handle;
34         struct samr_Connect r1;
35         struct samr_LookupDomain r2;
36         struct samr_OpenDomain r3;
37         
38         printf("connecting\n");
39         
40         r1.in.system_name = 0;
41         r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
42         r1.out.connect_handle = &h;
43         
44         status = dcerpc_samr_Connect(p, mem_ctx, &r1);
45         if (!NT_STATUS_IS_OK(status)) {
46                 printf("Connect failed - %s\n", nt_errstr(status));
47                 return False;
48         }
49         
50         r2.in.connect_handle = &h;
51         r2.in.domain_name = domname;
52
53         printf("domain lookup on %s\n", domname->string);
54
55         status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
56         if (!NT_STATUS_IS_OK(status)) {
57                 printf("LookupDomain failed - %s\n", nt_errstr(status));
58                 return False;
59         }
60
61         r3.in.connect_handle = &h;
62         r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
63         r3.in.sid = r2.out.sid;
64         r3.out.domain_handle = &domain_handle;
65
66         printf("opening domain\n");
67
68         status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
69         if (!NT_STATUS_IS_OK(status)) {
70                 printf("OpenDomain failed - %s\n", nt_errstr(status));
71                 return False;
72         } else {
73                 *handle = domain_handle;
74         }
75
76         return True;
77 }
78
79
80 static BOOL test_useradd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
81                          struct policy_handle *domain_handle,
82                          const char *name)
83 {
84         NTSTATUS status;
85         BOOL ret = True;
86         struct libnet_rpc_useradd user;
87         
88         user.in.domain_handle = *domain_handle;
89         user.in.username      = name;
90
91         printf("Testing libnet_rpc_useradd\n");
92
93         status = libnet_rpc_useradd(p, mem_ctx, &user);
94         if (!NT_STATUS_IS_OK(status)) {
95                 printf("Failed to call sync rpc_composite_userinfo - %s\n", nt_errstr(status));
96                 return False;
97         }
98         
99         return ret;
100 }
101
102
103 static void msg_handler(struct monitor_msg *m)
104 {
105         struct msg_rpc_create_user *msg_create;
106
107         switch (m->type) {
108         case rpc_create_user:
109                 msg_create = (struct msg_rpc_create_user*)m->data;
110                 printf("monitor_msg: user created (rid=%d)\n", msg_create->rid);
111                 break;
112         }
113 }
114
115
116 static BOOL test_useradd_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
117                                struct policy_handle *handle, const char* username)
118 {
119         NTSTATUS status;
120         struct composite_context *c;
121         struct libnet_rpc_useradd user;
122
123         user.in.domain_handle = *handle;
124         user.in.username      = username;
125         
126         printf("Testing async libnet_rpc_useradd\n");
127         
128         c = libnet_rpc_useradd_send(p, &user, msg_handler);
129         if (!c) {
130                 printf("Failed to call async libnet_rpc_useradd\n");
131                 return False;
132         }
133
134         status = libnet_rpc_useradd_recv(c, mem_ctx, &user);
135         if (!NT_STATUS_IS_OK(status)) {
136                 printf("Calling async libnet_rpc_useradd failed - %s\n", nt_errstr(status));
137                 return False;
138         }
139
140         return True;
141
142 }
143
144
145 static BOOL test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
146                          struct policy_handle *domain_handle, const char *username)
147 {
148         NTSTATUS status;
149         struct samr_LookupNames r1;
150         struct samr_OpenUser r2;
151         struct samr_DeleteUser r3;
152         struct lsa_String names[2];
153         uint32_t rid;
154         struct policy_handle user_handle;
155
156         names[0].string = username;
157
158         r1.in.domain_handle  = domain_handle;
159         r1.in.num_names      = 1;
160         r1.in.names          = names;
161         
162         printf("user account lookup '%s'\n", username);
163
164         status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
165         if (!NT_STATUS_IS_OK(status)) {
166                 printf("LookupNames failed - %s\n", nt_errstr(status));
167                 return False;
168         }
169
170         rid = r1.out.rids.ids[0];
171         
172         r2.in.domain_handle  = domain_handle;
173         r2.in.access_mask    = SEC_FLAG_MAXIMUM_ALLOWED;
174         r2.in.rid            = rid;
175         r2.out.user_handle   = &user_handle;
176
177         printf("opening user account\n");
178
179         status = dcerpc_samr_OpenUser(p, mem_ctx, &r2);
180         if (!NT_STATUS_IS_OK(status)) {
181                 printf("OpenUser failed - %s\n", nt_errstr(status));
182                 return False;
183         }
184
185         r3.in.user_handle  = &user_handle;
186         r3.out.user_handle = &user_handle;
187
188         printf("deleting user account\n");
189         
190         status = dcerpc_samr_DeleteUser(p, mem_ctx, &r3);
191         if (!NT_STATUS_IS_OK(status)) {
192                 printf("DeleteUser failed - %s\n", nt_errstr(status));
193                 return False;
194         }
195         
196         return True;
197 }
198
199
200 static BOOL test_createuser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
201                             struct policy_handle *handle, const char* user)
202 {
203         NTSTATUS status;
204         struct policy_handle user_handle;
205         struct lsa_String username;
206         struct samr_CreateUser r1;
207         struct samr_Close r2;
208         uint32_t user_rid;
209
210         username.string = user;
211         
212         r1.in.domain_handle = handle;
213         r1.in.account_name = &username;
214         r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
215         r1.out.user_handle = &user_handle;
216         r1.out.rid = &user_rid;
217
218         printf("creating user '%s'\n", username.string);
219         
220         status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
221         if (!NT_STATUS_IS_OK(status)) {
222                 printf("CreateUser failed - %s\n", nt_errstr(status));
223
224                 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
225                         printf("User (%s) already exists - attempting to delete and recreate account again\n", user);
226                         if (!test_cleanup(p, mem_ctx, handle, TEST_USERNAME)) {
227                                 return False;
228                         }
229
230                         printf("creating user account\n");
231                         
232                         status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
233                         if (!NT_STATUS_IS_OK(status)) {
234                                 printf("CreateUser failed - %s\n", nt_errstr(status));
235                                 return False;
236                         }
237                         return True;
238                 }               
239                 return False;
240         }
241
242         r2.in.handle = &user_handle;
243         r2.out.handle = &user_handle;
244         
245         printf("closing user '%s'\n", username.string);
246
247         status = dcerpc_samr_Close(p, mem_ctx, &r2);
248         if (!NT_STATUS_IS_OK(status)) {
249                 printf("Close failed - %s\n", nt_errstr(status));
250                 return False;
251         }
252
253         return True;
254 }
255
256
257 static BOOL test_usermod(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
258                          struct policy_handle *handle, int num_changes,
259                          struct libnet_rpc_usermod *mod, char **username)
260 {
261         const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
262         const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
263         const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
264         const char *homedir, *homedrive, *logonscript;
265         const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL),
266                                    (ACB_NORMAL | ACB_PWNOEXP),
267                                    (ACB_NORMAL) };
268
269         NTSTATUS status;
270         struct timeval now;
271         enum test_fields testfld;
272         int i;
273
274         ZERO_STRUCT(*mod);
275         srandom((unsigned)time(NULL));
276
277         mod->in.username = talloc_strdup(mem_ctx, *username);
278         mod->in.domain_handle = *handle;
279
280         printf("modifying user (%d simultaneous change(s))\n", num_changes);
281
282         printf("fields to change: [");
283
284         for (i = 0; i < num_changes && i < FIELDS_NUM - 1; i++) {
285                 const char *fldname;
286
287                 testfld = (random() % (FIELDS_NUM - 1)) + 1;
288
289                 gettimeofday(&now, NULL);
290
291                 switch (testfld) {
292                 case account_name:
293                         continue_if_field_set(mod->in.change.account_name);
294                         mod->in.change.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
295                                                                       (int)(random() % 100));
296                         mod->in.change.fields |= USERMOD_FIELD_ACCOUNT_NAME;
297                         fldname = "account_name";
298                         *username = talloc_strdup(mem_ctx, mod->in.change.account_name);
299                         break;
300
301                 case full_name:
302                         continue_if_field_set(mod->in.change.full_name);
303                         mod->in.change.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
304                                                                   (int)random(), (int)random());
305                         mod->in.change.fields |= USERMOD_FIELD_FULL_NAME;
306                         fldname = "full_name";
307                         break;
308
309                 case description:
310                         continue_if_field_set(mod->in.change.description);
311                         mod->in.change.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
312                                                                     random());
313                         mod->in.change.fields |= USERMOD_FIELD_DESCRIPTION;
314                         fldname = "description";
315                         break;
316                         
317                 case home_directory:
318                         continue_if_field_set(mod->in.change.home_directory);
319                         homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))];
320                         mod->in.change.home_directory = talloc_strdup(mem_ctx, homedir);
321                         mod->in.change.fields |= USERMOD_FIELD_HOME_DIRECTORY;
322                         fldname = "home_directory";
323                         break;
324
325                 case home_drive:
326                         continue_if_field_set(mod->in.change.home_drive);
327                         homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))];
328                         mod->in.change.home_drive = talloc_strdup(mem_ctx, homedrive);
329                         mod->in.change.fields |= USERMOD_FIELD_HOME_DRIVE;
330                         fldname = "home_drive";
331                         break;
332
333                 case comment:
334                         continue_if_field_set(mod->in.change.comment);
335                         mod->in.change.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
336                                                                 random(), random());
337                         mod->in.change.fields |= USERMOD_FIELD_COMMENT;
338                         fldname = "comment";
339                         break;
340
341                 case logon_script:
342                         continue_if_field_set(mod->in.change.logon_script);
343                         logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))];
344                         mod->in.change.logon_script = talloc_strdup(mem_ctx, logonscript);
345                         mod->in.change.fields |= USERMOD_FIELD_LOGON_SCRIPT;
346                         fldname = "logon_script";
347                         break;
348
349                 case profile_path:
350                         continue_if_field_set(mod->in.change.profile_path);
351                         mod->in.change.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
352                                                                      (long int)random(), (unsigned int)random());
353                         mod->in.change.fields |= USERMOD_FIELD_PROFILE_PATH;
354                         fldname = "profile_path";
355                         break;
356
357                 case acct_expiry:
358                         continue_if_field_set(mod->in.change.acct_expiry);
359                         now = timeval_add(&now, (random() % (31*24*60*60)), 0);
360                         mod->in.change.acct_expiry = talloc_memdup(mem_ctx, &now, sizeof(now));
361                         mod->in.change.fields |= USERMOD_FIELD_ACCT_EXPIRY;
362                         fldname = "acct_expiry";
363                         break;
364
365                 case acct_flags:
366                         continue_if_field_set(mod->in.change.acct_flags);
367                         mod->in.change.acct_flags = flags[random() % (sizeof(flags)/sizeof(uint32_t))];
368                         mod->in.change.fields |= USERMOD_FIELD_ACCT_FLAGS;
369                         fldname = "acct_flags";
370                         break;
371
372                 default:
373                         fldname = talloc_asprintf(mem_ctx, "unknown_field (%d)", testfld);
374                         break;
375                 }
376
377                 printf(((i < num_changes - 1) ? "%s," : "%s"), fldname);
378         }
379         printf("]\n");
380
381         status = libnet_rpc_usermod(p, mem_ctx, mod);
382         if (!NT_STATUS_IS_OK(status)) {
383                 printf("Failed to call sync libnet_rpc_usermod - %s\n", nt_errstr(status));
384                 return False;
385         }
386
387         return True;
388 }
389
390
391 static BOOL test_userdel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
392                          struct policy_handle *handle, const char *username)
393 {
394         NTSTATUS status;
395         struct libnet_rpc_userdel user;
396         
397         user.in.domain_handle = *handle;
398         user.in.username = username;
399         
400         status = libnet_rpc_userdel(p, mem_ctx, &user);
401         if (!NT_STATUS_IS_OK(status)) {
402                 printf("Failed to call sync libnet_rpc_userdel - %s\n", nt_errstr(status));
403                 return False;
404         }
405
406         return True;
407 }
408
409
410 #define CMP_LSA_STRING_FLD(fld, flags) \
411         if ((mod->in.change.fields & flags) && \
412             !strequal(i->fld.string, mod->in.change.fld)) { \
413                 printf("'%s' field does not match\n", #fld); \
414                 printf("received: '%s'\n", i->fld.string); \
415                 printf("expected: '%s'\n", mod->in.change.fld); \
416                 return False; \
417         }
418
419
420 #define CMP_TIME_FLD(fld, flags) \
421         if (mod->in.change.fields & flags) { \
422                 nttime_to_timeval(&t, i->fld); \
423                 if (timeval_compare(&t, mod->in.change.fld)) { \
424                         printf("'%s' field does not match\n", #fld); \
425                         printf("received: '%s (+%ld us)'\n", timestring(mem_ctx, t.tv_sec), t.tv_usec); \
426                         printf("expected: '%s (+%ld us)'\n", timestring(mem_ctx, mod->in.change.fld->tv_sec), mod->in.change.fld->tv_usec); \
427                         return False; \
428                 } \
429         }
430
431 #define CMP_NUM_FLD(fld, flags) \
432         if ((mod->in.change.fields & flags) && \
433             (i->fld != mod->in.change.fld)) { \
434                 printf("'%s' field does not match\n", #fld); \
435                 printf("received: '%04x'\n", i->fld); \
436                 printf("expected: '%04x'\n", mod->in.change.fld); \
437                 return False; \
438         }
439
440
441 static BOOL test_compare(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
442                          struct policy_handle *handle, struct libnet_rpc_usermod *mod,
443                          const char *username)
444 {
445         NTSTATUS status;
446         struct libnet_rpc_userinfo info;
447         struct samr_UserInfo21 *i;
448         struct timeval t;
449
450         ZERO_STRUCT(info);
451
452         info.in.username = username;
453         info.in.domain_handle = *handle;
454         info.in.level = 21;             /* the most rich infolevel available */
455
456         status = libnet_rpc_userinfo(p, mem_ctx, &info);
457         if (!NT_STATUS_IS_OK(status)) {
458                 printf("Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status));
459                 return False;
460         }
461
462         i = &info.out.info.info21;
463
464         CMP_LSA_STRING_FLD(account_name, USERMOD_FIELD_ACCOUNT_NAME);
465         CMP_LSA_STRING_FLD(full_name, USERMOD_FIELD_FULL_NAME);
466         CMP_LSA_STRING_FLD(description, USERMOD_FIELD_DESCRIPTION);
467         CMP_LSA_STRING_FLD(comment, USERMOD_FIELD_COMMENT);
468         CMP_LSA_STRING_FLD(logon_script, USERMOD_FIELD_LOGON_SCRIPT);
469         CMP_LSA_STRING_FLD(profile_path, USERMOD_FIELD_PROFILE_PATH);
470         CMP_LSA_STRING_FLD(home_directory, USERMOD_FIELD_HOME_DIRECTORY);
471         CMP_LSA_STRING_FLD(home_drive, USERMOD_FIELD_HOME_DRIVE);
472         CMP_TIME_FLD(acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
473         CMP_NUM_FLD(acct_flags, USERMOD_FIELD_ACCT_FLAGS)
474
475         return True;
476 }
477
478
479 BOOL torture_useradd(struct torture_context *torture)
480 {
481         NTSTATUS status;
482         const char *binding;
483         struct dcerpc_pipe *p;
484         struct policy_handle h;
485         struct lsa_String domain_name;
486         const char *name = TEST_USERNAME;
487         TALLOC_CTX *mem_ctx;
488         BOOL ret = True;
489
490         mem_ctx = talloc_init("test_useradd");
491         binding = torture_setting_string(torture, "binding", NULL);
492
493         status = torture_rpc_connection(mem_ctx, 
494                                         &p,
495                                         &dcerpc_table_samr);
496         
497         if (!NT_STATUS_IS_OK(status)) {
498                 return False;
499         }
500
501         domain_name.string = lp_workgroup();
502         if (!test_opendomain(p, mem_ctx, &h, &domain_name)) {
503                 ret = False;
504                 goto done;
505         }
506
507         if (!test_useradd(p, mem_ctx, &h, name)) {
508                 ret = False;
509                 goto done;
510         }
511
512         if (!test_cleanup(p, mem_ctx, &h, name)) {
513                 ret = False;
514                 goto done;
515         }
516
517         if (!test_opendomain(p, mem_ctx, &h, &domain_name)) {
518                 ret = False;
519                 goto done;
520         }
521
522         if (!test_useradd_async(p, mem_ctx, &h, name)) {
523                 ret = False;
524                 goto done;
525         }
526
527         if (!test_cleanup(p, mem_ctx, &h, name)) {
528                 ret = False;
529                 goto done;
530         }
531
532 done:
533         talloc_free(mem_ctx);
534         return ret;
535 }
536
537
538 BOOL torture_userdel(struct torture_context *torture)
539 {
540         NTSTATUS status;
541         const char *binding;
542         struct dcerpc_pipe *p;
543         struct policy_handle h;
544         struct lsa_String domain_name;
545         const char *name = TEST_USERNAME;
546         TALLOC_CTX *mem_ctx;
547         BOOL ret = True;
548
549         mem_ctx = talloc_init("test_userdel");
550         binding = torture_setting_string(torture, "binding", NULL);
551
552         status = torture_rpc_connection(mem_ctx, 
553                                         &p,
554                                         &dcerpc_table_samr);
555         
556         if (!NT_STATUS_IS_OK(status)) {
557                 return False;
558         }
559
560         domain_name.string = lp_workgroup();
561         if (!test_opendomain(p, mem_ctx, &h, &domain_name)) {
562                 ret = False;
563                 goto done;
564         }
565
566         if (!test_createuser(p, mem_ctx, &h, name)) {
567                 ret = False;
568                 goto done;
569         }
570         
571         if (!test_userdel(p, mem_ctx, &h, name)) {
572                 ret = False;
573                 goto done;
574         }
575         
576 done:
577         talloc_free(mem_ctx);
578         return ret;
579 }
580
581
582 BOOL torture_usermod(struct torture_context *torture)
583 {
584         NTSTATUS status;
585         const char *binding;
586         struct dcerpc_pipe *p;
587         struct policy_handle h;
588         struct lsa_String domain_name;
589         int i;
590         char *name;
591         TALLOC_CTX *mem_ctx;
592         BOOL ret = True;
593
594         mem_ctx = talloc_init("test_userdel");
595         binding = torture_setting_string(torture, "binding", NULL);
596
597         status = torture_rpc_connection(mem_ctx, 
598                                         &p,
599                                         &dcerpc_table_samr);
600         
601         if (!NT_STATUS_IS_OK(status)) {
602                 ret = False;
603                 goto done;
604         }
605
606         domain_name.string = lp_workgroup();
607         name = talloc_strdup(mem_ctx, TEST_USERNAME);
608
609         if (!test_opendomain(p, mem_ctx, &h, &domain_name)) {
610                 ret = False;
611                 goto done;
612         }
613
614         if (!test_createuser(p, mem_ctx, &h, name)) {
615                 ret = False;
616                 goto done;
617         }
618         
619         for (i = 1; i < FIELDS_NUM; i++) {
620                 struct libnet_rpc_usermod m;
621
622                 if (!test_usermod(p, mem_ctx, &h, i, &m, &name)) {
623                         ret = False;
624                         goto cleanup;
625                 }
626
627                 if (!test_compare(p, mem_ctx, &h, &m, name)) {
628                         ret = False;
629                         goto cleanup;
630                 }
631         }
632         
633 cleanup:        
634         if (!test_cleanup(p, mem_ctx, &h, name)) {
635                 ret = False;
636                 goto done;
637         }
638
639 done:
640         talloc_free(mem_ctx);
641         return ret;
642 }