Line data Source code
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 708 : static NTSTATUS torture_samr_Close(struct torture_context *tctx,
34 : struct dcerpc_binding_handle *b,
35 : struct policy_handle *h)
36 : {
37 0 : NTSTATUS status;
38 0 : struct samr_Close cl;
39 :
40 708 : cl.in.handle = h;
41 708 : cl.out.handle = h;
42 708 : status = dcerpc_samr_Close_r(b, tctx, &cl);
43 708 : if (!NT_STATUS_IS_OK(status)) {
44 0 : return status;
45 : }
46 :
47 708 : return cl.out.result;
48 : }
49 :
50 5 : 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 0 : NTSTATUS status;
55 0 : struct samr_Connect5 r5;
56 0 : union samr_ConnectInfo info;
57 5 : uint32_t level_out = 0;
58 :
59 5 : info.info1.client_version = 0;
60 5 : info.info1.supported_features = 0;
61 5 : r5.in.system_name = "";
62 5 : r5.in.level_in = 1;
63 5 : r5.in.info_in = &info;
64 5 : r5.out.info_out = &info;
65 5 : r5.out.level_out = &level_out;
66 5 : r5.out.connect_handle = h;
67 5 : r5.in.access_mask = mask;
68 :
69 5 : status = dcerpc_samr_Connect5_r(b, tctx, &r5);
70 5 : if (!NT_STATUS_IS_OK(status)) {
71 0 : return status;
72 : }
73 :
74 5 : return r5.out.result;
75 : }
76 :
77 : /* check which bits in accessmask allows us to connect to the server */
78 0 : static bool test_samr_accessmask_Connect5(struct torture_context *tctx,
79 : struct dcerpc_pipe *p)
80 : {
81 0 : NTSTATUS status;
82 0 : struct policy_handle h;
83 0 : int i;
84 0 : uint32_t mask;
85 0 : struct dcerpc_binding_handle *b = p->binding_handle;
86 :
87 0 : printf("Testing which bits in accessmask allows us to connect\n");
88 0 : mask = 1;
89 0 : for (i=0;i<33;i++) {
90 0 : printf("Testing Connect5 with access mask 0x%08x", mask);
91 0 : status = torture_samr_Connect5(tctx, b, mask, &h);
92 0 : mask <<= 1;
93 :
94 0 : switch (i) {
95 0 : 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 0 : printf(" expecting to fail");
112 : /* of only one of these bits are set we expect to
113 : fail by default
114 : */
115 0 : if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) {
116 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
117 0 : return false;
118 : }
119 0 : break;
120 0 : default:
121 : /* these bits set are expected to succeed by default */
122 0 : if (!NT_STATUS_IS_OK(status)) {
123 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
124 0 : return false;
125 : }
126 :
127 0 : status = torture_samr_Close(tctx, b, &h);
128 0 : if (!NT_STATUS_IS_OK(status)) {
129 0 : printf("Close failed - %s\n", nt_errstr(status));
130 0 : return false;
131 : }
132 0 : break;
133 : }
134 0 : printf(" OK\n");
135 : }
136 :
137 0 : 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 0 : static bool test_samr_accessmask_EnumDomains(struct torture_context *tctx,
150 : struct dcerpc_pipe *p)
151 : {
152 0 : NTSTATUS status;
153 0 : struct samr_EnumDomains ed;
154 0 : struct policy_handle ch;
155 0 : int i;
156 0 : uint32_t mask;
157 0 : uint32_t resume_handle = 0;
158 0 : struct samr_SamArray *sam = NULL;
159 0 : uint32_t num_entries = 0;
160 0 : struct dcerpc_binding_handle *b = p->binding_handle;
161 :
162 0 : printf("Testing which bits in Connect5 accessmask allows us to EnumDomains\n");
163 0 : mask = 1;
164 0 : for (i=0;i<33;i++) {
165 0 : printf("Testing Connect5/EnumDomains with access mask 0x%08x", mask);
166 0 : status = torture_samr_Connect5(tctx, b, mask, &ch);
167 0 : mask <<= 1;
168 :
169 0 : switch (i) {
170 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
176 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
177 0 : return false;
178 : }
179 :
180 0 : ed.in.connect_handle = &ch;
181 0 : ed.in.resume_handle = &resume_handle;
182 0 : ed.in.buf_size = (uint32_t)-1;
183 0 : ed.out.resume_handle = &resume_handle;
184 0 : ed.out.num_entries = &num_entries;
185 0 : ed.out.sam = &sam;
186 :
187 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
188 : "EnumDomains failed");
189 0 : if (!NT_STATUS_IS_OK(ed.out.result)) {
190 0 : printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
191 0 : return false;
192 : }
193 :
194 0 : status = torture_samr_Close(tctx, b, &ch);
195 0 : if (!NT_STATUS_IS_OK(status)) {
196 0 : printf("Close failed - %s\n", nt_errstr(status));
197 0 : return false;
198 : }
199 0 : break;
200 0 : default:
201 0 : printf(" expecting to fail");
202 :
203 0 : if (!NT_STATUS_IS_OK(status)) {
204 0 : printf(" OK\n");
205 0 : continue;
206 : }
207 :
208 0 : ed.in.connect_handle = &ch;
209 0 : ed.in.resume_handle = &resume_handle;
210 0 : ed.in.buf_size = (uint32_t)-1;
211 0 : ed.out.resume_handle = &resume_handle;
212 0 : ed.out.num_entries = &num_entries;
213 0 : ed.out.sam = &sam;
214 :
215 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &ed),
216 : "EnumDomains failed");
217 0 : if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ed.out.result)) {
218 0 : printf("EnumDomains failed - %s\n", nt_errstr(ed.out.result));
219 0 : return false;
220 : }
221 :
222 0 : status = torture_samr_Close(tctx, b, &ch);
223 0 : if (!NT_STATUS_IS_OK(status)) {
224 0 : printf("Close failed - %s\n", nt_errstr(status));
225 0 : return false;
226 : }
227 0 : break;
228 : }
229 0 : printf(" OK\n");
230 : }
231 :
232 0 : 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 0 : 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 0 : NTSTATUS status;
250 0 : struct policy_handle ch;
251 0 : struct policy_handle uch;
252 0 : struct samr_QuerySecurity qs;
253 0 : struct samr_SetSecurity ss;
254 0 : struct security_ace ace = {};
255 0 : struct security_descriptor *sd;
256 0 : struct sec_desc_buf sdb, *sdbuf = NULL;
257 0 : bool ret = true;
258 0 : int sd_size;
259 0 : struct dcerpc_pipe *test_p;
260 0 : struct dcerpc_binding_handle *test_b;
261 0 : const char *binding = torture_setting_string(tctx, "binding", NULL);
262 :
263 0 : printf("Testing ACLs to allow/prevent users to connect to SAMR");
264 :
265 : /* connect to SAMR */
266 0 : status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
267 0 : if (!NT_STATUS_IS_OK(status)) {
268 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
269 0 : return false;
270 : }
271 :
272 :
273 : /* get the current ACL for the SAMR policy handle */
274 0 : qs.in.handle = &ch;
275 0 : qs.in.sec_info = SECINFO_DACL;
276 0 : qs.out.sdbuf = &sdbuf;
277 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
278 : "QuerySecurity failed");
279 0 : if (!NT_STATUS_IS_OK(qs.out.result)) {
280 0 : printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
281 0 : ret = false;
282 : }
283 :
284 : /* how big is the security descriptor? */
285 0 : 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 0 : sd = sdbuf->sd;
292 0 : ace.type = SEC_ACE_TYPE_ACCESS_DENIED;
293 0 : ace.flags = 0;
294 0 : ace.access_mask = SAMR_ACCESS_CONNECT_TO_SERVER;
295 0 : ace.trustee = *test_sid;
296 0 : status = security_descriptor_dacl_add(sd, &ace);
297 0 : if (!NT_STATUS_IS_OK(status)) {
298 0 : printf("Failed to add ACE to security descriptor\n");
299 0 : ret = false;
300 : }
301 0 : ss.in.handle = &ch;
302 0 : ss.in.sec_info = SECINFO_DACL;
303 0 : ss.in.sdbuf = &sdb;
304 0 : sdb.sd = sd;
305 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetSecurity_r(b, tctx, &ss),
306 : "SetSecurity failed");
307 0 : if (!NT_STATUS_IS_OK(ss.out.result)) {
308 0 : printf("SetSecurity failed - %s\n", nt_errstr(ss.out.result));
309 0 : ret = false;
310 : }
311 :
312 :
313 : /* Try to connect as the test user */
314 0 : status = dcerpc_pipe_connect(tctx,
315 : &test_p, binding, &ndr_table_samr,
316 : test_credentials, tctx->ev, tctx->lp_ctx);
317 0 : if (!NT_STATUS_IS_OK(status)) {
318 0 : printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
319 0 : return false;
320 : }
321 0 : test_b = test_p->binding_handle;
322 :
323 : /* connect to SAMR as the user */
324 0 : status = torture_samr_Connect5(tctx, test_b, SEC_FLAG_MAXIMUM_ALLOWED, &uch);
325 0 : if (!NT_STATUS_IS_OK(status)) {
326 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
327 0 : return false;
328 : }
329 : /* disconnect the user */
330 0 : talloc_free(test_p);
331 :
332 :
333 : /* read the sequrity descriptor back. it should not have changed
334 : * even though samr_SetSecurity returned SUCCESS
335 : */
336 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_QuerySecurity_r(b, tctx, &qs),
337 : "QuerySecurity failed");
338 0 : if (!NT_STATUS_IS_OK(qs.out.result)) {
339 0 : printf("QuerySecurity failed - %s\n", nt_errstr(qs.out.result));
340 0 : ret = false;
341 : }
342 0 : if (sd_size != sdbuf->sd_size) {
343 0 : printf("security descriptor changed\n");
344 0 : ret = false;
345 : }
346 :
347 :
348 0 : status = torture_samr_Close(tctx, b, &ch);
349 0 : if (!NT_STATUS_IS_OK(status)) {
350 0 : printf("Close failed - %s\n", nt_errstr(status));
351 0 : ret = false;
352 : }
353 :
354 0 : if (ret == true) {
355 0 : printf(" OK\n");
356 : }
357 0 : return ret;
358 : }
359 :
360 : /*
361 : * test if the ACLs are enforced for users.
362 : * a normal testuser only gets the rights provided in the 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 0 : 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 0 : NTSTATUS status;
375 0 : struct policy_handle uch;
376 0 : bool ret = true;
377 0 : struct dcerpc_pipe *test_p;
378 0 : struct dcerpc_binding_handle *test_b;
379 0 : const char *binding = torture_setting_string(tctx, "binding", NULL);
380 :
381 0 : printf("Testing if ACLs are enforced for non domain admin users when connecting to SAMR");
382 :
383 :
384 0 : status = dcerpc_pipe_connect(tctx,
385 : &test_p, binding, &ndr_table_samr,
386 : test_credentials, tctx->ev, tctx->lp_ctx);
387 0 : if (!NT_STATUS_IS_OK(status)) {
388 0 : printf("dcerpc_pipe_connect failed: %s\n", nt_errstr(status));
389 0 : return false;
390 : }
391 0 : test_b = test_p->binding_handle;
392 :
393 : /* connect to SAMR as the user */
394 0 : status = torture_samr_Connect5(tctx, test_b, SAMR_ACCESS_SHUTDOWN_SERVER, &uch);
395 0 : if (NT_STATUS_IS_OK(status)) {
396 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
397 0 : return false;
398 : }
399 0 : printf(" OK\n");
400 :
401 : /* disconnect the user */
402 0 : talloc_free(test_p);
403 :
404 0 : 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 0 : static bool test_samr_accessmask_LookupDomain(struct torture_context *tctx,
417 : struct dcerpc_pipe *p)
418 : {
419 0 : NTSTATUS status;
420 0 : struct samr_LookupDomain ld;
421 0 : struct dom_sid2 *sid = NULL;
422 0 : struct policy_handle ch;
423 0 : struct lsa_String dn;
424 0 : int i;
425 0 : uint32_t mask;
426 0 : struct dcerpc_binding_handle *b = p->binding_handle;
427 :
428 0 : printf("Testing which bits in Connect5 accessmask allows us to LookupDomain\n");
429 0 : mask = 1;
430 0 : for (i=0;i<33;i++) {
431 0 : printf("Testing Connect5/LookupDomain with access mask 0x%08x", mask);
432 0 : status = torture_samr_Connect5(tctx, b, mask, &ch);
433 0 : mask <<= 1;
434 :
435 0 : switch (i) {
436 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
442 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
443 0 : return false;
444 : }
445 :
446 0 : ld.in.connect_handle = &ch;
447 0 : ld.in.domain_name = &dn;
448 0 : ld.out.sid = &sid;
449 0 : dn.string = lpcfg_workgroup(tctx->lp_ctx);
450 :
451 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
452 : "LookupDomain failed");
453 0 : if (!NT_STATUS_IS_OK(ld.out.result)) {
454 0 : printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
455 0 : return false;
456 : }
457 :
458 0 : status = torture_samr_Close(tctx, b, &ch);
459 0 : if (!NT_STATUS_IS_OK(status)) {
460 0 : printf("Close failed - %s\n", nt_errstr(status));
461 0 : return false;
462 : }
463 0 : break;
464 0 : default:
465 0 : printf(" expecting to fail");
466 :
467 0 : if (!NT_STATUS_IS_OK(status)) {
468 0 : printf(" OK\n");
469 0 : continue;
470 : }
471 :
472 0 : ld.in.connect_handle = &ch;
473 0 : ld.in.domain_name = &dn;
474 0 : ld.out.sid = &sid;
475 0 : dn.string = lpcfg_workgroup(tctx->lp_ctx);
476 :
477 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
478 : "LookupDomain failed");
479 0 : if(!NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, ld.out.result)) {
480 0 : printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
481 0 : return false;
482 : }
483 :
484 0 : status = torture_samr_Close(tctx, b, &ch);
485 0 : if (!NT_STATUS_IS_OK(status)) {
486 0 : printf("Close failed - %s\n", nt_errstr(status));
487 0 : return false;
488 : }
489 0 : break;
490 : }
491 0 : printf(" OK\n");
492 : }
493 :
494 0 : 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 0 : static bool test_samr_accessmask_OpenDomain(struct torture_context *tctx,
507 : struct dcerpc_pipe *p)
508 : {
509 0 : NTSTATUS status;
510 0 : struct samr_LookupDomain ld;
511 0 : struct dom_sid2 *sid = NULL;
512 0 : struct samr_OpenDomain od;
513 0 : struct policy_handle ch;
514 0 : struct policy_handle dh;
515 0 : struct lsa_String dn;
516 0 : int i;
517 0 : uint32_t mask;
518 0 : struct dcerpc_binding_handle *b = p->binding_handle;
519 :
520 :
521 : /* first we must grab the sid of the domain */
522 0 : status = torture_samr_Connect5(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED, &ch);
523 0 : if (!NT_STATUS_IS_OK(status)) {
524 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
525 0 : return false;
526 : }
527 :
528 0 : ld.in.connect_handle = &ch;
529 0 : ld.in.domain_name = &dn;
530 0 : ld.out.sid = &sid;
531 0 : dn.string = lpcfg_workgroup(tctx->lp_ctx);
532 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &ld),
533 : "LookupDomain failed");
534 0 : if (!NT_STATUS_IS_OK(ld.out.result)) {
535 0 : printf("LookupDomain failed - %s\n", nt_errstr(ld.out.result));
536 0 : return false;
537 : }
538 :
539 :
540 :
541 0 : printf("Testing which bits in Connect5 accessmask allows us to OpenDomain\n");
542 0 : mask = 1;
543 0 : for (i=0;i<33;i++) {
544 0 : printf("Testing Connect5/OpenDomain with access mask 0x%08x", mask);
545 0 : status = torture_samr_Connect5(tctx, b, mask, &ch);
546 0 : mask <<= 1;
547 :
548 0 : switch (i) {
549 0 : 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 0 : if (!NT_STATUS_IS_OK(status)) {
555 0 : printf("Connect5 failed - %s\n", nt_errstr(status));
556 0 : return false;
557 : }
558 :
559 0 : od.in.connect_handle = &ch;
560 0 : od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
561 0 : od.in.sid = sid;
562 0 : od.out.domain_handle = &dh;
563 :
564 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &od),
565 : "OpenDomain failed");
566 0 : if (!NT_STATUS_IS_OK(od.out.result)) {
567 0 : printf("OpenDomain failed - %s\n", nt_errstr(od.out.result));
568 0 : return false;
569 : }
570 :
571 0 : status = torture_samr_Close(tctx, b, &dh);
572 0 : if (!NT_STATUS_IS_OK(status)) {
573 0 : printf("Close failed - %s\n", nt_errstr(status));
574 0 : return false;
575 : }
576 :
577 0 : status = torture_samr_Close(tctx, b, &ch);
578 0 : if (!NT_STATUS_IS_OK(status)) {
579 0 : printf("Close failed - %s\n", nt_errstr(status));
580 0 : return false;
581 : }
582 0 : break;
583 0 : default:
584 0 : printf(" expecting to fail");
585 :
586 0 : if (!NT_STATUS_IS_OK(status)) {
587 0 : printf(" OK\n");
588 0 : continue;
589 : }
590 :
591 0 : status = torture_samr_Close(tctx, b, &ch);
592 0 : if (!NT_STATUS_IS_OK(status)) {
593 0 : printf("Close failed - %s\n", nt_errstr(status));
594 0 : return false;
595 : }
596 0 : break;
597 : }
598 0 : printf(" OK\n");
599 : }
600 :
601 0 : return true;
602 : }
603 :
604 0 : static bool test_samr_connect(struct torture_context *tctx,
605 : struct dcerpc_pipe *p)
606 : {
607 0 : void *testuser;
608 0 : const char *testuser_passwd;
609 0 : struct cli_credentials *test_credentials;
610 0 : bool ret = true;
611 0 : const struct dom_sid *test_sid;
612 0 : struct dcerpc_binding_handle *b = p->binding_handle;
613 :
614 0 : if (torture_setting_bool(tctx, "samba3", false)) {
615 0 : torture_skip(tctx, "Skipping test against Samba 3");
616 : }
617 :
618 : /* create a test user */
619 0 : testuser = torture_create_testuser(tctx, TEST_USER_NAME, lpcfg_workgroup(tctx->lp_ctx),
620 : ACB_NORMAL, &testuser_passwd);
621 0 : if (!testuser) {
622 0 : printf("Failed to create test user\n");
623 0 : return false;
624 : }
625 0 : test_credentials = cli_credentials_init(tctx);
626 0 : cli_credentials_set_workstation(test_credentials, "localhost", CRED_SPECIFIED);
627 0 : cli_credentials_set_domain(test_credentials, lpcfg_workgroup(tctx->lp_ctx),
628 : CRED_SPECIFIED);
629 0 : cli_credentials_set_username(test_credentials, TEST_USER_NAME, CRED_SPECIFIED);
630 0 : cli_credentials_set_password(test_credentials, testuser_passwd, CRED_SPECIFIED);
631 0 : 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 0 : if (!test_samr_connect_user_acl(tctx, b, test_credentials, test_sid)) {
638 0 : 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 0 : if (!test_samr_connect_user_acl_enforced(tctx, b, test_credentials, test_sid)) {
652 0 : ret = false;
653 : }
654 :
655 : /* remove the test user */
656 0 : torture_leave_domain(tctx, testuser);
657 :
658 0 : return ret;
659 : }
660 :
661 2354 : struct torture_suite *torture_rpc_samr_accessmask(TALLOC_CTX *mem_ctx)
662 : {
663 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.accessmask");
664 125 : struct torture_rpc_tcase *tcase;
665 :
666 2354 : tcase = torture_suite_add_rpc_iface_tcase(suite, "samr",
667 : &ndr_table_samr);
668 :
669 2354 : 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 2354 : 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 2354 : 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 2354 : 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 2354 : torture_rpc_tcase_add_test(tcase, "Connect5",
689 : test_samr_accessmask_Connect5);
690 :
691 2354 : return suite;
692 : }
693 :
694 1013 : 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 0 : struct samr_LookupRids r;
700 0 : struct lsa_Strings names;
701 0 : struct samr_Ids types;
702 :
703 1013 : torture_comment(tctx, "Testing LookupRids %d\n", rid);
704 :
705 1013 : r.in.domain_handle = domain_handle;
706 1013 : r.in.num_rids = 1;
707 1013 : r.in.rids = &rid;
708 1013 : r.out.names = &names;
709 1013 : r.out.types = &types;
710 :
711 1013 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupRids_r(b, tctx, &r),
712 : "failed to call samr_LookupRids");
713 1013 : torture_assert_ntstatus_ok(tctx, r.out.result,
714 : "failed to call samr_LookupRids");
715 :
716 1013 : return true;
717 : }
718 :
719 :
720 355 : 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 0 : struct policy_handle user_handle;
727 :
728 355 : torture_comment(tctx, "Testing user %s (%d)\n", u->account_name.string, u->rid);
729 :
730 355 : torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, u->rid),
731 : "failed to call lookuprids");
732 :
733 : {
734 0 : struct samr_OpenUser r;
735 :
736 355 : r.in.domain_handle = domain_handle;
737 355 : r.in.access_mask = access_mask;
738 355 : r.in.rid = u->rid;
739 355 : r.out.user_handle = &user_handle;
740 :
741 355 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenUser_r(b, tctx, &r),
742 : "failed to open user");
743 355 : torture_assert_ntstatus_ok(tctx, r.out.result,
744 : "failed to open user");
745 : }
746 : {
747 0 : struct samr_QueryUserInfo r;
748 0 : union samr_UserInfo *info;
749 355 : uint32_t levels[] = { 16, 21 };
750 0 : int i;
751 :
752 355 : r.in.user_handle = &user_handle;
753 355 : r.out.info = &info;
754 :
755 1065 : for (i=0; i < ARRAY_SIZE(levels); i++) {
756 :
757 710 : r.in.level = levels[i];
758 :
759 710 : torture_comment(tctx, "Testing QueryUserInfo rid: %d level: %d\n",
760 710 : u->rid, r.in.level);
761 :
762 710 : 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 710 : 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 0 : struct samr_GetGroupsForUser r;
770 0 : struct samr_RidWithAttributeArray *rids;
771 :
772 355 : r.in.user_handle = &user_handle;
773 355 : r.out.rids = &rids;
774 :
775 355 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetGroupsForUser_r(b, tctx, &r),
776 : "failed to query groups for user");
777 355 : torture_assert_ntstatus_ok(tctx, r.out.result,
778 : "failed to query groups for user");
779 : }
780 :
781 355 : torture_assert_ntstatus_ok(tctx,
782 : torture_samr_Close(tctx, b, &user_handle),
783 : "failed to close user handle");
784 :
785 355 : return true;
786 : }
787 :
788 343 : 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 0 : struct policy_handle group_handle;
795 :
796 343 : torture_comment(tctx, "Testing group %s (%d)\n", g->name.string, g->idx);
797 :
798 343 : torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, g->idx),
799 : "failed to call lookuprids");
800 : {
801 0 : struct samr_OpenGroup r;
802 :
803 343 : r.in.domain_handle = domain_handle;
804 343 : r.in.access_mask = access_mask;
805 343 : r.in.rid = g->idx;
806 343 : r.out.group_handle = &group_handle;
807 :
808 343 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenGroup_r(b, tctx, &r),
809 : "failed to open group");
810 343 : torture_assert_ntstatus_ok(tctx, r.out.result,
811 : "failed to open group");
812 : }
813 : {
814 0 : struct samr_QueryGroupMember r;
815 0 : struct samr_RidAttrArray *rids;
816 :
817 343 : r.in.group_handle = &group_handle;
818 343 : r.out.rids = &rids;
819 :
820 343 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryGroupMember_r(b, tctx, &r),
821 : "failed to query group member");
822 343 : torture_assert_ntstatus_ok(tctx, r.out.result,
823 : "failed to query group member");
824 :
825 : }
826 :
827 343 : torture_assert_ntstatus_ok(tctx,
828 : torture_samr_Close(tctx, b, &group_handle),
829 : "failed to close group handle");
830 :
831 343 : return true;
832 : }
833 :
834 315 : 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 315 : torture_comment(tctx, "Testing alias %s (%d)\n", a->name.string, a->idx);
840 :
841 315 : torture_assert(tctx, test_LookupRids(tctx, b, domain_handle, a->idx),
842 : "failed to call lookuprids");
843 :
844 : {
845 0 : struct samr_GetAliasMembership r;
846 0 : struct lsa_SidArray sids;
847 0 : struct samr_Ids rids;
848 :
849 315 : ZERO_STRUCT(sids);
850 :
851 315 : r.in.domain_handle = domain_handle;
852 315 : r.in.sids = &sids;
853 315 : r.out.rids = &rids;
854 :
855 315 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_GetAliasMembership_r(b, tctx, &r),
856 : "failed to get alias membership");
857 315 : torture_assert_ntstatus_ok(tctx, r.out.result,
858 : "failed to get alias membership");
859 : }
860 :
861 :
862 315 : return true;
863 : }
864 :
865 5 : 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 0 : struct policy_handle domain_handle;
873 0 : struct dom_sid *domain_sid;
874 :
875 5 : if (!domain_name) {
876 0 : struct samr_EnumDomains r;
877 0 : uint32_t resume_handle;
878 0 : struct samr_SamArray *sam;
879 0 : uint32_t num_entries;
880 0 : int i;
881 :
882 0 : r.in.connect_handle = connect_handle;
883 0 : r.in.buf_size = 0xffff;
884 0 : r.in.resume_handle = &resume_handle;
885 0 : r.out.sam = &sam;
886 0 : r.out.num_entries = &num_entries;
887 0 : r.out.resume_handle = &resume_handle;
888 :
889 0 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomains_r(b, tctx, &r),
890 : "failed to enum domains");
891 0 : torture_assert_ntstatus_ok(tctx, r.out.result,
892 : "failed to enum domains");
893 :
894 0 : torture_assert_int_equal(tctx, num_entries, 2,
895 : "unexpected number of domains");
896 :
897 0 : torture_assert(tctx, sam,
898 : "no domain pointer returned");
899 :
900 0 : for (i=0; i < sam->count; i++) {
901 0 : if (!strequal(sam->entries[i].name.string, "builtin")) {
902 0 : domain_name = sam->entries[i].name.string;
903 0 : break;
904 : }
905 : }
906 :
907 0 : torture_assert(tctx, domain_name,
908 : "no domain found other than builtin found");
909 : }
910 :
911 : {
912 0 : struct samr_LookupDomain r;
913 0 : struct dom_sid2 *sid;
914 0 : struct lsa_String name;
915 :
916 5 : name.string = talloc_strdup(tctx, domain_name);
917 :
918 5 : r.in.connect_handle = connect_handle;
919 5 : r.in.domain_name = &name;
920 5 : r.out.sid = &sid;
921 :
922 5 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_LookupDomain_r(b, tctx, &r),
923 : "failed to lookup domain");
924 5 : torture_assert_ntstatus_ok(tctx, r.out.result,
925 : "failed to lookup domain");
926 :
927 5 : domain_sid = dom_sid_dup(tctx, sid);
928 : }
929 :
930 : {
931 0 : struct samr_OpenDomain r;
932 :
933 5 : r.in.connect_handle = connect_handle;
934 5 : r.in.access_mask = access_mask;
935 5 : r.in.sid = domain_sid;
936 5 : r.out.domain_handle = &domain_handle;
937 :
938 5 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_OpenDomain_r(b, tctx, &r),
939 : "failed to open domain");
940 5 : torture_assert_ntstatus_ok(tctx, r.out.result,
941 : "failed to open domain");
942 :
943 : }
944 :
945 : {
946 0 : struct samr_QueryDomainInfo r;
947 0 : union samr_DomainInfo *info;
948 5 : uint32_t levels[] = { 1, 2, 8, 12 };
949 0 : int i;
950 :
951 5 : r.in.domain_handle = &domain_handle;
952 5 : r.out.info = &info;
953 :
954 25 : for (i=0; i < ARRAY_SIZE(levels); i++) {
955 :
956 20 : r.in.level = levels[i];
957 :
958 20 : 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 20 : 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 5 : *domain_handle_p = domain_handle;
967 :
968 5 : return true;
969 : }
970 :
971 5 : static void get_query_dispinfo_params(int loop_count,
972 : uint32_t *max_entries,
973 : uint32_t *buf_size)
974 : {
975 5 : switch(loop_count) {
976 5 : case 0:
977 5 : *max_entries = 512;
978 5 : *buf_size = 16383;
979 5 : break;
980 0 : case 1:
981 0 : *max_entries = 1024;
982 0 : *buf_size = 32766;
983 0 : break;
984 0 : case 2:
985 0 : *max_entries = 2048;
986 0 : *buf_size = 65532;
987 0 : break;
988 0 : case 3:
989 0 : *max_entries = 4096;
990 0 : *buf_size = 131064;
991 0 : break;
992 0 : default: /* loop_count >= 4 */
993 0 : *max_entries = 4096;
994 0 : *buf_size = 131071;
995 0 : break;
996 : }
997 5 : }
998 :
999 :
1000 5 : 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 0 : struct samr_QueryDisplayInfo r;
1007 0 : uint32_t total_size;
1008 0 : uint32_t returned_size;
1009 0 : union samr_DispInfo info;
1010 5 : int loop_count = 0;
1011 :
1012 5 : r.in.domain_handle = domain_handle;
1013 5 : r.in.level = 1;
1014 5 : r.in.start_idx = 0;
1015 :
1016 5 : r.out.total_size = &total_size;
1017 5 : r.out.returned_size = &returned_size;
1018 5 : r.out.info = &info;
1019 :
1020 0 : do {
1021 0 : int i;
1022 :
1023 5 : r.in.max_entries = 0xffff;
1024 5 : r.in.buf_size = 0xffff;
1025 :
1026 5 : get_query_dispinfo_params(loop_count,
1027 : &r.in.max_entries,
1028 : &r.in.buf_size);
1029 :
1030 5 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryDisplayInfo_r(b, tctx, &r),
1031 : "QueryDisplayInfo failed");
1032 5 : if (NT_STATUS_IS_ERR(r.out.result)) {
1033 0 : torture_assert_ntstatus_ok(tctx, r.out.result,
1034 : "failed to call QueryDisplayInfo");
1035 : }
1036 :
1037 360 : for (i=0; i < info.info1.count; i++) {
1038 355 : torture_assert(tctx,
1039 : test_user(tctx, b, domain_handle, access_mask, &info.info1.entries[i]),
1040 : "failed to test user");
1041 : }
1042 5 : loop_count++;
1043 5 : r.in.start_idx += info.info1.count;
1044 :
1045 5 : } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1046 : }
1047 :
1048 5 : return true;
1049 : }
1050 :
1051 5 : 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 0 : struct samr_EnumDomainGroups r;
1058 5 : uint32_t resume_handle = 0;
1059 0 : struct samr_SamArray *sam;
1060 0 : uint32_t num_entries;
1061 :
1062 5 : r.in.domain_handle = domain_handle;
1063 5 : r.in.resume_handle = &resume_handle;
1064 5 : r.in.max_size = 0xFFFF;
1065 :
1066 5 : r.out.sam = &sam;
1067 5 : r.out.num_entries = &num_entries;
1068 5 : r.out.resume_handle = &resume_handle;
1069 :
1070 0 : do {
1071 0 : int i;
1072 :
1073 5 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainGroups_r(b, tctx, &r),
1074 : "EnumDomainGroups failed");
1075 5 : if (NT_STATUS_IS_ERR(r.out.result)) {
1076 0 : torture_assert_ntstatus_ok(tctx, r.out.result,
1077 : "failed to call EnumDomainGroups");
1078 : }
1079 :
1080 348 : for (i=0; i < num_entries; i++) {
1081 343 : torture_assert(tctx,
1082 : test_samr_group(tctx, b, domain_handle, access_mask, &sam->entries[i]),
1083 : "failed to test group");
1084 : }
1085 :
1086 5 : } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1087 : }
1088 :
1089 5 : return true;
1090 : }
1091 :
1092 5 : 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 0 : struct samr_EnumDomainAliases r;
1099 5 : uint32_t resume_handle = 0;
1100 0 : struct samr_SamArray *sam;
1101 0 : uint32_t num_entries;
1102 :
1103 5 : r.in.domain_handle = domain_handle;
1104 5 : r.in.resume_handle = &resume_handle;
1105 5 : r.in.max_size = 0xFFFF;
1106 :
1107 5 : r.out.sam = &sam;
1108 5 : r.out.num_entries = &num_entries;
1109 5 : r.out.resume_handle = &resume_handle;
1110 :
1111 0 : do {
1112 0 : int i;
1113 :
1114 5 : torture_assert_ntstatus_ok(tctx, dcerpc_samr_EnumDomainAliases_r(b, tctx, &r),
1115 : "EnumDomainAliases failed");
1116 5 : if (NT_STATUS_IS_ERR(r.out.result)) {
1117 0 : torture_assert_ntstatus_ok(tctx, r.out.result,
1118 : "failed to call EnumDomainAliases");
1119 : }
1120 :
1121 320 : for (i=0; i < num_entries; i++) {
1122 315 : torture_assert(tctx,
1123 : test_samr_alias(tctx, b, domain_handle, &sam->entries[i]),
1124 : "failed to test alias");
1125 : }
1126 :
1127 5 : } while (NT_STATUS_EQUAL(r.out.result, STATUS_MORE_ENTRIES));
1128 : }
1129 :
1130 5 : return true;
1131 : }
1132 :
1133 5 : static bool torture_rpc_samr_workstation_query(struct torture_context *tctx,
1134 : struct dcerpc_pipe *p,
1135 : struct cli_credentials *machine_credentials)
1136 : {
1137 0 : struct policy_handle connect_handle;
1138 0 : struct policy_handle domain_handle;
1139 5 : struct dcerpc_binding_handle *b = p->binding_handle;
1140 :
1141 5 : 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 5 : 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 5 : torture_assert(tctx,
1153 : test_samr_users(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1154 : &domain_handle),
1155 : "failed to test users");
1156 :
1157 5 : torture_assert(tctx,
1158 : test_samr_groups(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1159 : &domain_handle),
1160 : "failed to test groups");
1161 :
1162 5 : torture_assert(tctx,
1163 : test_samr_aliases(tctx, b, SEC_FLAG_MAXIMUM_ALLOWED,
1164 : &domain_handle),
1165 : "failed to test aliases");
1166 :
1167 5 : torture_assert_ntstatus_ok(tctx,
1168 : torture_samr_Close(tctx, b, &domain_handle),
1169 : "failed to close domain handle");
1170 :
1171 5 : torture_assert_ntstatus_ok(tctx,
1172 : torture_samr_Close(tctx, b, &connect_handle),
1173 : "failed to close connect handle");
1174 :
1175 5 : 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 2354 : struct torture_suite *torture_rpc_samr_workstation_auth(TALLOC_CTX *mem_ctx)
1185 : {
1186 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "samr.machine.auth");
1187 125 : struct torture_rpc_tcase *tcase;
1188 :
1189 2354 : tcase = torture_suite_add_machine_workstation_rpc_iface_tcase(suite, "samr",
1190 : &ndr_table_samr,
1191 : TEST_MACHINENAME);
1192 :
1193 2354 : torture_rpc_tcase_add_test_creds(tcase, "workstation_query",
1194 : torture_rpc_samr_workstation_query);
1195 :
1196 2354 : return suite;
1197 : }
|