s3-docs: Adapt version in man ldbrename.
[Samba.git] / source4 / torture / rpc / samr_accessmask.c
blob1e74455849cea45e9690aa895f89f393121d9330
1 /*
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/>.
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"
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)
38 NTSTATUS status;
39 struct samr_Close cl;
41 cl.in.handle = h;
42 cl.out.handle = h;
43 status = dcerpc_samr_Close(p, tctx, &cl);
45 return status;
48 static NTSTATUS torture_samr_Connect5(struct torture_context *tctx,
49 struct dcerpc_pipe *p,
50 uint32_t mask, struct policy_handle *h)
52 NTSTATUS status;
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 = "";
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;
67 status = dcerpc_samr_Connect5(p, tctx, &r5);
69 return status;
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)
76 NTSTATUS status;
77 struct policy_handle h;
78 int i;
79 uint32_t mask;
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;
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
109 if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
110 printf("Connect5 failed - %s\n", nt_errstr(status));
111 return false;
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;
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;
126 break;
128 printf(" OK\n");
131 return true;
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()
143 static bool test_samr_accessmask_EnumDomains(struct torture_context *tctx,
144 struct dcerpc_pipe *p)
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;
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;
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;
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;
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;
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;
191 break;
192 default:
193 printf(" expecting to fail");
195 if (!NT_STATUS_IS_OK(status)) {
196 printf(" OK\n");
197 continue;
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;
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;
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;
218 break;
220 printf(" OK\n");
223 return true;
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
232 * the server
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)
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);
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));
259 return false;
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;
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
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;
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;
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));
307 return false;
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));
314 return false;
316 /* disconnec the user */
317 talloc_free(test_p);
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));
326 ret = false;
328 if (sd_size != sdbuf->sd_size) {
329 printf("security descriptor changed\n");
330 ret = false;
334 status = torture_samr_Close(tctx, p, &ch);
335 if (!NT_STATUS_IS_OK(status)) {
336 printf("Close failed - %s\n", nt_errstr(status));
337 ret = false;
340 if (ret == true) {
341 printf(" OK\n");
343 return ret;
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)
360 NTSTATUS status;
361 struct policy_handle uch;
362 bool ret = true;
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));
374 return false;
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));
381 return false;
383 printf(" OK\n");
385 /* disconnec the user */
386 talloc_free(test_p);
388 return ret;
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
395 case 25: Maximum
396 case 28: GenericAll
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)
403 NTSTATUS status;
404 struct samr_LookupDomain ld;
405 struct dom_sid2 *sid = NULL;
406 struct policy_handle ch;
407 struct lsa_String dn;
408 int i;
409 uint32_t mask;
411 printf("testing which bits in Connect5 accessmask allows us to LookupDomain\n");
412 mask = 1;
413 for (i=0;i<33;i++) {
414 printf("testing Connect5/LookupDomain with access mask 0x%08x", mask);
415 status = torture_samr_Connect5(tctx, p, mask, &ch);
416 mask <<= 1;
418 switch (i) {
419 case 5:
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));
426 return false;
429 ld.in.connect_handle = &ch;
430 ld.in.domain_name = &dn;
431 ld.out.sid = &sid;
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));
437 return false;
440 status = torture_samr_Close(tctx, p, &ch);
441 if (!NT_STATUS_IS_OK(status)) {
442 printf("Close failed - %s\n", nt_errstr(status));
443 return false;
445 break;
446 default:
447 printf(" expecting to fail");
449 if (!NT_STATUS_IS_OK(status)) {
450 printf(" OK\n");
451 continue;
454 ld.in.connect_handle = &ch;
455 ld.in.domain_name = &dn;
456 ld.out.sid = &sid;
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));
462 return false;
465 status = torture_samr_Close(tctx, p, &ch);
466 if (!NT_STATUS_IS_OK(status)) {
467 printf("Close failed - %s\n", nt_errstr(status));
468 return false;
470 break;
472 printf(" OK\n");
475 return true;
478 /* check which bits in accessmask allows us to OpenDomain()
479 by default we must specify at least one of :
480 samr/opendomain
481 Maximum
482 GenericAll
483 GenericExecute
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)
490 NTSTATUS status;
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;
497 int i;
498 uint32_t mask;
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));
505 return false;
508 ld.in.connect_handle = &ch;
509 ld.in.domain_name = &dn;
510 ld.out.sid = &sid;
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));
515 return false;
520 printf("testing which bits in Connect5 accessmask allows us to OpenDomain\n");
521 mask = 1;
522 for (i=0;i<33;i++) {
523 printf("testing Connect5/OpenDomain with access mask 0x%08x", mask);
524 status = torture_samr_Connect5(tctx, p, mask, &ch);
525 mask <<= 1;
527 switch (i) {
528 case 5:
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));
535 return false;
538 od.in.connect_handle = &ch;
539 od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
540 od.in.sid = sid;
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));
546 return false;
549 status = torture_samr_Close(tctx, p, &dh);
550 if (!NT_STATUS_IS_OK(status)) {
551 printf("Close failed - %s\n", nt_errstr(status));
552 return false;
555 status = torture_samr_Close(tctx, p, &ch);
556 if (!NT_STATUS_IS_OK(status)) {
557 printf("Close failed - %s\n", nt_errstr(status));
558 return false;
560 break;
561 default:
562 printf(" expecting to fail");
564 if (!NT_STATUS_IS_OK(status)) {
565 printf(" OK\n");
566 continue;
569 status = torture_samr_Close(tctx, p, &ch);
570 if (!NT_STATUS_IS_OK(status)) {
571 printf("Close failed - %s\n", nt_errstr(status));
572 return false;
574 break;
576 printf(" OK\n");
579 return true;
582 static bool test_samr_connect(struct torture_context *tctx,
583 struct dcerpc_pipe *p)
585 void *testuser;
586 const char *testuser_passwd;
587 struct cli_credentials *test_credentials;
588 bool ret = true;
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);
598 if (!testuser) {
599 printf("Failed to create test user\n");
600 return false;
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),
605 CRED_SPECIFIED);
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)) {
615 ret = false;
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
621 * ReadControl
622 * Samr/OpenDomain
623 * Samr/EnumDomains
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)) {
629 ret = false;
632 /* remove the test user */
633 torture_leave_domain(tctx, testuser);
635 return ret;
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",
644 &ndr_table_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);
668 return suite;