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 if isinstance(qmsg, str): 39 # Strip key type and fingerprint 40 p = r"\S+ (key fingerprint) '(md5|sha1|sha256):[0-9a-f]+'" 41 return re.sub(p, r"\1 '\2:HASH'", qmsg) 42 else: 43 return iotests.filter_qmp(qmsg, _filter) 44 45def blockdev_create(vm, options): 46 vm.blockdev_create(options, filters=[iotests.filter_qmp_testfiles, filter_hash]) 47 48with iotests.FilePath('t.img') as disk_path, \ 49 iotests.VM() as vm: 50 51 remote_path = iotests.remote_filename(disk_path) 52 53 # 54 # Successful image creation (defaults) 55 # 56 iotests.log("=== Successful image creation (defaults) ===") 57 iotests.log("") 58 59 vm.launch() 60 blockdev_create(vm, { 'driver': 'ssh', 61 'location': { 62 'path': disk_path, 63 'server': { 64 'host': '127.0.0.1', 65 'port': '22' 66 } 67 }, 68 'size': 4194304 }) 69 vm.shutdown() 70 71 iotests.img_info_log(remote_path) 72 iotests.log("") 73 iotests.img_info_log(disk_path) 74 75 # 76 # Test host-key-check options 77 # 78 iotests.log("=== Test host-key-check options ===") 79 iotests.log("") 80 81 iotests.log("--- no host key checking --") 82 iotests.log("") 83 84 vm.launch() 85 blockdev_create(vm, { 'driver': 'ssh', 86 'location': { 87 'path': disk_path, 88 'server': { 89 'host': '127.0.0.1', 90 'port': '22' 91 }, 92 'host-key-check': { 93 'mode': 'none' 94 } 95 }, 96 'size': 8388608 }) 97 vm.shutdown() 98 99 iotests.img_info_log(remote_path) 100 101 iotests.log("--- known_hosts key checking --") 102 iotests.log("") 103 104 vm.launch() 105 blockdev_create(vm, { 'driver': 'ssh', 106 'location': { 107 'path': disk_path, 108 'server': { 109 'host': '127.0.0.1', 110 'port': '22' 111 }, 112 'host-key-check': { 113 'mode': 'known_hosts' 114 } 115 }, 116 'size': 4194304 }) 117 vm.shutdown() 118 119 iotests.img_info_log(remote_path) 120 121 keys = subprocess.check_output( 122 'ssh-keyscan 127.0.0.1 2>/dev/null | grep -v "\\^#" | ' + 123 'cut -d" " -f3', 124 shell=True).rstrip().decode('ascii').split('\n') 125 126 # Mappings of base64 representations to digests 127 md5_keys = {} 128 sha1_keys = {} 129 sha256_keys = {} 130 131 for key in keys: 132 md5_keys[key] = subprocess.check_output( 133 'echo %s | base64 -d | md5sum -b | cut -d" " -f1' % key, 134 shell=True).rstrip().decode('ascii') 135 136 sha1_keys[key] = subprocess.check_output( 137 'echo %s | base64 -d | sha1sum -b | cut -d" " -f1' % key, 138 shell=True).rstrip().decode('ascii') 139 140 sha256_keys[key] = subprocess.check_output( 141 'echo %s | base64 -d | sha256sum -b | cut -d" " -f1' % key, 142 shell=True).rstrip().decode('ascii') 143 144 vm.launch() 145 146 # Find correct key first 147 matching_key = None 148 for key in keys: 149 result = vm.qmp('blockdev-add', 150 driver='ssh', node_name='node0', path=disk_path, 151 server={ 152 'host': '127.0.0.1', 153 'port': '22', 154 }, host_key_check={ 155 'mode': 'hash', 156 'type': 'md5', 157 'hash': md5_keys[key], 158 }) 159 160 if 'error' not in result: 161 vm.qmp('blockdev-del', node_name='node0') 162 matching_key = key 163 break 164 165 if matching_key is None: 166 vm.shutdown() 167 iotests.notrun('Did not find a key that fits 127.0.0.1') 168 169 iotests.log("--- explicit md5 key checking --") 170 iotests.log("") 171 172 blockdev_create(vm, { 'driver': 'ssh', 173 'location': { 174 'path': disk_path, 175 'server': { 176 'host': '127.0.0.1', 177 'port': '22' 178 }, 179 'host-key-check': { 180 'mode': 'hash', 181 'type': 'md5', 182 'hash': 'wrong', 183 } 184 }, 185 'size': 2097152 }) 186 187 blockdev_create(vm, { 'driver': 'ssh', 188 'location': { 189 'path': disk_path, 190 'server': { 191 'host': '127.0.0.1', 192 'port': '22' 193 }, 194 'host-key-check': { 195 'mode': 'hash', 196 'type': 'md5', 197 'hash': md5_keys[matching_key], 198 } 199 }, 200 'size': 8388608 }) 201 vm.shutdown() 202 203 iotests.img_info_log(remote_path) 204 205 iotests.log("--- explicit sha1 key checking --") 206 iotests.log("") 207 208 vm.launch() 209 blockdev_create(vm, { 'driver': 'ssh', 210 'location': { 211 'path': disk_path, 212 'server': { 213 'host': '127.0.0.1', 214 'port': '22' 215 }, 216 'host-key-check': { 217 'mode': 'hash', 218 'type': 'sha1', 219 'hash': 'wrong', 220 } 221 }, 222 'size': 2097152 }) 223 blockdev_create(vm, { 'driver': 'ssh', 224 'location': { 225 'path': disk_path, 226 'server': { 227 'host': '127.0.0.1', 228 'port': '22' 229 }, 230 'host-key-check': { 231 'mode': 'hash', 232 'type': 'sha1', 233 'hash': sha1_keys[matching_key], 234 } 235 }, 236 'size': 4194304 }) 237 vm.shutdown() 238 239 iotests.img_info_log(remote_path) 240 241 iotests.log("--- explicit sha256 key checking --") 242 iotests.log("") 243 244 vm.launch() 245 blockdev_create(vm, { 'driver': 'ssh', 246 'location': { 247 'path': disk_path, 248 'server': { 249 'host': '127.0.0.1', 250 'port': '22' 251 }, 252 'host-key-check': { 253 'mode': 'hash', 254 'type': 'sha256', 255 'hash': 'wrong', 256 } 257 }, 258 'size': 2097152 }) 259 blockdev_create(vm, { 'driver': 'ssh', 260 'location': { 261 'path': disk_path, 262 'server': { 263 'host': '127.0.0.1', 264 'port': '22' 265 }, 266 'host-key-check': { 267 'mode': 'hash', 268 'type': 'sha256', 269 'hash': sha256_keys[matching_key], 270 } 271 }, 272 'size': 4194304 }) 273 vm.shutdown() 274 275 iotests.img_info_log(remote_path) 276 277 # 278 # Invalid path and user 279 # 280 iotests.log("=== Invalid path and user ===") 281 iotests.log("") 282 283 vm.launch() 284 blockdev_create(vm, { 'driver': 'ssh', 285 'location': { 286 'path': '/this/is/not/an/existing/path', 287 'server': { 288 'host': '127.0.0.1', 289 'port': '22' 290 }, 291 'host-key-check': { 292 'mode': 'none' 293 } 294 }, 295 'size': 4194304 }) 296 blockdev_create(vm, { 'driver': 'ssh', 297 'location': { 298 'path': disk_path, 299 'user': 'invalid user', 300 'server': { 301 'host': '127.0.0.1', 302 'port': '22' 303 }, 304 'host-key-check': { 305 'mode': 'none' 306 } 307 }, 308 'size': 4194304 }) 309 vm.shutdown() 310