mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-09 03:36:48 +00:00
fix(instances): only administrators choose where a console listens
A VM owner who may manage the console (is_change and is_vnc) could set its listen address to all interfaces and remove its password: a VNC console reachable from the network without a password. Checked on a test host: the owner's form changed the VM's listen address to 0.0.0.0 and then removed the password. - The listen address field is disabled for users who are not superusers; a disabled field ignores posted values. They can still set or change the password and the keymap. - A console whose persistent definition does not bind it to loopback (or a Unix socket) only loses its password through an administrator. A binding the XML does not pin down counts as not local: listen type network, or no address (the host's default in qemu.conf). On the test host, the owner's form now leaves the listen address alone and is refused when it removes the password of a console listening on 0.0.0.0; with the console on localhost the password can be removed. The new tests fail on the previous code.
This commit is contained in:
parent
eab27f8aba
commit
f3929b8e8f
4 changed files with 147 additions and 5 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import contextlib
|
||||
import ipaddress
|
||||
import json
|
||||
import logging
|
||||
import os.path
|
||||
|
|
@ -1092,6 +1093,31 @@ class wvmInstance(wvmConnect):
|
|||
return "127.0.0.1"
|
||||
return listener_addr
|
||||
|
||||
def console_listens_locally(self):
|
||||
"""True if the persistent definition binds the console to loopback
|
||||
addresses or a Unix socket only. Anything the XML does not pin down
|
||||
counts as not local: listen type network, or no address at all (the
|
||||
host's default in qemu.conf)."""
|
||||
graphic = etree.fromstring(self._XMLDesc(PERSISTENT_XML)).find("devices/graphics")
|
||||
if graphic is None:
|
||||
return True # no console
|
||||
addresses = [graphic.get("listen")]
|
||||
local_types = 0
|
||||
for listen in graphic.findall("listen"):
|
||||
if listen.get("type") == "address":
|
||||
addresses.append(listen.get("address"))
|
||||
elif listen.get("type") in ("socket", "none"):
|
||||
local_types += 1
|
||||
else:
|
||||
return False
|
||||
addresses = [a for a in addresses if a]
|
||||
if not addresses:
|
||||
return local_types > 0
|
||||
try:
|
||||
return all(ipaddress.ip_address(a).is_loopback for a in addresses)
|
||||
except ValueError: # a host name
|
||||
return False
|
||||
|
||||
def set_console_listener_addr(self, listener_addr):
|
||||
root = etree.fromstring(self._XMLDesc(PERSISTENT_XML))
|
||||
# The console is the first graphics device of the definition being
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue