vnc none auth support

This commit is contained in:
Devaev Maxim 2020-05-15 14:14:12 +03:00
parent b2c2244aa3
commit a364e689c6
2 changed files with 58 additions and 20 deletions

View File

@ -62,6 +62,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
height: int, height: int,
name: str, name: str,
vnc_passwds: List[str], vnc_passwds: List[str],
none_auth_only: bool,
) -> None: ) -> None:
super().__init__(reader, writer) super().__init__(reader, writer)
@ -73,6 +74,7 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
self._height = height self._height = height
self.__name = name self.__name = name
self.__vnc_passwds = vnc_passwds self.__vnc_passwds = vnc_passwds
self.__none_auth_only = none_auth_only
self.__rfb_version = 0 self.__rfb_version = 0
self._encodings = RfbClientEncodings(frozenset()) self._encodings = RfbClientEncodings(frozenset())
@ -124,6 +126,11 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
async def _on_authorized_vnc_passwd(self, passwd: str) -> str: async def _on_authorized_vnc_passwd(self, passwd: str) -> str:
raise NotImplementedError raise NotImplementedError
async def _on_authorized_none(self) -> bool:
raise NotImplementedError
# =====
async def _on_key_event(self, code: int, state: bool) -> None: async def _on_key_event(self, code: int, state: bool) -> None:
raise NotImplementedError raise NotImplementedError
@ -201,10 +208,12 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
sec_types: Dict[int, Tuple[str, Callable]] = {} sec_types: Dict[int, Tuple[str, Callable]] = {}
if self.__rfb_version > 3: if self.__rfb_version > 3:
sec_types[19] = ("VeNCrypt", self.__handshake_security_vencrypt) sec_types[19] = ("VeNCrypt", self.__handshake_security_vencrypt)
if self.__vnc_passwds: if self.__none_auth_only:
sec_types[1] = ("None", self.__handshake_security_none)
elif self.__vnc_passwds:
sec_types[2] = ("VNCAuth", self.__handshake_security_vnc_auth) sec_types[2] = ("VNCAuth", self.__handshake_security_vnc_auth)
if not sec_types: if not sec_types:
msg = "The client uses a very old protocol 3.3 and VNCAuth is disabled" msg = "The client uses a very old protocol 3.3 and VNCAuth or NoneAuth is disabled"
await self._write_struct("L", 0, drain=False) # Refuse old clients using the invalid security type await self._write_struct("L", 0, drain=False) # Refuse old clients using the invalid security type
await self._write_reason(msg) await self._write_reason(msg)
raise RfbError(msg) raise RfbError(msg)
@ -229,6 +238,12 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
await self._write_struct("B", 0) await self._write_struct("B", 0)
if self.__none_auth_only:
auth_types = {
1: ("VeNCrypt/None", False, self.__handshake_security_none),
257: ("VeNCrypt/TLSNone", True, self.__handshake_security_none),
}
else:
auth_types = { auth_types = {
256: ("VeNCrypt/Plain", False, self.__handshake_security_vencrypt_userpass), 256: ("VeNCrypt/Plain", False, self.__handshake_security_vencrypt_userpass),
259: ("VeNCrypt/TLSPlain", True, self.__handshake_security_vencrypt_userpass), 259: ("VeNCrypt/TLSPlain", True, self.__handshake_security_vencrypt_userpass),
@ -266,9 +281,12 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
passwd = await self._read_text(passwd_length) passwd = await self._read_text(passwd_length)
ok = await self._authorize_userpass(user, passwd) ok = await self._authorize_userpass(user, passwd)
await self.__handshake_security_send_result(ok, user) await self.__handshake_security_send_result(ok, user)
async def __handshake_security_none(self) -> None:
ok = await self._on_authorized_none()
await self.__handshake_security_send_result(ok, "")
async def __handshake_security_vnc_auth(self) -> None: async def __handshake_security_vnc_auth(self) -> None:
challenge = rfb_make_challenge() challenge = rfb_make_challenge()
await self._write_struct("", challenge) await self._write_struct("", challenge)
@ -287,14 +305,26 @@ class RfbClient(RfbClientStream): # pylint: disable=too-many-instance-attribute
async def __handshake_security_send_result(self, ok: bool, user: str) -> None: async def __handshake_security_send_result(self, ok: bool, user: str) -> None:
if ok: if ok:
if self.__none_auth_only:
assert len(user) == 0
get_logger(0).info("[main] Client %s: Anonymous access granted", self._remote)
else:
assert user assert user
get_logger(0).info("[main] Client %s: Access granted for user %r", self._remote, user) get_logger(0).info("[main] Client %s: Access granted for user %r", self._remote, user)
await self._write_struct("L", 0) await self._write_struct("L", 0)
else: else:
await self._write_struct("L", 1, drain=(self.__rfb_version < 8)) await self._write_struct("L", 1, drain=(self.__rfb_version < 8))
if self.__none_auth_only:
reason = msg = "Anonymous access denied"
elif user:
reason = "Invalid username or password"
msg = f"Access denied for user {user!r}"
else:
reason = "Invalid password"
msg = "Access denied"
if self.__rfb_version >= 8: if self.__rfb_version >= 8:
await self._write_reason("Invalid username or password" if user else "Invalid password") await self._write_reason(reason)
raise RfbError(f"Access denied for user {user!r}" if user else "Access denied") raise RfbError(msg)
# ===== # =====

View File

@ -73,6 +73,7 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
streamer: StreamerClient, streamer: StreamerClient,
vnc_credentials: Dict[str, VncAuthKvmdCredentials], vnc_credentials: Dict[str, VncAuthKvmdCredentials],
none_auth_only: bool,
shared_params: _SharedParams, shared_params: _SharedParams,
) -> None: ) -> None:
@ -84,6 +85,7 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
tls_ciphers=tls_ciphers, tls_ciphers=tls_ciphers,
tls_timeout=tls_timeout, tls_timeout=tls_timeout,
vnc_passwds=list(vnc_credentials), vnc_passwds=list(vnc_credentials),
none_auth_only=none_auth_only,
**dataclasses.asdict(shared_params), **dataclasses.asdict(shared_params),
) )
@ -239,6 +241,11 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
return kc.user return kc.user
return "" return ""
async def _on_authorized_none(self) -> bool:
return (await self._authorize_userpass("", ""))
# =====
async def _on_key_event(self, code: int, state: bool) -> None: async def _on_key_event(self, code: int, state: bool) -> None:
if (web_name := self.__symmap.get(code)) is not None: # noqa: E203,E231 if (web_name := self.__symmap.get(code)) is not None: # noqa: E203,E231
await self.__ws_writer_queue.put({ await self.__ws_writer_queue.put({
@ -321,6 +328,7 @@ class VncServer: # pylint: disable=too-many-instance-attributes
kvmd=kvmd, kvmd=kvmd,
streamer=streamer, streamer=streamer,
vnc_credentials=(await self.__vnc_auth_manager.read_credentials())[0], vnc_credentials=(await self.__vnc_auth_manager.read_credentials())[0],
none_auth_only=(await kvmd.authorize("", "")),
shared_params=shared_params, shared_params=shared_params,
).run() ).run()