s3:ntlm_auth: make logs more consistent with length check
[Samba.git] / python / samba / tests / security_descriptors.py
blobb3dd2ca90512eed1102d23ada74d92fb7039b8e1
1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Volker Lendecke <vl@samba.org> 2021
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """These tests compare Windows security descriptors with Samba
19 descriptors derived from the same SDDL.
21 They use json and json.gz files in libcli/security/tests/data.
22 """
24 from samba.dcerpc import security
25 from samba.ndr import ndr_pack, ndr_unpack, ndr_print
26 from samba.tests import TestCase, DynamicTestCase
27 from samba.colour import colourdiff
28 from hashlib import md5
29 import gzip
31 import json
32 from pathlib import Path
34 TEST_DIR = Path(__name__).parent.parent.parent / 'libcli/security/tests/data'
37 class SDDLvsDescriptorBase(TestCase):
38 """These tests have no explicit cases and no inline data. The actual
39 data is kept in JSON files in libcli/security/tests/data, so that
40 it easy to share those files with Windows. To control what tests
41 are run, set the `json_file` attribute in subclasses, and/or add a
42 filter_test_cases class method.
43 """
44 maxDiff = 10000
45 json_file = None
46 munge_to_v4 = True
47 domain_sid = security.dom_sid("S-1-5-21-2457507606-2709100691-398136650")
48 failure_json = None
49 success_json = None
51 @classmethod
52 def filter_test_cases(cls, data):
53 """Filter out some cases before running the tests.
54 Like this, for example:
55 return {k:v for k, v in data.items() if len(k) < 200 and
56 '(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)' in k}
57 """
58 return data
60 @classmethod
61 def setUpDynamicTestCases(cls):
62 try:
63 with gzip.open(cls.json_file, 'rt') as f:
64 data = json.load(f)
65 except Exception:
66 with open(cls.json_file) as f:
67 data = json.load(f)
69 data = cls.filter_test_cases(data)
70 i = 0
71 for sddl, sdl in data.items():
72 i += 1
73 name = f'{i:03}-{sddl}'
74 if len(name) > 130:
75 tag = md5(sddl.encode()).hexdigest()[:10]
76 name = f"{name[:100]}+{len(name) - 100}-more-characters-{tag}"
77 cls.generate_dynamic_test('test_sddl_vs_sd', name, sddl, sdl)
79 if cls.failure_json:
80 cls.failures = {}
81 cls.failure_file = open(cls.failure_json, 'w')
82 cls.addClassCleanup(json.dump, cls.failures, cls.failure_file)
83 if cls.success_json:
84 cls.successes = {}
85 cls.success_file = open(cls.success_json, 'w')
86 cls.addClassCleanup(json.dump, cls.successes, cls.success_file)
88 def _test_sddl_vs_sd_with_args(self, sddl, sdl):
89 sdb_win = bytes(sdl)
90 try:
91 sd_sam = security.descriptor.from_sddl(sddl, self.domain_sid)
92 except (TypeError, ValueError, security.SDDLValueError) as e:
93 try:
94 sd_win = ndr_unpack(security.descriptor, sdb_win)
95 win_ndr_print = ndr_print(sd_win)
96 except RuntimeError as e2:
97 win_ndr_print = f"not parseable: {e2}"
98 if self.failure_json:
99 self.failures[sddl] = sdl
101 self.fail(f"failed to parse {sddl} into SD: {e}")
103 try:
104 sdb_sam = ndr_pack(sd_sam)
105 except RuntimeError as e:
106 if self.failure_json:
107 self.failures[sddl] = sdl
108 self.fail(f"failed to pack samba SD from {sddl} into bytes: {e}\n"
109 f"{ndr_print(sd_sam)}")
111 try:
112 sd_win = ndr_unpack(security.descriptor, sdb_win)
113 except RuntimeError as e:
114 if self.failure_json:
115 self.failures[sddl] = sdl
116 self.fail(f"could not unpack windows descriptor for {sddl}: {e}")
118 if self.munge_to_v4:
119 # Force the ACL revisions to match Samba. Windows seems to
120 # use the lowest possible revision, while Samba uses
121 # ACL_REVISION_DS when generating from SDDL. The _DS
122 # version allows more ACE types, but is otherwise the same.
124 # MS-DTYP 2.4.5 ACL:
126 # ACL_REVISION 0x02
128 # When set to 0x02, only AceTypes 0x00, 0x01,
129 # 0x02, 0x03, 0x11, 0x12, and 0x13 can be present in the ACL.
130 # An AceType of 0x11 is used for SACLs but not for DACLs. For
131 # more information about ACE types, see section 2.4.4.1.
133 # ACL_REVISION_DS 0x04
135 # When set to 0x04, AceTypes 0x05, 0x06, 0x07, 0x08, and 0x11
136 # are allowed. ACLs of revision 0x04 are applicable only to
137 # directory service objects. An AceType of 0x11 is used for
138 # SACLs but not for DACLs.
140 # 5, 6, 7, 8 are object ACES.
141 if sd_win.dacl:
142 sd_win.dacl.revision = 4
143 if sd_win.sacl:
144 sd_win.sacl.revision = 4
146 if (sd_win != sd_sam):
147 if self.failure_json:
148 self.failures[sddl] = sdl
149 self.fail(f"Descriptors differ for {sddl}")
151 if self.success_json:
152 self.successes[sddl] = sdl
155 @DynamicTestCase
156 class SDDLvsDescriptorShortOrdinaryAcls(SDDLvsDescriptorBase):
157 """These are not conditional ACEs or resource attribute aces, the SDDL
158 is less than 1000 characters long, and success is expected.
160 json_file = TEST_DIR / 'short-ordinary-acls.json.gz'
163 @DynamicTestCase
164 class SDDLvsDescriptorRegistryObjectRights(SDDLvsDescriptorBase):
165 """We'll fail these because we don't recognise 'KA' and related object
166 rights strings that are used for registry objects."""
167 json_file = TEST_DIR / 'registry-object-rights.json'
170 @DynamicTestCase
171 class SDDLvsDescriptorOverSizeAcls(SDDLvsDescriptorBase):
172 """These are ordinary ACLs that contain duplicate ACEs (e.g.
173 'D:P(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)(D;;;;;MP)'). Due to a
174 peculiarity in Windows, the ACL structures generated have extra
175 trailing zero bytes. Due to a peculiarity in the way Samba reads
176 an ACL (namely, it assumes an ACL will be just big enough for its
177 ACEs), these cannot currently be parsed by Samba.
179 json_file = TEST_DIR / 'oversize-acls.json'
182 @DynamicTestCase
183 class SDDLvsDescriptorShortConditionalAndResourceAceSuccesses(SDDLvsDescriptorBase):
184 """These contain conditional ACEs or resource attribute aces, the SDDL
185 is less than 1000 characters long, and success is expected.
187 json_file = TEST_DIR / 'short-conditional-and-resource-aces-successes.json.gz'
190 @DynamicTestCase
191 class SDDLvsDescriptorShortConditionalAndResourceAcesTxIntegers(SDDLvsDescriptorBase):
192 """These contain resource attribute aces in the form
194 (RA;;;;;WD;("foo",TX,0x0,0077,00,...))
196 where the numbers after the 0x0 flags like "0077" are interpreted
197 by Windows as if they are octet strings. This is not documented
198 and not supported by Samba.
200 json_file = TEST_DIR / 'short-conditional-and-resource-aces-tx-int.json.gz'
203 @DynamicTestCase
204 class SDDLvsDescriptorShortOrdinaryAclsNoMungeV4(SDDLvsDescriptorBase):
205 """These ones have revision 2 ACLs (NT4), but Samba's SDDL only writes
206 revision 4 ACLs (which are otherwise identical).
208 munge_to_v4 = False
209 json_file = TEST_DIR / 'short-ordinary-acls-v2.json.gz'
212 @DynamicTestCase
213 class SDDLvsDescriptorCollectedConditionalAces(SDDLvsDescriptorBase):
214 """Some conditional ACE strings that have collected up.
216 json_file = TEST_DIR / 'conditional_aces.txt.json'