selftest: Add test for ndr_size_union() faulting on a NULL pointer
[amitay/samba.git] / python / samba / tests / blackbox / ndrdump.py
1 # Blackbox tests for ndrdump
2 # Copyright (C) 2008 Andrew Tridgell <tridge@samba.org>
3 # Copyright (C) 2008 Andrew Bartlett <abartlet@samba.org>
4 # Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
5 # based on test_smbclient.sh
6
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20
21 from __future__ import print_function
22 """Blackbox tests for ndrdump."""
23
24 import os
25 from samba.tests import BlackboxTestCase, BlackboxProcessError
26
27 for p in ["../../../../../source4/librpc/tests",
28           "../../../../../librpc/tests"]:
29     data_path_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), p))
30     print(data_path_dir)
31     if os.path.exists(data_path_dir):
32         break
33
34
35 class NdrDumpTests(BlackboxTestCase):
36     """Blackbox tests for ndrdump."""
37
38     def data_path(self, name):
39         return os.path.join(data_path_dir, name)
40
41     def test_ndrdump_with_in(self):
42         self.check_run(("ndrdump samr samr_CreateUser in %s" %
43                        (self.data_path("samr-CreateUser-in.dat"))))
44
45     def test_ndrdump_with_out(self):
46         self.check_run(("ndrdump samr samr_CreateUser out %s" %
47                        (self.data_path("samr-CreateUser-out.dat"))))
48
49     def test_ndrdump_context_file(self):
50         self.check_run(
51             ("ndrdump --context-file %s samr samr_CreateUser out %s" %
52                 (self.data_path("samr-CreateUser-in.dat"),
53                 self.data_path("samr-CreateUser-out.dat"))))
54
55     def test_ndrdump_with_validate(self):
56         self.check_run(("ndrdump --validate samr samr_CreateUser in %s" %
57                        (self.data_path("samr-CreateUser-in.dat"))))
58
59     def test_ndrdump_with_hex_decode_function(self):
60         self.check_run(
61             ("ndrdump dns decode_dns_name_packet in --hex-input %s" %
62                 self.data_path("dns-decode_dns_name_packet-hex.dat")))
63
64     def test_ndrdump_with_hex_struct_name(self):
65         expected = open(self.data_path("dns-decode_dns_name_packet-hex.txt")).read()
66         try:
67             actual = self.check_output(
68                 "ndrdump dns dns_name_packet struct --hex-input %s" %
69                 self.data_path("dns-decode_dns_name_packet-hex.dat"))
70         except BlackboxProcessError as e:
71             self.fail(e)
72
73         # check_output will return bytes
74         # convert expected to bytes for python 3
75         self.assertEqual(actual, expected.encode('utf-8'))
76
77     def test_ndrdump_with_binary_struct_name(self):
78         # Prefix of the expected unparsed PAC data (without times, as
79         # these vary by host)
80         expected = '''pull returned Success
81     PAC_DATA: struct PAC_DATA
82         num_buffers              : 0x00000005 (5)
83         version                  : 0x00000000 (0)
84         buffers: ARRAY(5)'''
85         try:
86             actual = self.check_output(
87                 "ndrdump krb5pac PAC_DATA struct %s" %
88                 self.data_path("krb5pac-PAC_DATA.dat"))
89         except BlackboxProcessError as e:
90             self.fail(e)
91
92         # check_output will return bytes
93         # convert expected to bytes for python 3
94         self.assertEqual(actual[:len(expected)],
95                          expected.encode('utf-8'))
96         self.assertTrue(actual.endswith(b"dump OK\n"))
97
98     def test_ndrdump_with_binary_struct_number(self):
99         expected = '''pull returned Success
100     GUID                     : 33323130-3534-3736-3839-616263646566
101 dump OK
102 '''
103         try:
104             actual = self.check_output(
105                 "ndrdump misc 0 struct %s" %
106                 self.data_path("misc-GUID.dat"))
107         except BlackboxProcessError as e:
108             self.fail(e)
109
110         # check_output will return bytes
111         # convert expected to bytes for python 3
112         self.assertEqual(actual, expected.encode('utf-8'))
113
114     def test_ndrdump_with_enum_not_struct(self):
115         expected = '''Public structure 'netr_SchannelType' not found
116 '''
117         try:
118             actual = self.check_exit_code(
119                 "ndrdump misc netr_SchannelType --input=x struct",
120                 1)
121         except BlackboxProcessError as e:
122             self.fail(e)
123
124         # check_output will return bytes
125         # convert expected to bytes for python 3
126         self.assertEqual(actual, expected.encode('utf-8'))
127
128     def test_ndrdump_input_cmdline_short_struct_name(self):
129         expected = '''pull returned Buffer Size Error
130 '''
131         try:
132             actual = self.check_exit_code(
133                 "ndrdump -d0 misc GUID struct --input=abcdefg", 2)
134         except BlackboxProcessError as e:
135             self.fail(e)
136
137         # check_output will return bytes
138         # convert expected to bytes for python 3
139         self.assertEqual(actual, expected.encode('utf-8'))
140
141     def test_ndrdump_input_cmdline_short_struct_name_dump(self):
142         expected = '''pull returned Buffer Size Error
143 6 bytes consumed
144 [0000] 61 62 63 64 65 66 67                               abcdefg ''' \
145         '''
146 '''
147         try:
148             actual = self.check_exit_code(
149                 "ndrdump -d0 misc GUID struct --input=abcdefg --dump-data", 2)
150         except BlackboxProcessError as e:
151             self.fail(e)
152
153         # check_output will return bytes
154         # convert expected to bytes for python 3
155         self.assertEqual(actual, expected.encode('utf-8'))
156
157     def test_ndrdump_input_cmdline_short_struct_name_print_fail(self):
158         expected = '''pull returned Buffer Size Error
159 6 bytes consumed
160 [0000] 61 62 63 64 65 66 67                               abcdefg ''' \
161         '''
162 WARNING! 1 unread bytes
163 [0000] 67                                                 g ''' \
164     '''
165 WARNING: pull of GUID was incomplete, therefore the parse below may SEGFAULT
166     GUID                     : 64636261-6665-0000-0000-000000000000
167 dump of failed-to-parse GUID complete
168 '''
169         try:
170             actual = self.check_exit_code(
171                 "ndrdump -d0 misc GUID struct --input=abcdefg --dump-data --print-after-parse-failure", 2)
172         except BlackboxProcessError as e:
173             self.fail(e)
174
175         # check_output will return bytes
176         # convert expected to bytes for python 3
177         self.assertEqual(actual, expected.encode('utf-8'))
178
179     def test_ndrdump_fuzzed_clusapi_QueryAllValues(self):
180         expected = b'''pull returned Success
181 WARNING! 53 unread bytes
182 [0000] 00 FF 00 00 FF 00 00 00   00 09 00 00 00 08 00 33   ........ .......3
183 [0010] 33 32 37 36 32 36 39 33   32 37 36 38 34 01 00 00   32762693 27684...
184 [0020] 80 32 0D FF 00 00 FF 00   00 00 00 08 00 00 00 1C   .2...... ........
185 [0030] F1 29 08 00 00                                     .)... ''' \
186         b'''
187     clusapi_QueryAllValues: struct clusapi_QueryAllValues
188         out: struct clusapi_QueryAllValues
189             pcbData                  : *
190                 pcbData                  : 0x01000000 (16777216)
191             ppData                   : *
192                 ppData: ARRAY(1)
193                     ppData                   : NULL
194             rpc_status               : *
195                 rpc_status               : WERR_OK
196             result                   : WERR_NOT_ENOUGH_MEMORY
197 dump OK
198 '''
199         try:
200             actual = self.check_output(
201                 'ndrdump clusapi clusapi_QueryAllValues out ' +\
202                 '--base64-input --input=' +\
203                 'AAAAAQEAAAAAAAAAAAAAAAgAAAAA/wAA/wAAAAAJAAAACAAzMzI3NjI2OTMyNzY4NAEAAIAyDf8AAP8AAAAACAAAABzxKQgAAA==')
204         except BlackboxProcessError as e:
205             self.fail(e)
206         self.assertEqual(actual, expected)
207
208     def test_ndrdump_fuzzed_IOXIDResolver_ResolveOxid(self):
209         expected = '''pull returned Character Conversion Error
210 '''
211         try:
212             actual = self.check_exit_code(
213                 'ndrdump IOXIDResolver ResolveOxid out ' +\
214                 '--base64-input --input=' +\
215                 'c87PMf7CBAUAAAAADgQMBASjfPqKw0KPld6DY87PMfQ=',
216                 2)
217         except BlackboxProcessError as e:
218             self.fail(e)
219         self.assertRegex(actual.decode('utf8'), expected + "$")
220
221     def test_ndrdump_fuzzed_IOXIDResolver_ResolveOxid2(self):
222         expected = '''pull returned Buffer Size Error
223 '''
224         try:
225             actual = self.check_exit_code(
226                 'ndrdump IOXIDResolver ResolveOxid2 out ' +\
227                 '--base64-input --input=' +\
228                 'AAAAAQ0K9Q0AAAAAAAAAA6ampqampqampqampqampqampqampqamNAAAAAAtNDQ=',
229                 2)
230         except BlackboxProcessError as e:
231             self.fail(e)
232         self.assertRegex(actual.decode('utf8'), expected + "$")
233
234     def test_ndrdump_fuzzed_IOXIDResolver_ServerAlive2(self):
235         expected = b'''pull returned Success
236 WARNING! 46 unread bytes
237 [0000] 0D 36 0A 0A 0A 0A 0A 00   00 00 00 00 00 00 03 00   .6...... ........
238 [0010] 00 00 01 00 00 33 39 36   31 36 31 37 37 36 38 34   .....396 16177684
239 [0020] 32 34 FC 85 AC 49 0B 61   87 0A 0A 0A F5 00         24...I.a ......
240     ServerAlive: struct ServerAlive
241         out: struct ServerAlive
242             result                   : DOS code 0x01000000
243 dump OK
244 '''
245         try:
246             actual = self.check_output(
247                 'ndrdump IOXIDResolver ServerAlive out ' +\
248                 '--base64-input --input=' +\
249                 'AAAAAQ02CgoKCgoAAAAAAAAAAwAAAAEAADM5NjE2MTc3Njg0MjT8haxJC2GHCgoK9QA=')
250         except BlackboxProcessError as e:
251             self.fail(e)
252         self.assertEqual(actual, expected)
253
254     def test_ndrdump_fuzzed_IRemoteActivation_RemoteActivation(self):
255         expected = '''pull returned Buffer Size Error
256 '''
257         try:
258             actual = self.check_exit_code(
259                 'ndrdump IRemoteActivation RemoteActivation out ' +\
260                 '--base64-input --input=' +\
261                 'AAAAAQAAAAAAAABKAAD/AAAAAP4AAAAAAAAASgAAAAAAAAABIiIjIiIiIiIiIiIiIiMiAAAAAAD/AAAAAAAA',
262                 2)
263         except BlackboxProcessError as e:
264             self.fail(e)
265         self.assertRegex(actual.decode('utf8'), expected + "$")
266
267     def test_ndrdump_fuzzed_ntlmsssp_AUTHENTICATE_MESSAGE(self):
268         expected = open(self.data_path("fuzzed_ntlmssp-AUTHENTICATE_MESSAGE.txt")).read()
269         try:
270             actual = self.check_output(
271                 "ndrdump ntlmssp AUTHENTICATE_MESSAGE struct --base64-input %s --validate" %
272                 self.data_path("fuzzed_ntlmssp-AUTHENTICATE_MESSAGE.b64.txt"))
273         except BlackboxProcessError as e:
274             self.fail(e)
275         # check_output will return bytes
276         # convert expected to bytes for python 3
277         self.assertEqual(actual, expected.encode('utf-8'))
278
279     def test_ndrdump_fuzzed_PackagesBlob(self):
280         expected = 'ndr_pull_string: ndr_pull_error\\(Buffer Size Error\\):'
281         command = (
282             "ndrdump drsblobs package_PackagesBlob struct --input='aw=='"
283             " --base64-input")
284         try:
285             actual = self.check_exit_code(command, 2)
286         except BlackboxProcessError as e:
287             self.fail(e)
288         # check_output will return bytes
289         # convert expected to bytes for python 3
290         self.assertRegex(actual.decode('utf8'), expected)
291
292     def test_ndrdump_fuzzed_drsuapi_DsAddEntry_1(self):
293         expected = open(self.data_path("fuzzed_drsuapi_DsAddEntry_1.txt")).read()
294         try:
295             actual = self.check_output(
296                 "ndrdump drsuapi drsuapi_DsAddEntry in --base64-input --validate %s" %
297                 self.data_path("fuzzed_drsuapi_DsAddEntry_1.b64.txt"))
298         except BlackboxProcessError as e:
299             self.fail(e)
300         # check_output will return bytes
301         # convert expected to bytes for python 3
302         self.assertEqual(actual, expected.encode('utf-8'))
303
304     def test_ndrdump_fuzzed_drsuapi_DsReplicaAttribute(self):
305         expected = open(self.data_path("fuzzed_drsuapi_DsReplicaAttribute.txt")).read()
306         try:
307             actual = self.check_output(
308                 "ndrdump drsuapi drsuapi_DsReplicaAttribute struct --base64-input --validate %s" %
309                 self.data_path("fuzzed_drsuapi_DsReplicaAttribute.b64.txt"))
310         except BlackboxProcessError as e:
311             self.fail(e)
312         # check_output will return bytes
313         # convert expected to bytes for python 3
314         self.assertEqual(actual, expected.encode('utf-8'))
315
316     # This is a good example of a union with an empty default
317     # and no buffers to parse.
318     def test_ndrdump_fuzzed_spoolss_EnumForms(self):
319         expected_head = b'''pull returned Success
320 WARNING! 2 unread bytes
321 [0000] 00 00                                              .. ''' b'''
322     spoolss_EnumForms: struct spoolss_EnumForms
323         out: struct spoolss_EnumForms
324             count                    : *
325                 count                    : 0x00000100 (256)
326             info                     : *
327                 info                     : *
328                     info: ARRAY(256)
329                         info                     : union spoolss_FormInfo(case 0)
330                         info                     : union spoolss_FormInfo(case 0)
331 '''
332         expected_tail = b'''info                     : union spoolss_FormInfo(case 0)
333                         info                     : union spoolss_FormInfo(case 0)
334                         info                     : union spoolss_FormInfo(case 0)
335                         info                     : union spoolss_FormInfo(case 0)
336                         info                     : union spoolss_FormInfo(case 0)
337                         info                     : union spoolss_FormInfo(case 0)
338             needed                   : *
339                 needed                   : 0x00000000 (0)
340             result                   : DOS code 0xa9a9a900
341 dump OK
342 '''
343         try:
344             actual = self.check_output(
345                 "ndrdump spoolss spoolss_EnumForms out --base64-input " +\
346                 "--input AAAAAQAAAAAAAAAAAAEAAACpqakAAA="
347                 )
348         except BlackboxProcessError as e:
349             self.fail(e)
350         self.assertEqual(actual[:len(expected_head)],
351                          expected_head)
352         self.assertTrue(actual.endswith(expected_tail))
353
354     # This is a good example of a union with scalars and buffers
355     def test_ndrdump_xattr_NTACL(self):
356
357         expected_head =  open(self.data_path("xattr_NTACL.txt")).read().encode('utf8')
358         expected_tail = b'''dump OK
359 '''
360         try:
361             actual = self.check_output(
362                 "ndrdump xattr xattr_NTACL struct --hex-input %s --validate" %
363                 self.data_path("xattr_NTACL.dat"))
364         except BlackboxProcessError as e:
365             self.fail(e)
366
367         self.assertEqual(actual[:len(expected_head)],
368                          expected_head)
369         self.assertTrue(actual.endswith(expected_tail))
370
371     # Test a --validate push of a NULL union pointer
372     def test_ndrdump_fuzzed_NULL_union_PAC_BUFFER(self):
373         expected = b'''pull returned Success
374 WARNING! 13 unread bytes
375 [0000] F5 FF 00 3C 3C 25 FF 70   16 1F A0 12 84            ...<<%.p .....
376     PAC_BUFFER: struct PAC_BUFFER
377         type                     : UNKNOWN_ENUM_VALUE (1094251328)
378         _ndr_size                : 0x048792c6 (75993798)
379         info                     : NULL
380         _pad                     : 0x06000000 (100663296)
381 push returned Success
382 pull returned Success
383     PAC_BUFFER: struct PAC_BUFFER
384         type                     : UNKNOWN_ENUM_VALUE (1094251328)
385         _ndr_size                : 0x00000000 (0)
386         info                     : NULL
387         _pad                     : 0x00000000 (0)
388 WARNING! orig bytes:29 validated pushed bytes:16
389 WARNING! orig and validated differ at byte 0x04 (4)
390 WARNING! orig byte[0x04] = 0xC6 validated byte[0x04] = 0x00
391 dump OK
392 '''
393         try:
394             actual = self.check_output(
395                 "ndrdump krb5pac PAC_BUFFER struct --validate --input " +\
396                 "QPM4QcaShwQAAAAAAAAABvX/ADw8Jf9wFh+gEoQ= --base64-input")
397         except BlackboxProcessError as e:
398             self.fail(e)
399
400         self.assertEqual(actual, expected)