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