r25398: Parse loadparm context to all lp_*() functions.
[jelmer/samba4-debian.git] / source / torture / rpc / samr_accessmask.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for accessmasks on the SAMR pipe
4
5    Copyright (C) Ronnie Sahlberg 2007
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/torture.h"
23 #include "librpc/gen_ndr/ndr_samr_c.h"
24 #include "torture/rpc/rpc.h"
25 #include "param/param.h"
26 #include "libcli/security/security.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28
29
30 /* test user created to test the ACLs associated to SAMR objects */
31 #define TEST_USER_NAME "samr_testuser"
32
33
34 static NTSTATUS torture_samr_Close(struct torture_context *tctx,
35                 struct dcerpc_pipe *p, 
36                 struct policy_handle *h)
37 {
38         NTSTATUS status;
39         struct samr_Close cl;
40
41         cl.in.handle  = h;
42         cl.out.handle = h;
43         status = dcerpc_samr_Close(p, tctx, &cl);
44
45         return status;
46 }
47
48 static NTSTATUS torture_samr_Connect5(struct torture_context *tctx,
49                 struct dcerpc_pipe *p, 
50                 uint32_t mask, struct policy_handle *h)
51 {
52         NTSTATUS status;
53         struct samr_Connect5 r5;
54         union samr_ConnectInfo info;
55
56         info.info1.unknown1 = 0;
57         info.info1.unknown2 = 0;
58         r5.in.system_name = "";
59         r5.in.level = 1;
60         r5.in.info = &info;
61         r5.out.info = &info;
62         r5.out.connect_handle = h;
63         r5.in.access_mask = mask;
64
65         status = dcerpc_samr_Connect5(p, tctx, &r5);
66
67         return status;
68 }
69
70 /* check which bits in accessmask allows us to connect to the server */
71 static bool test_samr_accessmask_Connect5(struct torture_context *tctx, 
72                                                    struct dcerpc_pipe *p)
73 {
74         NTSTATUS status;
75         struct policy_handle h;
76         int i;
77         uint32_t mask;
78
79         printf("testing which bits in accessmask allows us to connect\n");
80         mask = 1;
81         for (i=0;i<33;i++) {    
82                 printf("testing Connect5 with access mask 0x%08x", mask);
83                 status = torture_samr_Connect5(tctx, p, mask, &h);
84                 mask <<= 1;
85
86                 switch (i) {
87                 case 6:
88                 case 7:
89                 case 8:
90                 case 9:
91                 case 10:
92                 case 11:
93                 case 12:
94                 case 13:
95                 case 14:
96                 case 15:
97                 case 20:
98                 case 21:
99                 case 22:
100                 case 23:
101                 case 26:
102                 case 27:
103                         printf(" expecting to fail");
104                         /* of only one of these bits are set we expect to
105                            fail by default
106                         */
107                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
108                                 printf("Connect5 failed - %s\n", nt_errstr(status));
109                                 return False;
110                         }
111                         break;
112                 default:
113                         /* these bits set are expected to succeed by default */
114                         if (!NT_STATUS_IS_OK(status)) {
115                                 printf("Connect5 failed - %s\n", nt_errstr(status));
116                                 return False;
117                         }
118
119                         status = torture_samr_Close(tctx, p, &h);
120                         if (!NT_STATUS_IS_OK(status)) {
121                                 printf("Close failed - %s\n", nt_errstr(status));
122                                 return False;
123                         }
124                         break;
125                 }
126                 printf(" OK\n");
127         }
128
129         return True;
130 }
131
132 /* check which bits in accessmask allows us to EnumDomains()
133    by default we must specify at least one of :
134         SAMR/EnumDomains
135         Maximum
136         GenericAll
137         GenericRead
138    in the access mask to Connect5() in order to be allowed to perform
139    EnumDomains() on the policy handle returned from Connect5()
140 */
141 static bool test_samr_accessmask_EnumDomains(struct torture_context *tctx, 
142                                                    struct dcerpc_pipe *p)
143 {
144         NTSTATUS status;
145         struct samr_EnumDomains ed;
146         struct policy_handle ch;
147         int i;
148         uint32_t mask;
149         uint32_t resume_handle = 0;
150
151         printf("testing which bits in Connect5 accessmask allows us to EnumDomains\n");
152         mask = 1;
153         for (i=0;i<33;i++) {    
154                 printf("testing Connect5/EnumDomains with access mask 0x%08x", mask);
155                 status = torture_samr_Connect5(tctx, p, mask, &ch);
156                 mask <<= 1;
157
158                 switch (i) {
159                 case 4:  /* SAMR/EnumDomains */
160                 case 25: /* Maximum */
161                 case 28: /* GenericAll */
162                 case 31: /* GenericRead */
163                         /* these bits set are expected to succeed by default */
164                         if (!NT_STATUS_IS_OK(status)) {
165                                 printf("Connect5 failed - %s\n", nt_errstr(status));
166                                 return False;
167                         }
168
169                         ed.in.connect_handle = &ch;
170                         ed.in.resume_handle = &resume_handle;
171                         ed.in.buf_size = (uint32_t)-1;
172                         ed.out.resume_handle = &resume_handle;
173
174                         status = dcerpc_samr_EnumDomains(p, tctx, &ed);
175                         if (!NT_STATUS_IS_OK(status)) {
176                                 printf("EnumDomains failed - %s\n", nt_errstr(status));
177                                 return False;
178                         }
179
180                         status = torture_samr_Close(tctx, p, &ch);
181                         if (!NT_STATUS_IS_OK(status)) {
182                                 printf("Close failed - %s\n", nt_errstr(status));
183                                 return False;
184                         }
185                         break;
186                 default:
187                         printf(" expecting to fail");
188
189                         if (!NT_STATUS_IS_OK(status)) {
190                                 printf(" OK\n");
191                                 continue;
192                         }
193
194                         ed.in.connect_handle = &ch;
195                         ed.in.resume_handle = &resume_handle;
196                         ed.in.buf_size = (uint32_t)-1;
197                         ed.out.resume_handle = &resume_handle;
198
199                         status = dcerpc_samr_EnumDomains(p, tctx, &ed);
200                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
201                                 printf("EnumDomains failed - %s\n", nt_errstr(status));
202                                 return False;
203                         }
204
205                         status = torture_samr_Close(tctx, p, &ch);
206                         if (!NT_STATUS_IS_OK(status)) {
207                                 printf("Close failed - %s\n", nt_errstr(status));
208                                 return False;
209                         }
210                         break;
211                 }
212                 printf(" OK\n");
213         }
214
215         return True;
216 }
217
218
219 /*
220  * test how ACLs affect how/if a user can connect to the SAMR service 
221  *
222  * samr_SetSecurity() returns SUCCESS when changing the ACL for
223  * a policy handle got from Connect5()   but the ACL is not changed on
224  * the server
225  */
226 static bool test_samr_connect_user_acl(struct torture_context *tctx, 
227                                    struct dcerpc_pipe *p,
228                                    struct cli_credentials *test_credentials,
229                                    const struct dom_sid *test_sid)
230
231 {
232         NTSTATUS status;
233         struct policy_handle ch;
234         struct policy_handle uch;
235         struct samr_QuerySecurity qs;
236         struct samr_SetSecurity ss;
237         struct security_ace ace;
238         struct security_descriptor *sd;
239         struct sec_desc_buf sdb;
240         bool ret = True;
241         int sd_size;
242         struct dcerpc_pipe *test_p;
243         const char *binding = torture_setting_string(tctx, "binding", NULL);
244
245         printf("testing ACLs to allow/prevent users to connect to SAMR");
246
247         /* connect to SAMR */
248         status = torture_samr_Connect5(tctx, p, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
249         if (!NT_STATUS_IS_OK(status)) {
250                 printf("Connect5 failed - %s\n", nt_errstr(status));
251                 return False;
252         }
253
254         
255         /* get the current ACL for the SAMR policy handle */
256         qs.in.handle = &ch;
257         qs.in.sec_info = SECINFO_DACL;
258         status = dcerpc_samr_QuerySecurity(p, tctx, &qs);
259         if (!NT_STATUS_IS_OK(status)) {
260                 printf("QuerySecurity failed - %s\n", nt_errstr(status));
261                 ret = False;
262         }
263
264         /* how big is the security descriptor? */
265         sd_size = qs.out.sdbuf->sd_size;
266
267
268         /* add an ACE to the security descriptor to deny the user the
269          * 'connect to server' right
270          */
271         sd = qs.out.sdbuf->sd;
272         ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
273         ace.flags = 0;
274         ace.access_mask = SAMR_ACCESS_CONNECT_TO_SERVER;
275         ace.trustee = *test_sid;
276         status = security_descriptor_dacl_add(sd, &ace);
277         if (!NT_STATUS_IS_OK(status)) {
278                 printf("Failed to add ACE to security descriptor\n");
279                 ret = False;
280         }
281         ss.in.handle = &ch;
282         ss.in.sec_info = SECINFO_DACL;
283         ss.in.sdbuf = &sdb;
284         sdb.sd = sd;
285         status = dcerpc_samr_SetSecurity(p, tctx, &ss);
286         if (!NT_STATUS_IS_OK(status)) {
287                 printf("SetSecurity failed - %s\n", nt_errstr(status));
288                 ret = False;
289         }
290
291
292         /* Try to connect as the test user */
293         status = dcerpc_pipe_connect(tctx, 
294                              &test_p, binding, &ndr_table_samr,
295                              test_credentials, NULL);
296         /* connect to SAMR as the user */
297         status = torture_samr_Connect5(tctx, test_p, SEC_FLAG_MAXIMUM_ALLOWED, &uch);
298         if (!NT_STATUS_IS_OK(status)) {
299                 printf("Connect5 failed - %s\n", nt_errstr(status));
300                 return False;
301         }
302         /* disconnec the user */
303         talloc_free(test_p);
304         if (!NT_STATUS_IS_OK(status)) {
305                 return False;
306         }
307
308
309         /* read the sequrity descriptor back. it should not have changed 
310          * eventhough samr_SetSecurity returned SUCCESS
311          */
312         status = dcerpc_samr_QuerySecurity(p, tctx, &qs);
313         if (!NT_STATUS_IS_OK(status)) {
314                 printf("QuerySecurity failed - %s\n", nt_errstr(status));
315                 ret = False;
316         }
317         if (sd_size != qs.out.sdbuf->sd_size) {
318                 printf("security descriptor changed\n");
319                 ret = False;
320         }
321
322
323         status = torture_samr_Close(tctx, p, &ch);
324         if (!NT_STATUS_IS_OK(status)) {
325                 printf("Close failed - %s\n", nt_errstr(status));
326                 ret = False;
327         }
328
329         if (ret == True) {
330                 printf(" OK\n");
331         }
332         return ret;
333 }
334
335 /*
336  * test if the ACLs are enforced for users.
337  * a normal testuser only gets the rights provided in hte ACL for
338  * Everyone   which does not include the SAMR_ACCESS_SHUTDOWN_SERVER
339  * right.  If the ACLs are checked when a user connects   
340  * a testuser that requests the accessmask with only this bit set
341  * the connect should fail.
342  */
343 static bool test_samr_connect_user_acl_enforced(struct torture_context *tctx, 
344                                    struct dcerpc_pipe *p,
345                                    struct cli_credentials *test_credentials,
346                                    const struct dom_sid *test_sid)
347
348 {
349         NTSTATUS status;
350         struct policy_handle uch;
351         bool ret = True;
352         struct dcerpc_pipe *test_p;
353         const char *binding = torture_setting_string(tctx, "binding", NULL);
354
355         printf("testing if ACLs are enforced for non domain admin users when connecting to SAMR");
356
357
358         status = dcerpc_pipe_connect(tctx, 
359                              &test_p, binding, &ndr_table_samr,
360                              test_credentials, NULL);
361
362         /* connect to SAMR as the user */
363         status = torture_samr_Connect5(tctx, test_p, SAMR_ACCESS_SHUTDOWN_SERVER, &uch);
364         if (NT_STATUS_IS_OK(status)) {
365                 printf("Connect5 failed - %s\n", nt_errstr(status));
366                 return False;
367         }
368         printf(" OK\n");
369
370         /* disconnec the user */
371         talloc_free(test_p);
372
373         return ret;
374 }
375
376 /* check which bits in accessmask allows us to LookupDomain()
377    by default we must specify at least one of :
378    in the access mask to Connect5() in order to be allowed to perform
379                 case 5:  samr/opendomain
380                 case 25: Maximum 
381                 case 28: GenericAll
382                 case 29: GenericExecute
383    LookupDomain() on the policy handle returned from Connect5()
384 */
385 static bool test_samr_accessmask_LookupDomain(struct torture_context *tctx, 
386                                                    struct dcerpc_pipe *p)
387 {
388         NTSTATUS status;
389         struct samr_LookupDomain ld;
390         struct policy_handle ch;
391         struct lsa_String dn;
392         int i;
393         uint32_t mask;
394
395         printf("testing which bits in Connect5 accessmask allows us to LookupDomain\n");
396         mask = 1;
397         for (i=0;i<33;i++) {    
398                 printf("testing Connect5/LookupDomain with access mask 0x%08x", mask);
399                 status = torture_samr_Connect5(tctx, p, mask, &ch);
400                 mask <<= 1;
401
402                 switch (i) {
403                 case 5:  
404                 case 25: /* Maximum */
405                 case 28: /* GenericAll */
406                 case 29: /* GenericExecute */
407                         /* these bits set are expected to succeed by default */
408                         if (!NT_STATUS_IS_OK(status)) {
409                                 printf("Connect5 failed - %s\n", nt_errstr(status));
410                                 return False;
411                         }
412
413                         ld.in.connect_handle = &ch;
414                         ld.in.domain_name    = &dn;
415                         dn.string            = lp_workgroup(global_loadparm);
416
417                         status = dcerpc_samr_LookupDomain(p, tctx, &ld);
418                         if (!NT_STATUS_IS_OK(status)) {
419                                 printf("LookupDomain failed - %s\n", nt_errstr(status));
420                                 return False;
421                         }
422
423                         status = torture_samr_Close(tctx, p, &ch);
424                         if (!NT_STATUS_IS_OK(status)) {
425                                 printf("Close failed - %s\n", nt_errstr(status));
426                                 return False;
427                         }
428                         break;
429                 default:
430                         printf(" expecting to fail");
431
432                         if (!NT_STATUS_IS_OK(status)) {
433                                 printf(" OK\n");
434                                 continue;
435                         }
436
437                         ld.in.connect_handle = &ch;
438                         ld.in.domain_name    = &dn;
439                         dn.string            = lp_workgroup(global_loadparm);
440
441                         status = dcerpc_samr_LookupDomain(p, tctx, &ld);
442                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
443                                 printf("LookupDomain failed - %s\n", nt_errstr(status));
444                                 return False;
445                         }
446
447                         status = torture_samr_Close(tctx, p, &ch);
448                         if (!NT_STATUS_IS_OK(status)) {
449                                 printf("Close failed - %s\n", nt_errstr(status));
450                                 return False;
451                         }
452                         break;
453                 }
454                 printf(" OK\n");
455         }
456
457         return True;
458 }
459
460 /* check which bits in accessmask allows us to OpenDomain()
461    by default we must specify at least one of :
462         samr/opendomain
463         Maximum 
464         GenericAll
465         GenericExecute
466    in the access mask to Connect5() in order to be allowed to perform
467    OpenDomain() on the policy handle returned from Connect5()
468 */
469 static bool test_samr_accessmask_OpenDomain(struct torture_context *tctx, 
470                                                    struct dcerpc_pipe *p)
471 {
472         NTSTATUS status;
473         struct samr_LookupDomain ld;
474         struct samr_OpenDomain od;
475         struct policy_handle ch;
476         struct policy_handle dh;
477         struct lsa_String dn;
478         int i;
479         uint32_t mask;
480
481
482         /* first we must grab the sid of the domain */
483         status = torture_samr_Connect5(tctx, p, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
484         if (!NT_STATUS_IS_OK(status)) {
485                 printf("Connect5 failed - %s\n", nt_errstr(status));
486                 return False;
487         }
488
489         ld.in.connect_handle = &ch;
490         ld.in.domain_name    = &dn;
491         dn.string            = lp_workgroup(global_loadparm);
492         status = dcerpc_samr_LookupDomain(p, tctx, &ld);
493         if (!NT_STATUS_IS_OK(status)) {
494                 printf("LookupDomain failed - %s\n", nt_errstr(status));
495                 return False;
496         }
497
498
499
500         printf("testing which bits in Connect5 accessmask allows us to OpenDomain\n");
501         mask = 1;
502         for (i=0;i<33;i++) {    
503                 printf("testing Connect5/OpenDomain with access mask 0x%08x", mask);
504                 status = torture_samr_Connect5(tctx, p, mask, &ch);
505                 mask <<= 1;
506
507                 switch (i) {
508                 case 5:  
509                 case 25: /* Maximum */
510                 case 28: /* GenericAll */
511                 case 29: /* GenericExecute */
512                         /* these bits set are expected to succeed by default */
513                         if (!NT_STATUS_IS_OK(status)) {
514                                 printf("Connect5 failed - %s\n", nt_errstr(status));
515                                 return False;
516                         }
517
518                         od.in.connect_handle = &ch;
519                         od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
520                         od.in.sid = ld.out.sid;
521                         od.out.domain_handle = &dh;
522
523                         status = dcerpc_samr_OpenDomain(p, tctx, &od);
524                         if (!NT_STATUS_IS_OK(status)) {
525                                 printf("OpenDomain failed - %s\n", nt_errstr(status));
526                                 return False;
527                         }
528
529                         status = torture_samr_Close(tctx, p, &dh);
530                         if (!NT_STATUS_IS_OK(status)) {
531                                 printf("Close failed - %s\n", nt_errstr(status));
532                                 return False;
533                         }
534
535                         status = torture_samr_Close(tctx, p, &ch);
536                         if (!NT_STATUS_IS_OK(status)) {
537                                 printf("Close failed - %s\n", nt_errstr(status));
538                                 return False;
539                         }
540                         break;
541                 default:
542                         printf(" expecting to fail");
543
544                         if (!NT_STATUS_IS_OK(status)) {
545                                 printf(" OK\n");
546                                 continue;
547                         }
548
549                         status = torture_samr_Close(tctx, p, &ch);
550                         if (!NT_STATUS_IS_OK(status)) {
551                                 printf("Close failed - %s\n", nt_errstr(status));
552                                 return False;
553                         }
554                         break;
555                 }
556                 printf(" OK\n");
557         }
558
559         return True;
560 }
561
562 static bool test_samr_connect(struct torture_context *tctx, 
563                                                    struct dcerpc_pipe *p)
564 {
565         void *testuser;
566         const char *testuser_passwd;
567         struct cli_credentials *test_credentials;
568         bool ret = True;
569         const struct dom_sid *test_sid;
570
571         /* create a test user */
572         testuser = torture_create_testuser(tctx, TEST_USER_NAME, lp_workgroup(global_loadparm), 
573                                            ACB_NORMAL, &testuser_passwd);
574         if (!testuser) {
575                 printf("Failed to create test user\n");
576                 return False;
577         }
578         test_credentials = cli_credentials_init(tctx);
579         cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
580         cli_credentials_set_domain(test_credentials, lp_workgroup(global_loadparm), 
581                                    CRED_SPECIFIED);
582         cli_credentials_set_username(test_credentials, TEST_USER_NAME, CRED_SPECIFIED);
583         cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
584         test_sid = torture_join_user_sid(testuser);
585
586
587         /* test which bits in the accessmask to Connect5 
588            will allow us to connect to the server 
589         */
590         if (!test_samr_accessmask_Connect5(tctx, p)) {
591                 ret = False;
592         }
593
594
595         /* test which bits in the accessmask to Connect5 will allow
596          * us to call EnumDomains() 
597          */
598         if (!test_samr_accessmask_EnumDomains(tctx, p)) {
599                 ret = False;
600         }
601
602         /* test which bits in the accessmask to Connect5 will allow
603          * us to call LookupDomain()
604          */
605         if (!test_samr_accessmask_LookupDomain(tctx, p)) {
606                 ret = False;
607         }
608
609
610         /* test which bits in the accessmask to Connect5 will allow
611          * us to call OpenDomain()
612          */
613         if (!test_samr_accessmask_OpenDomain(tctx, p)) {
614                 ret = False;
615         }
616
617
618         /* test if ACLs can be changed for the policy handle
619          * returned by Connect5
620          */
621         if (!test_samr_connect_user_acl(tctx, p, test_credentials, test_sid)) {
622                 ret = False;
623         }
624
625         /* test if the ACLs that are reported from the Connect5 
626          * policy handle is enforced.
627          * i.e. an ordinary user only has the same rights as Everybody
628          *   ReadControl
629          *   Samr/OpenDomain
630          *   Samr/EnumDomains
631          *   Samr/ConnectToServer
632          * is granted and should therefore not be able to connect when
633          * requesting SAMR_ACCESS_SHUTDOWN_SERVER
634          */
635         if (!test_samr_connect_user_acl_enforced(tctx, p, test_credentials, test_sid)) {
636                 ret = False;
637         }
638
639
640
641         /* remove the test user */
642         torture_leave_domain(testuser);
643
644         return ret;
645 }
646
647 struct torture_suite *torture_rpc_samr_accessmask(TALLOC_CTX *mem_ctx)
648 {
649         struct torture_suite *suite = torture_suite_create(mem_ctx, "SAMR_ACCESSMASK");
650         struct torture_rpc_tcase *tcase;
651
652         tcase = torture_suite_add_rpc_iface_tcase(suite, "samr", 
653                                                                                           &ndr_table_samr);
654         
655         torture_rpc_tcase_add_test(tcase, "CONNECT", test_samr_connect);
656
657         return suite;
658 }