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