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