1#!/usr/bin/env python3
2# group: rw
3#
4# Test ssh image creation
5#
6# Copyright (C) 2018 Red Hat, Inc.
7#
8# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program.  If not, see <http://www.gnu.org/licenses/>.
22#
23
24import iotests
25import subprocess
26import re
27
28iotests.script_initialize(
29    supported_fmts=['raw'],
30    supported_protocols=['ssh'],
31)
32
33def filter_hash(qmsg):
34    def _filter(key, value):
35        if key == 'hash' and re.match('[0-9a-f]+', value):
36            return 'HASH'
37        return value
38    return iotests.filter_qmp(qmsg, _filter)
39
40def blockdev_create(vm, options):
41    vm.blockdev_create(options, filters=[iotests.filter_qmp_testfiles, filter_hash])
42
43with iotests.FilePath('t.img') as disk_path, \
44     iotests.VM() as vm:
45
46    remote_path = iotests.remote_filename(disk_path)
47
48    #
49    # Successful image creation (defaults)
50    #
51    iotests.log("=== Successful image creation (defaults) ===")
52    iotests.log("")
53
54    vm.launch()
55    blockdev_create(vm, { 'driver': 'ssh',
56                          'location': {
57                              'path': disk_path,
58                              'server': {
59                                  'host': '127.0.0.1',
60                                  'port': '22'
61                              }
62                          },
63                          'size': 4194304 })
64    vm.shutdown()
65
66    iotests.img_info_log(remote_path)
67    iotests.log("")
68    iotests.img_info_log(disk_path)
69
70    #
71    # Test host-key-check options
72    #
73    iotests.log("=== Test host-key-check options ===")
74    iotests.log("")
75
76    iotests.log("--- no host key checking --")
77    iotests.log("")
78
79    vm.launch()
80    blockdev_create(vm, { 'driver': 'ssh',
81                          'location': {
82                              'path': disk_path,
83                              'server': {
84                                  'host': '127.0.0.1',
85                                  'port': '22'
86                              },
87                              'host-key-check': {
88                                  'mode': 'none'
89                              }
90                          },
91                          'size': 8388608 })
92    vm.shutdown()
93
94    iotests.img_info_log(remote_path)
95
96    iotests.log("--- known_hosts key checking --")
97    iotests.log("")
98
99    vm.launch()
100    blockdev_create(vm, { 'driver': 'ssh',
101                          'location': {
102                              'path': disk_path,
103                              'server': {
104                                  'host': '127.0.0.1',
105                                  'port': '22'
106                              },
107                              'host-key-check': {
108                                  'mode': 'known_hosts'
109                              }
110                          },
111                          'size': 4194304 })
112    vm.shutdown()
113
114    iotests.img_info_log(remote_path)
115
116    keys = subprocess.check_output(
117        'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' +
118        'cut -d" " -f3',
119        shell=True).rstrip().decode('ascii').split('\n')
120
121    # Mappings of base64 representations to digests
122    md5_keys = {}
123    sha1_keys = {}
124    sha256_keys = {}
125
126    for key in keys:
127        md5_keys[key] = subprocess.check_output(
128            'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key,
129            shell=True).rstrip().decode('ascii')
130
131        sha1_keys[key] = subprocess.check_output(
132            'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key,
133            shell=True).rstrip().decode('ascii')
134
135        sha256_keys[key] = subprocess.check_output(
136            'echo %s | base64 -d | sha256sum -b | cut -d" " -f1' % key,
137            shell=True).rstrip().decode('ascii')
138
139    vm.launch()
140
141    # Find correct key first
142    matching_key = None
143    for key in keys:
144        result = vm.qmp('blockdev-add',
145                        driver='ssh', node_name='node0', path=disk_path,
146                        server={
147                             'host': '127.0.0.1',
148                             'port': '22',
149                        }, host_key_check={
150                             'mode': 'hash',
151                             'type': 'md5',
152                             'hash': md5_keys[key],
153                        })
154
155        if 'error' not in result:
156            vm.qmp('blockdev-del', node_name='node0')
157            matching_key = key
158            break
159
160    if matching_key is None:
161        vm.shutdown()
162        iotests.notrun('Did not find a key that fits 127.0.0.1')
163
164    iotests.log("--- explicit md5 key checking --")
165    iotests.log("")
166
167    blockdev_create(vm, { 'driver': 'ssh',
168                          'location': {
169                              'path': disk_path,
170                              'server': {
171                                  'host': '127.0.0.1',
172                                  'port': '22'
173                              },
174                              'host-key-check': {
175                                  'mode': 'hash',
176                                  'type': 'md5',
177                                  'hash': 'wrong',
178                              }
179                          },
180                          'size': 2097152 })
181
182    blockdev_create(vm, { 'driver': 'ssh',
183                          'location': {
184                              'path': disk_path,
185                              'server': {
186                                  'host': '127.0.0.1',
187                                  'port': '22'
188                              },
189                              'host-key-check': {
190                                  'mode': 'hash',
191                                  'type': 'md5',
192                                  'hash': md5_keys[matching_key],
193                              }
194                          },
195                          'size': 8388608 })
196    vm.shutdown()
197
198    iotests.img_info_log(remote_path)
199
200    iotests.log("--- explicit sha1 key checking --")
201    iotests.log("")
202
203    vm.launch()
204    blockdev_create(vm, { 'driver': 'ssh',
205                          'location': {
206                              'path': disk_path,
207                              'server': {
208                                  'host': '127.0.0.1',
209                                  'port': '22'
210                              },
211                              'host-key-check': {
212                                  'mode': 'hash',
213                                  'type': 'sha1',
214                                  'hash': 'wrong',
215                              }
216                          },
217                          'size': 2097152 })
218    blockdev_create(vm, { 'driver': 'ssh',
219                          'location': {
220                              'path': disk_path,
221                              'server': {
222                                  'host': '127.0.0.1',
223                                  'port': '22'
224                              },
225                              'host-key-check': {
226                                  'mode': 'hash',
227                                  'type': 'sha1',
228                                  'hash': sha1_keys[matching_key],
229                              }
230                          },
231                          'size': 4194304 })
232    vm.shutdown()
233
234    iotests.img_info_log(remote_path)
235
236    iotests.log("--- explicit sha256 key checking --")
237    iotests.log("")
238
239    vm.launch()
240    blockdev_create(vm, { 'driver': 'ssh',
241                          'location': {
242                              'path': disk_path,
243                              'server': {
244                                  'host': '127.0.0.1',
245                                  'port': '22'
246                              },
247                              'host-key-check': {
248                                  'mode': 'hash',
249                                  'type': 'sha256',
250                                  'hash': 'wrong',
251                              }
252                          },
253                          'size': 2097152 })
254    blockdev_create(vm, { 'driver': 'ssh',
255                          'location': {
256                              'path': disk_path,
257                              'server': {
258                                  'host': '127.0.0.1',
259                                  'port': '22'
260                              },
261                              'host-key-check': {
262                                  'mode': 'hash',
263                                  'type': 'sha256',
264                                  'hash': sha256_keys[matching_key],
265                              }
266                          },
267                          'size': 4194304 })
268    vm.shutdown()
269
270    iotests.img_info_log(remote_path)
271
272    #
273    # Invalid path and user
274    #
275    iotests.log("=== Invalid path and user ===")
276    iotests.log("")
277
278    vm.launch()
279    blockdev_create(vm, { 'driver': 'ssh',
280                          'location': {
281                              'path': '/this/is/not/an/existing/path',
282                              'server': {
283                                  'host': '127.0.0.1',
284                                  'port': '22'
285                              },
286                              'host-key-check': {
287                                  'mode': 'none'
288                              }
289                          },
290                          'size': 4194304 })
291    blockdev_create(vm, { 'driver': 'ssh',
292                          'location': {
293                              'path': disk_path,
294                              'user': 'invalid user',
295                              'server': {
296                                  'host': '127.0.0.1',
297                                  'port': '22'
298                              },
299                              'host-key-check': {
300                                  'mode': 'none'
301                              }
302                          },
303                          'size': 4194304 })
304    vm.shutdown()
305