2 Unix SMB/CIFS implementation.
3 test suite for accessmasks on the SAMR pipe
5 Copyright (C) Ronnie Sahlberg 2007
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.
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.
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/>.
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"
30 /* test user created to test the ACLs associated to SAMR objects */
31 #define TEST_USER_NAME "samr_testuser"
34 static NTSTATUS
torture_samr_Close(struct torture_context
*tctx
,
35 struct dcerpc_pipe
*p
,
36 struct policy_handle
*h
)
43 status
= dcerpc_samr_Close(p
, tctx
, &cl
);
48 static NTSTATUS
torture_samr_Connect5(struct torture_context
*tctx
,
49 struct dcerpc_pipe
*p
,
50 uint32_t mask
, struct policy_handle
*h
)
53 struct samr_Connect5 r5
;
54 union samr_ConnectInfo info
;
55 uint32_t level_out
= 0;
57 info
.info1
.client_version
= 0;
58 info
.info1
.unknown2
= 0;
59 r5
.in
.system_name
= "";
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
;
67 status
= dcerpc_samr_Connect5(p
, tctx
, &r5
);
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
)
77 struct policy_handle h
;
81 printf("testing which bits in accessmask allows us to connect\n");
84 printf("testing Connect5 with access mask 0x%08x", mask
);
85 status
= torture_samr_Connect5(tctx
, p
, mask
, &h
);
105 printf(" expecting to fail");
106 /* of only one of these bits are set we expect to
109 if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED
, status
)) {
110 printf("Connect5 failed - %s\n", nt_errstr(status
));
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
));
121 status
= torture_samr_Close(tctx
, p
, &h
);
122 if (!NT_STATUS_IS_OK(status
)) {
123 printf("Close failed - %s\n", nt_errstr(status
));
134 /* check which bits in accessmask allows us to EnumDomains()
135 by default we must specify at least one of :
140 in the access mask to Connect5() in order to be allowed to perform
141 EnumDomains() on the policy handle returned from Connect5()
143 static bool test_samr_accessmask_EnumDomains(struct torture_context
*tctx
,
144 struct dcerpc_pipe
*p
)
147 struct samr_EnumDomains ed
;
148 struct policy_handle ch
;
151 uint32_t resume_handle
= 0;
152 struct samr_SamArray
*sam
= NULL
;
153 uint32_t num_entries
= 0;
155 printf("testing which bits in Connect5 accessmask allows us to EnumDomains\n");
158 printf("testing Connect5/EnumDomains with access mask 0x%08x", mask
);
159 status
= torture_samr_Connect5(tctx
, p
, mask
, &ch
);
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
));
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
;
180 status
= dcerpc_samr_EnumDomains(p
, tctx
, &ed
);
181 if (!NT_STATUS_IS_OK(status
)) {
182 printf("EnumDomains failed - %s\n", nt_errstr(status
));
186 status
= torture_samr_Close(tctx
, p
, &ch
);
187 if (!NT_STATUS_IS_OK(status
)) {
188 printf("Close failed - %s\n", nt_errstr(status
));
193 printf(" expecting to fail");
195 if (!NT_STATUS_IS_OK(status
)) {
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
;
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
));
213 status
= torture_samr_Close(tctx
, p
, &ch
);
214 if (!NT_STATUS_IS_OK(status
)) {
215 printf("Close failed - %s\n", nt_errstr(status
));
228 * test how ACLs affect how/if a user can connect to the SAMR service
230 * samr_SetSecurity() returns SUCCESS when changing the ACL for
231 * a policy handle got from Connect5() but the ACL is not changed on
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
)
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
;
250 struct dcerpc_pipe
*test_p
;
251 const char *binding
= torture_setting_string(tctx
, "binding", NULL
);
253 printf("testing ACLs to allow/prevent users to connect to SAMR");
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
));
263 /* get the current ACL for the SAMR policy handle */
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
));
273 /* how big is the security descriptor? */
274 sd_size
= sdbuf
->sd_size
;
277 /* add an ACE to the security descriptor to deny the user the
278 * 'connect to server' right
281 ace
.type
= SEC_ACE_TYPE_ACCESS_DENIED
;
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");
291 ss
.in
.sec_info
= SECINFO_DACL
;
294 status
= dcerpc_samr_SetSecurity(p
, tctx
, &ss
);
295 if (!NT_STATUS_IS_OK(status
)) {
296 printf("SetSecurity failed - %s\n", nt_errstr(status
));
301 /* Try to connect as the test user */
302 status
= dcerpc_pipe_connect(tctx
,
303 &test_p
, binding
, &ndr_table_samr
,
304 test_credentials
, tctx
->ev
, tctx
->lp_ctx
);
305 if (!NT_STATUS_IS_OK(status
)) {
306 printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status
));
310 /* connect to SAMR as the user */
311 status
= torture_samr_Connect5(tctx
, test_p
, SEC_FLAG_MAXIMUM_ALLOWED
, &uch
);
312 if (!NT_STATUS_IS_OK(status
)) {
313 printf("Connect5 failed - %s\n", nt_errstr(status
));
316 /* disconnec the user */
320 /* read the sequrity descriptor back. it should not have changed
321 * eventhough samr_SetSecurity returned SUCCESS
323 status
= dcerpc_samr_QuerySecurity(p
, tctx
, &qs
);
324 if (!NT_STATUS_IS_OK(status
)) {
325 printf("QuerySecurity failed - %s\n", nt_errstr(status
));
328 if (sd_size
!= sdbuf
->sd_size
) {
329 printf("security descriptor changed\n");
334 status
= torture_samr_Close(tctx
, p
, &ch
);
335 if (!NT_STATUS_IS_OK(status
)) {
336 printf("Close failed - %s\n", nt_errstr(status
));
347 * test if the ACLs are enforced for users.
348 * a normal testuser only gets the rights provided in hte ACL for
349 * Everyone which does not include the SAMR_ACCESS_SHUTDOWN_SERVER
350 * right. If the ACLs are checked when a user connects
351 * a testuser that requests the accessmask with only this bit set
352 * the connect should fail.
354 static bool test_samr_connect_user_acl_enforced(struct torture_context
*tctx
,
355 struct dcerpc_pipe
*p
,
356 struct cli_credentials
*test_credentials
,
357 const struct dom_sid
*test_sid
)
361 struct policy_handle uch
;
363 struct dcerpc_pipe
*test_p
;
364 const char *binding
= torture_setting_string(tctx
, "binding", NULL
);
366 printf("testing if ACLs are enforced for non domain admin users when connecting to SAMR");
369 status
= dcerpc_pipe_connect(tctx
,
370 &test_p
, binding
, &ndr_table_samr
,
371 test_credentials
, tctx
->ev
, tctx
->lp_ctx
);
372 if (!NT_STATUS_IS_OK(status
)) {
373 printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status
));
377 /* connect to SAMR as the user */
378 status
= torture_samr_Connect5(tctx
, test_p
, SAMR_ACCESS_SHUTDOWN_SERVER
, &uch
);
379 if (NT_STATUS_IS_OK(status
)) {
380 printf("Connect5 failed - %s\n", nt_errstr(status
));
385 /* disconnec the user */
391 /* check which bits in accessmask allows us to LookupDomain()
392 by default we must specify at least one of :
393 in the access mask to Connect5() in order to be allowed to perform
394 case 5: samr/opendomain
397 case 29: GenericExecute
398 LookupDomain() on the policy handle returned from Connect5()
400 static bool test_samr_accessmask_LookupDomain(struct torture_context
*tctx
,
401 struct dcerpc_pipe
*p
)
404 struct samr_LookupDomain ld
;
405 struct dom_sid2
*sid
= NULL
;
406 struct policy_handle ch
;
407 struct lsa_String dn
;
411 printf("testing which bits in Connect5 accessmask allows us to LookupDomain\n");
414 printf("testing Connect5/LookupDomain with access mask 0x%08x", mask
);
415 status
= torture_samr_Connect5(tctx
, p
, mask
, &ch
);
420 case 25: /* Maximum */
421 case 28: /* GenericAll */
422 case 29: /* GenericExecute */
423 /* these bits set are expected to succeed by default */
424 if (!NT_STATUS_IS_OK(status
)) {
425 printf("Connect5 failed - %s\n", nt_errstr(status
));
429 ld
.in
.connect_handle
= &ch
;
430 ld
.in
.domain_name
= &dn
;
432 dn
.string
= lp_workgroup(tctx
->lp_ctx
);
434 status
= dcerpc_samr_LookupDomain(p
, tctx
, &ld
);
435 if (!NT_STATUS_IS_OK(status
)) {
436 printf("LookupDomain failed - %s\n", nt_errstr(status
));
440 status
= torture_samr_Close(tctx
, p
, &ch
);
441 if (!NT_STATUS_IS_OK(status
)) {
442 printf("Close failed - %s\n", nt_errstr(status
));
447 printf(" expecting to fail");
449 if (!NT_STATUS_IS_OK(status
)) {
454 ld
.in
.connect_handle
= &ch
;
455 ld
.in
.domain_name
= &dn
;
457 dn
.string
= lp_workgroup(tctx
->lp_ctx
);
459 status
= dcerpc_samr_LookupDomain(p
, tctx
, &ld
);
460 if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED
, status
)) {
461 printf("LookupDomain failed - %s\n", nt_errstr(status
));
465 status
= torture_samr_Close(tctx
, p
, &ch
);
466 if (!NT_STATUS_IS_OK(status
)) {
467 printf("Close failed - %s\n", nt_errstr(status
));
478 /* check which bits in accessmask allows us to OpenDomain()
479 by default we must specify at least one of :
484 in the access mask to Connect5() in order to be allowed to perform
485 OpenDomain() on the policy handle returned from Connect5()
487 static bool test_samr_accessmask_OpenDomain(struct torture_context
*tctx
,
488 struct dcerpc_pipe
*p
)
491 struct samr_LookupDomain ld
;
492 struct dom_sid2
*sid
= NULL
;
493 struct samr_OpenDomain od
;
494 struct policy_handle ch
;
495 struct policy_handle dh
;
496 struct lsa_String dn
;
501 /* first we must grab the sid of the domain */
502 status
= torture_samr_Connect5(tctx
, p
, SEC_FLAG_MAXIMUM_ALLOWED
, &ch
);
503 if (!NT_STATUS_IS_OK(status
)) {
504 printf("Connect5 failed - %s\n", nt_errstr(status
));
508 ld
.in
.connect_handle
= &ch
;
509 ld
.in
.domain_name
= &dn
;
511 dn
.string
= lp_workgroup(tctx
->lp_ctx
);
512 status
= dcerpc_samr_LookupDomain(p
, tctx
, &ld
);
513 if (!NT_STATUS_IS_OK(status
)) {
514 printf("LookupDomain failed - %s\n", nt_errstr(status
));
520 printf("testing which bits in Connect5 accessmask allows us to OpenDomain\n");
523 printf("testing Connect5/OpenDomain with access mask 0x%08x", mask
);
524 status
= torture_samr_Connect5(tctx
, p
, mask
, &ch
);
529 case 25: /* Maximum */
530 case 28: /* GenericAll */
531 case 29: /* GenericExecute */
532 /* these bits set are expected to succeed by default */
533 if (!NT_STATUS_IS_OK(status
)) {
534 printf("Connect5 failed - %s\n", nt_errstr(status
));
538 od
.in
.connect_handle
= &ch
;
539 od
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
541 od
.out
.domain_handle
= &dh
;
543 status
= dcerpc_samr_OpenDomain(p
, tctx
, &od
);
544 if (!NT_STATUS_IS_OK(status
)) {
545 printf("OpenDomain failed - %s\n", nt_errstr(status
));
549 status
= torture_samr_Close(tctx
, p
, &dh
);
550 if (!NT_STATUS_IS_OK(status
)) {
551 printf("Close failed - %s\n", nt_errstr(status
));
555 status
= torture_samr_Close(tctx
, p
, &ch
);
556 if (!NT_STATUS_IS_OK(status
)) {
557 printf("Close failed - %s\n", nt_errstr(status
));
562 printf(" expecting to fail");
564 if (!NT_STATUS_IS_OK(status
)) {
569 status
= torture_samr_Close(tctx
, p
, &ch
);
570 if (!NT_STATUS_IS_OK(status
)) {
571 printf("Close failed - %s\n", nt_errstr(status
));
582 static bool test_samr_connect(struct torture_context
*tctx
,
583 struct dcerpc_pipe
*p
)
586 const char *testuser_passwd
;
587 struct cli_credentials
*test_credentials
;
589 const struct dom_sid
*test_sid
;
591 if (torture_setting_bool(tctx
, "samba3", false)) {
592 torture_skip(tctx
, "Skipping test against Samba 3");
595 /* create a test user */
596 testuser
= torture_create_testuser(tctx
, TEST_USER_NAME
, lp_workgroup(tctx
->lp_ctx
),
597 ACB_NORMAL
, &testuser_passwd
);
599 printf("Failed to create test user\n");
602 test_credentials
= cli_credentials_init(tctx
);
603 cli_credentials_set_workstation(test_credentials
, "localhost", CRED_SPECIFIED
);
604 cli_credentials_set_domain(test_credentials
, lp_workgroup(tctx
->lp_ctx
),
606 cli_credentials_set_username(test_credentials
, TEST_USER_NAME
, CRED_SPECIFIED
);
607 cli_credentials_set_password(test_credentials
, testuser_passwd
, CRED_SPECIFIED
);
608 test_sid
= torture_join_user_sid(testuser
);
611 /* test if ACLs can be changed for the policy handle
612 * returned by Connect5
614 if (!test_samr_connect_user_acl(tctx
, p
, test_credentials
, test_sid
)) {
618 /* test if the ACLs that are reported from the Connect5
619 * policy handle is enforced.
620 * i.e. an ordinary user only has the same rights as Everybody
624 * Samr/ConnectToServer
625 * is granted and should therefore not be able to connect when
626 * requesting SAMR_ACCESS_SHUTDOWN_SERVER
628 if (!test_samr_connect_user_acl_enforced(tctx
, p
, test_credentials
, test_sid
)) {
632 /* remove the test user */
633 torture_leave_domain(tctx
, testuser
);
638 struct torture_suite
*torture_rpc_samr_accessmask(TALLOC_CTX
*mem_ctx
)
640 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "SAMR-ACCESSMASK");
641 struct torture_rpc_tcase
*tcase
;
643 tcase
= torture_suite_add_rpc_iface_tcase(suite
, "samr",
646 torture_rpc_tcase_add_test(tcase
, "CONNECT", test_samr_connect
);
648 /* test which bits in the accessmask to Connect5 will allow
649 * us to call OpenDomain() */
650 torture_rpc_tcase_add_test(tcase
, "OpenDomain",
651 test_samr_accessmask_OpenDomain
);
653 /* test which bits in the accessmask to Connect5 will allow
654 * us to call LookupDomain() */
655 torture_rpc_tcase_add_test(tcase
, "LookupDomain",
656 test_samr_accessmask_LookupDomain
);
658 /* test which bits in the accessmask to Connect5 will allow
659 * us to call EnumDomains() */
660 torture_rpc_tcase_add_test(tcase
, "EnumDomains",
661 test_samr_accessmask_EnumDomains
);
663 /* test which bits in the accessmask to Connect5
664 will allow us to connect to the server */
665 torture_rpc_tcase_add_test(tcase
, "Connect5",
666 test_samr_accessmask_Connect5
);