63f99f90056bf091de7534a75906522de8b469b9
[samba.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    Copyright (C) Guenther Deschner 2009
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/gen_ndr/ndr_samr_c.h"
24 #include "torture/rpc/torture_rpc.h"
25 #include "param/param.h"
26 #include "libcli/security/security.h"
27
28
29 /* test user created to test the ACLs associated to SAMR objects */
30 #define TEST_USER_NAME "samr_testuser"
31 #define TEST_MACHINENAME "samrtestmach"
32
33 static NTSTATUS torture_samr_Close(struct torture_context *tctx,
34                                    struct dcerpc_binding_handle *b,
35                                    struct policy_handle *h)
36 {
37         NTSTATUS status;
38         struct samr_Close cl;
39
40         cl.in.handle  = h;
41         cl.out.handle = h;
42         status = dcerpc_samr_Close_r(b, tctx, &cl);
43         if (!NT_STATUS_IS_OK(status)) {
44                 return status;
45         }
46
47         return cl.out.result;
48 }
49
50 static NTSTATUS torture_samr_Connect5(struct torture_context *tctx,
51                                       struct dcerpc_binding_handle *b,
52                                       uint32_t mask, struct policy_handle *h)
53 {
54         NTSTATUS status;
55         struct samr_Connect5 r5;
56         union samr_ConnectInfo info;
57         uint32_t level_out = 0;
58
59         info.info1.client_version = 0;
60         info.info1.unknown2 = 0;
61         r5.in.system_name = "";
62         r5.in.level_in = 1;
63         r5.in.info_in = &info;
64         r5.out.info_out = &info;
65         r5.out.level_out = &level_out;
66         r5.out.connect_handle = h;
67         r5.in.access_mask = mask;
68
69         status = dcerpc_samr_Connect5_r(b, tctx, &r5);
70         if (!NT_STATUS_IS_OK(status)) {
71                 return status;
72         }
73
74         return r5.out.result;
75 }
76
77 /* check which bits in accessmask allows us to connect to the server */
78 static bool test_samr_accessmask_Connect5(struct torture_context *tctx,
79                                           struct dcerpc_pipe *p)
80 {
81         NTSTATUS status;
82         struct policy_handle h;
83         int i;
84         uint32_t mask;
85         struct dcerpc_binding_handle *b = p->binding_handle;
86
87         printf("Testing which bits in accessmask allows us to connect\n");
88         mask = 1;
89         for (i=0;i<33;i++) {
90                 printf("Testing Connect5 with access mask 0x%08x", mask);
91                 status = torture_samr_Connect5(tctx, b, mask, &h);
92                 mask <<= 1;
93
94                 switch (i) {
95                 case 6:
96                 case 7:
97                 case 8:
98                 case 9:
99                 case 10:
100                 case 11:
101                 case 12:
102                 case 13:
103                 case 14:
104                 case 15:
105                 case 20:
106                 case 21:
107                 case 22:
108                 case 23:
109                 case 26:
110                 case 27:
111                         printf(" expecting to fail");
112                         /* of only one of these bits are set we expect to
113                            fail by default
114                         */
115                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
116                                 printf("Connect5 failed - %s\n", nt_errstr(status));
117                                 return false;
118                         }
119                         break;
120                 default:
121                         /* these bits set are expected to succeed by default */
122                         if (!NT_STATUS_IS_OK(status)) {
123                                 printf("Connect5 failed - %s\n", nt_errstr(status));
124                                 return false;
125                         }
126
127                         status = torture_samr_Close(tctx, b, &h);
128                         if (!NT_STATUS_IS_OK(status)) {
129                                 printf("Close failed - %s\n", nt_errstr(status));
130                                 return false;
131                         }
132                         break;
133                 }
134                 printf(" OK\n");
135         }
136
137         return true;
138 }
139
140 /* check which bits in accessmask allows us to EnumDomains()
141    by default we must specify at least one of :
142         SAMR/EnumDomains
143         Maximum
144         GenericAll
145         GenericRead
146    in the access mask to Connect5() in order to be allowed to perform
147    EnumDomains() on the policy handle returned from Connect5()
148 */
149 static bool test_samr_accessmask_EnumDomains(struct torture_context *tctx,
150                                              struct dcerpc_pipe *p)
151 {
152         NTSTATUS status;
153         struct samr_EnumDomains ed;
154         struct policy_handle ch;
155         int i;
156         uint32_t mask;
157         uint32_t resume_handle = 0;
158         struct samr_SamArray *sam = NULL;
159         uint32_t num_entries = 0;
160         struct dcerpc_binding_handle *b = p->binding_handle;
161
162         printf("Testing which bits in Connect5 accessmask allows us to EnumDomains\n");
163         mask = 1;
164         for (i=0;i<33;i++) {
165                 printf("Testing Connect5/EnumDomains with access mask 0x%08x", mask);
166                 status = torture_samr_Connect5(tctx, b, mask, &ch);
167                 mask <<= 1;
168
169                 switch (i) {
170                 case 4:  /* SAMR/EnumDomains */
171                 case 25: /* Maximum */
172                 case 28: /* GenericAll */
173                 case 31: /* GenericRead */
174                         /* these bits set are expected to succeed by default */
175                         if (!NT_STATUS_IS_OK(status)) {
176                                 printf("Connect5 failed - %s\n", nt_errstr(status));
177                                 return false;
178                         }
179
180                         ed.in.connect_handle = &ch;
181                         ed.in.resume_handle = &resume_handle;
182                         ed.in.buf_size = (uint32_t)-1;
183                         ed.out.resume_handle = &resume_handle;
184                         ed.out.num_entries = &num_entries;
185                         ed.out.sam = &sam;
186
187                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
188                                 "EnumDomains failed");
189                         if (!NT_STATUS_IS_OK(ed.out.result)) {
190                                 printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
191                                 return false;
192                         }
193
194                         status = torture_samr_Close(tctx, b, &ch);
195                         if (!NT_STATUS_IS_OK(status)) {
196                                 printf("Close failed - %s\n", nt_errstr(status));
197                                 return false;
198                         }
199                         break;
200                 default:
201                         printf(" expecting to fail");
202
203                         if (!NT_STATUS_IS_OK(status)) {
204                                 printf(" OK\n");
205                                 continue;
206                         }
207
208                         ed.in.connect_handle = &ch;
209                         ed.in.resume_handle = &resume_handle;
210                         ed.in.buf_size = (uint32_t)-1;
211                         ed.out.resume_handle = &resume_handle;
212                         ed.out.num_entries = &num_entries;
213                         ed.out.sam = &sam;
214
215                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
216                                 "EnumDomains failed");
217                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ed.out.result)) {
218                                 printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
219                                 return false;
220                         }
221
222                         status = torture_samr_Close(tctx, b, &ch);
223                         if (!NT_STATUS_IS_OK(status)) {
224                                 printf("Close failed - %s\n", nt_errstr(status));
225                                 return false;
226                         }
227                         break;
228                 }
229                 printf(" OK\n");
230         }
231
232         return true;
233 }
234
235
236 /*
237  * test how ACLs affect how/if a user can connect to the SAMR service
238  *
239  * samr_SetSecurity() returns SUCCESS when changing the ACL for
240  * a policy handle got from Connect5()   but the ACL is not changed on
241  * the server
242  */
243 static bool test_samr_connect_user_acl(struct torture_context *tctx,
244                                        struct dcerpc_binding_handle *b,
245                                        struct cli_credentials *test_credentials,
246                                        const struct dom_sid *test_sid)
247
248 {
249         NTSTATUS status;
250         struct policy_handle ch;
251         struct policy_handle uch;
252         struct samr_QuerySecurity qs;
253         struct samr_SetSecurity ss;
254         struct security_ace ace;
255         struct security_descriptor *sd;
256         struct sec_desc_buf sdb, *sdbuf = NULL;
257         bool ret = true;
258         int sd_size;
259         struct dcerpc_pipe *test_p;
260         struct dcerpc_binding_handle *test_b;
261         const char *binding = torture_setting_string(tctx, "binding", NULL);
262
263         printf("Testing ACLs to allow/prevent users to connect to SAMR");
264
265         /* connect to SAMR */
266         status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
267         if (!NT_STATUS_IS_OK(status)) {
268                 printf("Connect5 failed - %s\n", nt_errstr(status));
269                 return false;
270         }
271
272
273         /* get the current ACL for the SAMR policy handle */
274         qs.in.handle = &ch;
275         qs.in.sec_info = SECINFO_DACL;
276         qs.out.sdbuf = &sdbuf;
277         torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
278                 "QuerySecurity failed");
279         if (!NT_STATUS_IS_OK(qs.out.result)) {
280                 printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
281                 ret = false;
282         }
283
284         /* how big is the security descriptor? */
285         sd_size = sdbuf->sd_size;
286
287
288         /* add an ACE to the security descriptor to deny the user the
289          * 'connect to server' right
290          */
291         sd = sdbuf->sd;
292         ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
293         ace.flags = 0;
294         ace.access_mask = SAMR_ACCESS_CONNECT_TO_SERVER;
295         ace.trustee = *test_sid;
296         status = security_descriptor_dacl_add(sd, &ace);
297         if (!NT_STATUS_IS_OK(status)) {
298                 printf("Failed to add ACE to security descriptor\n");
299                 ret = false;
300         }
301         ss.in.handle = &ch;
302         ss.in.sec_info = SECINFO_DACL;
303         ss.in.sdbuf = &sdb;
304         sdb.sd = sd;
305         torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetSecurity_r(b, tctx, &ss),
306                 "SetSecurity failed");
307         if (!NT_STATUS_IS_OK(ss.out.result)) {
308                 printf("SetSecurity failed - %s\n", nt_errstr(ss.out.result));
309                 ret = false;
310         }
311
312
313         /* Try to connect as the test user */
314         status = dcerpc_pipe_connect(tctx,
315                              &test_p, binding, &ndr_table_samr,
316                              test_credentials, tctx->ev, tctx->lp_ctx);
317         if (!NT_STATUS_IS_OK(status)) {
318                 printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
319                 return false;
320         }
321         test_b = test_p->binding_handle;
322
323         /* connect to SAMR as the user */
324         status = torture_samr_Connect5(tctx, test_b, SEC_FLAG_MAXIMUM_ALLOWED, &uch);
325         if (!NT_STATUS_IS_OK(status)) {
326                 printf("Connect5 failed - %s\n", nt_errstr(status));
327                 return false;
328         }
329         /* disconnec the user */
330         talloc_free(test_p);
331
332
333         /* read the sequrity descriptor back. it should not have changed
334          * eventhough samr_SetSecurity returned SUCCESS
335          */
336         torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
337                 "QuerySecurity failed");
338         if (!NT_STATUS_IS_OK(qs.out.result)) {
339                 printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
340                 ret = false;
341         }
342         if (sd_size != sdbuf->sd_size) {
343                 printf("security descriptor changed\n");
344                 ret = false;
345         }
346
347
348         status = torture_samr_Close(tctx, b, &ch);
349         if (!NT_STATUS_IS_OK(status)) {
350                 printf("Close failed - %s\n", nt_errstr(status));
351                 ret = false;
352         }
353
354         if (ret == true) {
355                 printf(" OK\n");
356         }
357         return ret;
358 }
359
360 /*
361  * test if the ACLs are enforced for users.
362  * a normal testuser only gets the rights provided in hte ACL for
363  * Everyone   which does not include the SAMR_ACCESS_SHUTDOWN_SERVER
364  * right.  If the ACLs are checked when a user connects
365  * a testuser that requests the accessmask with only this bit set
366  * the connect should fail.
367  */
368 static bool test_samr_connect_user_acl_enforced(struct torture_context *tctx,
369                                                 struct dcerpc_binding_handle *b,
370                                                 struct cli_credentials *test_credentials,
371                                                 const struct dom_sid *test_sid)
372
373 {
374         NTSTATUS status;
375         struct policy_handle uch;
376         bool ret = true;
377         struct dcerpc_pipe *test_p;
378         struct dcerpc_binding_handle *test_b;
379         const char *binding = torture_setting_string(tctx, "binding", NULL);
380
381         printf("Testing if ACLs are enforced for non domain admin users when connecting to SAMR");
382
383
384         status = dcerpc_pipe_connect(tctx,
385                              &test_p, binding, &ndr_table_samr,
386                              test_credentials, tctx->ev, tctx->lp_ctx);
387         if (!NT_STATUS_IS_OK(status)) {
388                 printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
389                 return false;
390         }
391         test_b = test_p->binding_handle;
392
393         /* connect to SAMR as the user */
394         status = torture_samr_Connect5(tctx, test_b, SAMR_ACCESS_SHUTDOWN_SERVER, &uch);
395         if (NT_STATUS_IS_OK(status)) {
396                 printf("Connect5 failed - %s\n", nt_errstr(status));
397                 return false;
398         }
399         printf(" OK\n");
400
401         /* disconnec the user */
402         talloc_free(test_p);
403
404         return ret;
405 }
406
407 /* check which bits in accessmask allows us to LookupDomain()
408    by default we must specify at least one of :
409    in the access mask to Connect5() in order to be allowed to perform
410                 case 5:  samr/opendomain
411                 case 25: Maximum
412                 case 28: GenericAll
413                 case 29: GenericExecute
414    LookupDomain() on the policy handle returned from Connect5()
415 */
416 static bool test_samr_accessmask_LookupDomain(struct torture_context *tctx,
417                                               struct dcerpc_pipe *p)
418 {
419         NTSTATUS status;
420         struct samr_LookupDomain ld;
421         struct dom_sid2 *sid = NULL;
422         struct policy_handle ch;
423         struct lsa_String dn;
424         int i;
425         uint32_t mask;
426         struct dcerpc_binding_handle *b = p->binding_handle;
427
428         printf("Testing which bits in Connect5 accessmask allows us to LookupDomain\n");
429         mask = 1;
430         for (i=0;i<33;i++) {
431                 printf("Testing Connect5/LookupDomain with access mask 0x%08x", mask);
432                 status = torture_samr_Connect5(tctx, b, mask, &ch);
433                 mask <<= 1;
434
435                 switch (i) {
436                 case 5:
437                 case 25: /* Maximum */
438                 case 28: /* GenericAll */
439                 case 29: /* GenericExecute */
440                         /* these bits set are expected to succeed by default */
441                         if (!NT_STATUS_IS_OK(status)) {
442                                 printf("Connect5 failed - %s\n", nt_errstr(status));
443                                 return false;
444                         }
445
446                         ld.in.connect_handle = &ch;
447                         ld.in.domain_name    = &dn;
448                         ld.out.sid           = &sid;
449                         dn.string            = lpcfg_workgroup(tctx->lp_ctx);
450
451                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
452                                 "LookupDomain failed");
453                         if (!NT_STATUS_IS_OK(ld.out.result)) {
454                                 printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
455                                 return false;
456                         }
457
458                         status = torture_samr_Close(tctx, b, &ch);
459                         if (!NT_STATUS_IS_OK(status)) {
460                                 printf("Close failed - %s\n", nt_errstr(status));
461                                 return false;
462                         }
463                         break;
464                 default:
465                         printf(" expecting to fail");
466
467                         if (!NT_STATUS_IS_OK(status)) {
468                                 printf(" OK\n");
469                                 continue;
470                         }
471
472                         ld.in.connect_handle = &ch;
473                         ld.in.domain_name    = &dn;
474                         ld.out.sid           = &sid;
475                         dn.string            = lpcfg_workgroup(tctx->lp_ctx);
476
477                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
478                                 "LookupDomain failed");
479                         if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ld.out.result)) {
480                                 printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
481                                 return false;
482                         }
483
484                         status = torture_samr_Close(tctx, b, &ch);
485                         if (!NT_STATUS_IS_OK(status)) {
486                                 printf("Close failed - %s\n", nt_errstr(status));
487                                 return false;
488                         }
489                         break;
490                 }
491                 printf(" OK\n");
492         }
493
494         return true;
495 }
496
497 /* check which bits in accessmask allows us to OpenDomain()
498    by default we must specify at least one of :
499         samr/opendomain
500         Maximum
501         GenericAll
502         GenericExecute
503    in the access mask to Connect5() in order to be allowed to perform
504    OpenDomain() on the policy handle returned from Connect5()
505 */
506 static bool test_samr_accessmask_OpenDomain(struct torture_context *tctx,
507                                             struct dcerpc_pipe *p)
508 {
509         NTSTATUS status;
510         struct samr_LookupDomain ld;
511         struct dom_sid2 *sid = NULL;
512         struct samr_OpenDomain od;
513         struct policy_handle ch;
514         struct policy_handle dh;
515         struct lsa_String dn;
516         int i;
517         uint32_t mask;
518         struct dcerpc_binding_handle *b = p->binding_handle;
519
520
521         /* first we must grab the sid of the domain */
522         status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
523         if (!NT_STATUS_IS_OK(status)) {
524                 printf("Connect5 failed - %s\n", nt_errstr(status));
525                 return false;
526         }
527
528         ld.in.connect_handle = &ch;
529         ld.in.domain_name    = &dn;
530         ld.out.sid           = &sid;
531         dn.string            = lpcfg_workgroup(tctx->lp_ctx);
532         torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
533                 "LookupDomain failed");
534         if (!NT_STATUS_IS_OK(ld.out.result)) {
535                 printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
536                 return false;
537         }
538
539
540
541         printf("Testing which bits in Connect5 accessmask allows us to OpenDomain\n");
542         mask = 1;
543         for (i=0;i<33;i++) {
544                 printf("Testing Connect5/OpenDomain with access mask 0x%08x", mask);
545                 status = torture_samr_Connect5(tctx, b, mask, &ch);
546                 mask <<= 1;
547
548                 switch (i) {
549                 case 5:
550                 case 25: /* Maximum */
551                 case 28: /* GenericAll */
552                 case 29: /* GenericExecute */
553                         /* these bits set are expected to succeed by default */
554                         if (!NT_STATUS_IS_OK(status)) {
555                                 printf("Connect5 failed - %s\n", nt_errstr(status));
556                                 return false;
557                         }
558
559                         od.in.connect_handle = &ch;
560                         od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
561                         od.in.sid = sid;
562                         od.out.domain_handle = &dh;
563
564                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &od),
565                                 "OpenDomain failed");
566                         if (!NT_STATUS_IS_OK(od.out.result)) {
567                                 printf("OpenDomain failed - %s\n", nt_errstr(od.out.result));
568                                 return false;
569                         }
570
571                         status = torture_samr_Close(tctx, b, &dh);
572                         if (!NT_STATUS_IS_OK(status)) {
573                                 printf("Close failed - %s\n", nt_errstr(status));
574                                 return false;
575                         }
576
577                         status = torture_samr_Close(tctx, b, &ch);
578                         if (!NT_STATUS_IS_OK(status)) {
579                                 printf("Close failed - %s\n", nt_errstr(status));
580                                 return false;
581                         }
582                         break;
583                 default:
584                         printf(" expecting to fail");
585
586                         if (!NT_STATUS_IS_OK(status)) {
587                                 printf(" OK\n");
588                                 continue;
589                         }
590
591                         status = torture_samr_Close(tctx, b, &ch);
592                         if (!NT_STATUS_IS_OK(status)) {
593                                 printf("Close failed - %s\n", nt_errstr(status));
594                                 return false;
595                         }
596                         break;
597                 }
598                 printf(" OK\n");
599         }
600
601         return true;
602 }
603
604 static bool test_samr_connect(struct torture_context *tctx,
605                               struct dcerpc_pipe *p)
606 {
607         void *testuser;
608         const char *testuser_passwd;
609         struct cli_credentials *test_credentials;
610         bool ret = true;
611         const struct dom_sid *test_sid;
612         struct dcerpc_binding_handle *b = p->binding_handle;
613
614         if (torture_setting_bool(tctx, "samba3", false)) {
615                 torture_skip(tctx, "Skipping test against Samba 3");
616         }
617
618         /* create a test user */
619         testuser = torture_create_testuser(tctx, TEST_USER_NAME, lpcfg_workgroup(tctx->lp_ctx),
620                                            ACB_NORMAL, &testuser_passwd);
621         if (!testuser) {
622                 printf("Failed to create test user\n");
623                 return false;
624         }
625         test_credentials = cli_credentials_init(tctx);
626         cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
627         cli_credentials_set_domain(test_credentials, lpcfg_workgroup(tctx->lp_ctx),
628                                    CRED_SPECIFIED);
629         cli_credentials_set_username(test_credentials, TEST_USER_NAME, CRED_SPECIFIED);
630         cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
631         test_sid = torture_join_user_sid(testuser);
632
633
634         /* test if ACLs can be changed for the policy handle
635          * returned by Connect5
636          */
637         if (!test_samr_connect_user_acl(tctx, b, test_credentials, test_sid)) {
638                 ret = false;
639         }
640
641         /* test if the ACLs that are reported from the Connect5
642          * policy handle is enforced.
643          * i.e. an ordinary user only has the same rights as Everybody
644          *   ReadControl
645          *   Samr/OpenDomain
646          *   Samr/EnumDomains
647          *   Samr/ConnectToServer
648          * is granted and should therefore not be able to connect when
649          * requesting SAMR_ACCESS_SHUTDOWN_SERVER
650          */
651         if (!test_samr_connect_user_acl_enforced(tctx, b, test_credentials, test_sid)) {
652                 ret = false;
653         }
654
655         /* remove the test user */
656         torture_leave_domain(tctx, testuser);
657
658         return ret;
659 }
660
661 struct torture_suite *torture_rpc_samr_accessmask(TALLOC_CTX *mem_ctx)
662 {
663         struct torture_suite *suite = torture_suite_create(mem_ctx, "SAMR-ACCESSMASK");
664         struct torture_rpc_tcase *tcase;
665
666         tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
667                                                   &ndr_table_samr);
668
669         torture_rpc_tcase_add_test(tcase, "CONNECT", test_samr_connect);
670
671         /* test which bits in the accessmask to Connect5 will allow
672          * us to call OpenDomain() */
673         torture_rpc_tcase_add_test(tcase, "OpenDomain",
674                                    test_samr_accessmask_OpenDomain);
675
676         /* test which bits in the accessmask to Connect5 will allow
677          * us to call LookupDomain() */
678         torture_rpc_tcase_add_test(tcase, "LookupDomain",
679                                    test_samr_accessmask_LookupDomain);
680
681         /* test which bits in the accessmask to Connect5 will allow
682          * us to call EnumDomains() */
683         torture_rpc_tcase_add_test(tcase, "EnumDomains",
684                                    test_samr_accessmask_EnumDomains);
685
686         /* test which bits in the accessmask to Connect5
687            will allow us to connect to the server */
688         torture_rpc_tcase_add_test(tcase, "Connect5",
689                                    test_samr_accessmask_Connect5);
690
691         return suite;
692 }
693
694 static bool test_LookupRids(struct torture_context *tctx,
695                             struct dcerpc_binding_handle *b,
696                             struct policy_handle *domain_handle,
697                             uint32_t rid)
698 {
699         struct samr_LookupRids r;
700         struct lsa_Strings names;
701         struct samr_Ids types;
702
703         torture_comment(tctx, "Testing LookupRids %d\n", rid);
704
705         r.in.domain_handle = domain_handle;
706         r.in.num_rids = 1;
707         r.in.rids = &rid;
708         r.out.names = &names;
709         r.out.types = &types;
710
711         torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupRids_r(b, tctx, &r),
712                 "failed to call samr_LookupRids");
713         torture_assert_ntstatus_ok(tctx, r.out.result,
714                 "failed to call samr_LookupRids");
715
716         return true;
717 }
718
719
720 static bool test_user(struct torture_context *tctx,
721                       struct dcerpc_binding_handle *b,
722                       struct policy_handle *domain_handle,
723                       uint32_t access_mask,
724                       struct samr_DispEntryGeneral *u)
725 {
726         struct policy_handle user_handle;
727
728         torture_comment(tctx, "Testing user %s (%d)\n", u->account_name.string, u->rid);
729
730         torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, u->rid),
731                 "failed to call lookuprids");
732
733         {
734                 struct samr_OpenUser r;
735
736                 r.in.domain_handle = domain_handle;
737                 r.in.access_mask = access_mask;
738                 r.in.rid = u->rid;
739                 r.out.user_handle = &user_handle;
740
741                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
742                         "failed to open user");
743                 torture_assert_ntstatus_ok(tctx, r.out.result,
744                         "failed to open user");
745         }
746         {
747                 struct samr_QueryUserInfo r;
748                 union samr_UserInfo *info;
749                 uint32_t levels[] = { 16, 21 };
750                 int i;
751
752                 r.in.user_handle = &user_handle;
753                 r.out.info = &info;
754
755                 for (i=0; i < ARRAY_SIZE(levels); i++) {
756
757                         r.in.level = levels[i];
758
759                         torture_comment(tctx, "Testing QueryUserInfo rid: %d level: %d\n",
760                                 u->rid, r.in.level);
761
762                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo_r(b, tctx, &r),
763                                 talloc_asprintf(tctx, "failed to query user info level %d", r.in.level));
764                         torture_assert_ntstatus_ok(tctx, r.out.result,
765                                 talloc_asprintf(tctx, "failed to query user info level %d", r.in.level));
766                 }
767         }
768         {
769                 struct samr_GetGroupsForUser r;
770                 struct samr_RidWithAttributeArray *rids;
771
772                 r.in.user_handle = &user_handle;
773                 r.out.rids = &rids;
774
775                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetGroupsForUser_r(b, tctx, &r),
776                         "failed to query groups for user");
777                 torture_assert_ntstatus_ok(tctx, r.out.result,
778                         "failed to query groups for user");
779         }
780
781         torture_assert_ntstatus_ok(tctx,
782                 torture_samr_Close(tctx, b, &user_handle),
783                 "failed to close user handle");
784
785         return true;
786 }
787
788 static bool test_samr_group(struct torture_context *tctx,
789                             struct dcerpc_binding_handle *b,
790                             struct policy_handle *domain_handle,
791                             uint32_t access_mask,
792                             struct samr_SamEntry *g)
793 {
794         struct policy_handle group_handle;
795
796         torture_comment(tctx, "Testing group %s (%d)\n", g->name.string, g->idx);
797
798         torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, g->idx),
799                 "failed to call lookuprids");
800         {
801                 struct samr_OpenGroup r;
802
803                 r.in.domain_handle = domain_handle;
804                 r.in.access_mask = access_mask;
805                 r.in.rid = g->idx;
806                 r.out.group_handle = &group_handle;
807
808                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r),
809                         "failed to open group");
810                 torture_assert_ntstatus_ok(tctx, r.out.result,
811                         "failed to open group");
812         }
813         {
814                 struct samr_QueryGroupMember r;
815                 struct samr_RidTypeArray *rids;
816
817                 r.in.group_handle = &group_handle;
818                 r.out.rids = &rids;
819
820                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &r),
821                         "failed to query group member");
822                 torture_assert_ntstatus_ok(tctx, r.out.result,
823                         "failed to query group member");
824
825         }
826
827         torture_assert_ntstatus_ok(tctx,
828                 torture_samr_Close(tctx, b, &group_handle),
829                 "failed to close group handle");
830
831         return true;
832 }
833
834 static bool test_samr_alias(struct torture_context *tctx,
835                             struct dcerpc_binding_handle *b,
836                             struct policy_handle *domain_handle,
837                             struct samr_SamEntry *a)
838 {
839         torture_comment(tctx, "Testing alias %s (%d)\n", a->name.string, a->idx);
840
841         torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, a->idx),
842                 "failed to call lookuprids");
843
844         {
845                 struct samr_GetAliasMembership r;
846                 struct lsa_SidArray sids;
847                 struct samr_Ids rids;
848
849                 ZERO_STRUCT(sids);
850
851                 r.in.domain_handle = domain_handle;
852                 r.in.sids = &sids;
853                 r.out.rids = &rids;
854
855                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r),
856                         "failed to get alias membership");
857                 torture_assert_ntstatus_ok(tctx, r.out.result,
858                         "failed to get alias membership");
859         }
860
861
862         return true;
863 }
864
865 static bool test_samr_domain(struct torture_context *tctx,
866                              struct dcerpc_binding_handle *b,
867                              uint32_t access_mask,
868                              const char *domain_name,
869                              struct policy_handle *connect_handle,
870                              struct policy_handle *domain_handle_p)
871 {
872         struct policy_handle domain_handle;
873         struct dom_sid *domain_sid;
874
875         if (!domain_name) {
876                 struct samr_EnumDomains r;
877                 uint32_t resume_handle;
878                 struct samr_SamArray *sam;
879                 uint32_t num_entries;
880                 int i;
881
882                 r.in.connect_handle = connect_handle;
883                 r.in.buf_size = 0xffff;
884                 r.in.resume_handle = &resume_handle;
885                 r.out.sam = &sam;
886                 r.out.num_entries = &num_entries;
887                 r.out.resume_handle = &resume_handle;
888
889                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r),
890                         "failed to enum domains");
891                 torture_assert_ntstatus_ok(tctx, r.out.result,
892                         "failed to enum domains");
893
894                 torture_assert_int_equal(tctx, num_entries, 2,
895                         "unexpected number of domains");
896
897                 torture_assert(tctx, sam,
898                         "no domain pointer returned");
899
900                 for (i=0; i < sam->count; i++) {
901                         if (!strequal(sam->entries[i].name.string, "builtin")) {
902                                 domain_name = sam->entries[i].name.string;
903                                 break;
904                         }
905                 }
906
907                 torture_assert(tctx, domain_name,
908                         "no domain found other than builtin found");
909         }
910
911         {
912                 struct samr_LookupDomain r;
913                 struct dom_sid2 *sid;
914                 struct lsa_String name;
915
916                 name.string = talloc_strdup(tctx, domain_name);
917
918                 r.in.connect_handle = connect_handle;
919                 r.in.domain_name = &name;
920                 r.out.sid = &sid;
921
922                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
923                         "failed to lookup domain");
924                 torture_assert_ntstatus_ok(tctx, r.out.result,
925                         "failed to lookup domain");
926
927                 domain_sid = dom_sid_dup(tctx, sid);
928         }
929
930         {
931                 struct samr_OpenDomain r;
932
933                 r.in.connect_handle = connect_handle;
934                 r.in.access_mask = access_mask;
935                 r.in.sid = domain_sid;
936                 r.out.domain_handle = &domain_handle;
937
938                 torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &r),
939                         "failed to open domain");
940                 torture_assert_ntstatus_ok(tctx, r.out.result,
941                         "failed to open domain");
942
943         }
944
945         {
946                 struct samr_QueryDomainInfo r;
947                 union samr_DomainInfo *info;
948                 uint32_t levels[] = { 1, 2, 8, 12 };
949                 int i;
950
951                 r.in.domain_handle = &domain_handle;
952                 r.out.info = &info;
953
954                 for (i=0; i < ARRAY_SIZE(levels); i++) {
955
956                         r.in.level = levels[i];
957
958                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDomainInfo_r(b, tctx, &r),
959                                 talloc_asprintf(tctx, "failed to query domain info level %d", r.in.level));
960                         torture_assert_ntstatus_ok(tctx, r.out.result,
961                                 talloc_asprintf(tctx, "failed to query domain info level %d", r.in.level));
962                 }
963
964         }
965
966         *domain_handle_p = domain_handle;
967
968         return true;
969 }
970
971 static void get_query_dispinfo_params(int loop_count,
972                                       uint32_t *max_entries,
973                                       uint32_t *buf_size)
974 {
975         switch(loop_count) {
976         case 0:
977                 *max_entries = 512;
978                 *buf_size = 16383;
979                 break;
980         case 1:
981                 *max_entries = 1024;
982                 *buf_size = 32766;
983                 break;
984         case 2:
985                 *max_entries = 2048;
986                 *buf_size = 65532;
987                 break;
988         case 3:
989                 *max_entries = 4096;
990                 *buf_size = 131064;
991                 break;
992         default:              /* loop_count >= 4 */
993                 *max_entries = 4096;
994                 *buf_size = 131071;
995                 break;
996         }
997 }
998
999
1000 static bool test_samr_users(struct torture_context *tctx,
1001                             struct dcerpc_binding_handle *b,
1002                             uint32_t access_mask,
1003                             struct policy_handle *domain_handle)
1004 {
1005         {
1006                 struct samr_QueryDisplayInfo r;
1007                 uint32_t total_size;
1008                 uint32_t returned_size;
1009                 union samr_DispInfo info;
1010                 int loop_count = 0;
1011
1012                 r.in.domain_handle = domain_handle;
1013                 r.in.level = 1;
1014                 r.in.start_idx = 0;
1015
1016                 r.out.total_size = &total_size;
1017                 r.out.returned_size = &returned_size;
1018                 r.out.info = &info;
1019
1020                 do {
1021                         int i;
1022
1023                         r.in.max_entries = 0xffff;
1024                         r.in.buf_size = 0xffff;
1025
1026                         get_query_dispinfo_params(loop_count,
1027                                                   &r.in.max_entries,
1028                                                   &r.in.buf_size);
1029
1030                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
1031                                 "QueryDisplayInfo failed");
1032                         if (NT_STATUS_IS_ERR(r.out.result)) {
1033                                 torture_assert_ntstatus_ok(tctx, r.out.result,
1034                                         "failed to call QueryDisplayInfo");
1035                         }
1036
1037                         for (i=0; i < info.info1.count; i++) {
1038                                 torture_assert(tctx,
1039                                         test_user(tctx, b, domain_handle, access_mask, &info.info1.entries[i]),
1040                                                 "failed to test user");
1041                         }
1042                         loop_count++;
1043                         r.in.start_idx += info.info1.count;
1044
1045                 } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1046         }
1047
1048         return true;
1049 }
1050
1051 static bool test_samr_groups(struct torture_context *tctx,
1052                              struct dcerpc_binding_handle *b,
1053                              uint32_t access_mask,
1054                              struct policy_handle *domain_handle)
1055 {
1056         {
1057                 struct samr_EnumDomainGroups r;
1058                 uint32_t resume_handle = 0;
1059                 struct samr_SamArray *sam;
1060                 uint32_t num_entries;
1061
1062                 r.in.domain_handle = domain_handle;
1063                 r.in.resume_handle = &resume_handle;
1064                 r.in.max_size = 0xFFFF;
1065
1066                 r.out.sam = &sam;
1067                 r.out.num_entries = &num_entries;
1068                 r.out.resume_handle = &resume_handle;
1069
1070                 do {
1071                         int i;
1072
1073                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r),
1074                                 "EnumDomainGroups failed");
1075                         if (NT_STATUS_IS_ERR(r.out.result)) {
1076                                 torture_assert_ntstatus_ok(tctx, r.out.result,
1077                                         "failed to call EnumDomainGroups");
1078                         }
1079
1080                         for (i=0; i < num_entries; i++) {
1081                                 torture_assert(tctx,
1082                                         test_samr_group(tctx, b, domain_handle, access_mask, &sam->entries[i]),
1083                                                 "failed to test group");
1084                         }
1085
1086                 } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1087         }
1088
1089         return true;
1090 }
1091
1092 static bool test_samr_aliases(struct torture_context *tctx,
1093                               struct dcerpc_binding_handle *b,
1094                               uint32_t access_mask,
1095                               struct policy_handle *domain_handle)
1096 {
1097         {
1098                 struct samr_EnumDomainAliases r;
1099                 uint32_t resume_handle = 0;
1100                 struct samr_SamArray *sam;
1101                 uint32_t num_entries;
1102
1103                 r.in.domain_handle = domain_handle;
1104                 r.in.resume_handle = &resume_handle;
1105                 r.in.max_size = 0xFFFF;
1106
1107                 r.out.sam = &sam;
1108                 r.out.num_entries = &num_entries;
1109                 r.out.resume_handle = &resume_handle;
1110
1111                 do {
1112                         int i;
1113
1114                         torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r),
1115                                 "EnumDomainAliases failed");
1116                         if (NT_STATUS_IS_ERR(r.out.result)) {
1117                                 torture_assert_ntstatus_ok(tctx, r.out.result,
1118                                         "failed to call EnumDomainAliases");
1119                         }
1120
1121                         for (i=0; i < num_entries; i++) {
1122                                 torture_assert(tctx,
1123                                         test_samr_alias(tctx, b, domain_handle, &sam->entries[i]),
1124                                                 "failed to test alias");
1125                         }
1126
1127                 } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1128         }
1129
1130         return true;
1131 }
1132
1133 static bool torture_rpc_samr_workstation_query(struct torture_context *tctx,
1134                                                struct dcerpc_pipe *p,
1135                                                struct cli_credentials *machine_credentials)
1136 {
1137         struct policy_handle connect_handle;
1138         struct policy_handle domain_handle;
1139         struct dcerpc_binding_handle *b = p->binding_handle;
1140
1141         torture_assert_ntstatus_ok(tctx,
1142                 torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1143                                       &connect_handle),
1144                 "failed to connect to samr server");
1145
1146         torture_assert(tctx,
1147                 test_samr_domain(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1148                                  lpcfg_workgroup(tctx->lp_ctx),
1149                                  &connect_handle, &domain_handle),
1150                 "failed to test domain");
1151
1152         torture_assert(tctx,
1153                 test_samr_users(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1154                                 &domain_handle),
1155                 "failed to test users");
1156
1157         torture_assert(tctx,
1158                 test_samr_groups(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1159                                  &domain_handle),
1160                 "failed to test groups");
1161
1162         torture_assert(tctx,
1163                 test_samr_aliases(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1164                                   &domain_handle),
1165                 "failed to test aliases");
1166
1167         torture_assert_ntstatus_ok(tctx,
1168                 torture_samr_Close(tctx, b, &domain_handle),
1169                 "failed to close domain handle");
1170
1171         torture_assert_ntstatus_ok(tctx,
1172                 torture_samr_Close(tctx, b, &connect_handle),
1173                 "failed to close connect handle");
1174
1175         return true;
1176 }
1177
1178 /* The purpose of this test is to verify that an account authenticated as a
1179  * domain member workstation can query a DC for various remote read calls all
1180  * opening objects while requesting SEC_FLAG_MAXIMUM_ALLOWED access rights on
1181  * the object open calls. This is the behavior of winbind (and most of samba's
1182  * client code) - gd */
1183
1184 struct torture_suite *torture_rpc_samr_workstation_auth(TALLOC_CTX *mem_ctx)
1185 {
1186         struct torture_suite *suite = torture_suite_create(mem_ctx, "SAMR-MACHINE-AUTH");
1187         struct torture_rpc_tcase *tcase;
1188
1189         tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "samr",
1190                                                                       &ndr_table_samr,
1191                                                                       TEST_MACHINENAME);
1192
1193         torture_rpc_tcase_add_test_creds(tcase, "workstation_query",
1194                                          torture_rpc_samr_workstation_query);
1195
1196         return suite;
1197 }