Make allow_remote_control a little more fine grained

Also, only respect listen_on if there is a possiblility of rc commands
over it being accepted
This commit is contained in:
Kovid Goyal 2022-08-15 20:51:11 +05:30
parent df5e6e1563
commit d027f524ce
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 79 additions and 48 deletions

View File

@ -258,7 +258,11 @@ class Boss:
# we dont allow reloading the config file to change # we dont allow reloading the config file to change
# allow_remote_control # allow_remote_control
self.allow_remote_control = opts.allow_remote_control self.allow_remote_control = opts.allow_remote_control
if args.listen_on: if self.allow_remote_control in ('y', 'yes', 'true'):
self.allow_remote_control = 'y'
elif self.allow_remote_control in ('n', 'no', 'false'):
self.allow_remote_control = 'n'
if args.listen_on and self.allow_remote_control in ('y', 'socket', 'socket-only', 'password'):
listen_fd = listen_on(args.listen_on) listen_fd = listen_on(args.listen_on)
self.prewarm = prewarm self.prewarm = prewarm
self.child_monitor = ChildMonitor( self.child_monitor = ChildMonitor(
@ -447,6 +451,10 @@ class Boss:
from .remote_control import is_cmd_allowed, parse_cmd from .remote_control import is_cmd_allowed, parse_cmd
response = None response = None
window = window or None window = window or None
if self.allow_remote_control == 'n':
return {'ok': False, 'error': 'Remote control is disabled'}
if self.allow_remote_control == 'socket-only' and peer_id == 0:
return {'ok': False, 'error': 'Remote control is allowed over a socket only'}
try: try:
pcmd = parse_cmd(cmd, self.encryption_key) pcmd = parse_cmd(cmd, self.encryption_key)
except Exception as e: except Exception as e:
@ -454,10 +462,10 @@ class Boss:
return response return response
if not pcmd: if not pcmd:
return response return response
allowed_by_channel = ( allowed_unconditionally = (
self.allow_remote_control == 'y' or (peer_id > 0 and self.allow_remote_control == 'socket-only') or self.allow_remote_control == 'y' or (peer_id > 0 and self.allow_remote_control in ('socket-only', 'socket')) or
getattr(window, 'allow_remote_control', False)) (window and window.allow_remote_control))
if allowed_by_channel: if allowed_unconditionally:
return self._execute_remote_command(pcmd, window, peer_id) return self._execute_remote_command(pcmd, window, peer_id)
q = is_cmd_allowed(pcmd, window, peer_id > 0, {}) q = is_cmd_allowed(pcmd, window, peer_id > 0, {})
if q is True: if q is True:

View File

@ -677,17 +677,18 @@ regardless of this option.
--listen-on --listen-on
Listen on the specified socket address for control messages. For example, Listen on the specified socket address for control messages. For example,
:option:`{appname} --listen-on`=unix:/tmp/mykitty or :option:`{appname} --listen-on`=unix:/tmp/mykitty or :option:`{appname}
:option:`{appname} --listen-on`=tcp:localhost:12345. On Linux systems, you can --listen-on`=tcp:localhost:12345. On Linux systems, you can also use abstract
also use abstract UNIX sockets, not associated with a file, like this: UNIX sockets, not associated with a file, like this: :option:`{appname}
:option:`{appname} --listen-on`=unix:@mykitty. Environment variables are --listen-on`=unix:@mykitty. Environment variables are expanded and relative
expanded and relative paths are resolved with respect to the temporary paths are resolved with respect to the temporary directory. To control kitty,
directory. To control kitty, you can send commands to it with you can send commands to it with :italic:`{appname} @` using the
:italic:`{appname} @` using the :option:`{appname} @ --to` option to specify :option:`{appname} @ --to` option to specify this address. Note that if you run
this address. Note that if you run :italic:`{appname} @` within a kitty window, there is :italic:`{appname} @` within a kitty window, there is no need to specify the
no need to specify the :option:`{appname} @ --to` option as it will :option:`{appname} @ --to` option as it will automatically read from the
automatically read from the environment. For UNIX sockets, this can also be environment. Note that this will be ignored unless :opt:`allow_remote_control`
specified in :file:`{conf_name}.conf`. is set to either: :code:`yes`, :code:`socket` or :code:`socket-only`. For UNIX
sockets, this can also be specified in :file:`{conf_name}.conf`.
--start-as --start-as

View File

@ -2713,35 +2713,50 @@ that is used to check every remote control command. See :ref:`rc_custom_auth` fo
Relative paths are resolved from the kitty configuration directory. Relative paths are resolved from the kitty configuration directory.
''') ''')
opt('allow_remote_control', 'no', opt('allow_remote_control', 'password', choices=('password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true'),
option_type='allow_remote_control',
long_text=''' long_text='''
Allow other programs to control kitty. If you turn this on, other programs can Allow other programs to control kitty. If you turn this on, other programs can
control all aspects of kitty, including sending text to kitty windows, opening control all aspects of kitty, including sending text to kitty windows, opening
new windows, closing windows, reading the content of windows, etc. Note that new windows, closing windows, reading the content of windows, etc. Note that
this even works over SSH connections. You can choose to either allow any program this even works over SSH connections. The default setting of :code:`password`
running within kitty to control it with :code:`yes`, or only allow programs that asks the user for confirmation when a remote control command is received.
connect to the socket (specified with the :opt:`listen_on` config option or The meaning of the various values are:
:option:`kitty --listen-on` command line option) with the value
:code:`socket-only`. The latter is useful if you want to prevent programs :code:`password`
running on a remote computer over SSH from controlling kitty. Reloading the Remote control requests received over both the TTY device and the socket are
config will not affect this option. confirmed based on passwords, see :opt:`remote_control_password`.
:code:`socket-only`
Remote control requests received over a socket are accepted unconditionally.
Requests received over the TTY are denied. See :opt:`listen_on`.
:code:`socket`
Remote control requests received over a socket are accepted unconditionally.
Requests received over the TTY are confirmed based on password.
:code:`no`
Remote control is completely disabled.
:code:`yes`
Remote control requests are always accepted.
''' '''
) )
opt('listen_on', 'none', opt('listen_on', 'none',
long_text=''' long_text='''
Listen to the specified UNIX socket for remote control connections. Note Listen to the specified UNIX socket for remote control connections. Note that
that this will apply to all kitty instances. It can be overridden by the this will apply to all kitty instances. It can be overridden by the
:option:`kitty --listen-on` command line option, which supports listening on TCP :option:`kitty --listen-on` command line option, which also supports listening
socket. This option accepts only UNIX sockets, such as on a TCP socket. This option accepts only UNIX sockets, such as
:code:`unix:${TEMP}/mykitty` or :code:`unix:@mykitty` (on Linux). Environment :code:`unix:${TEMP}/mykitty` or :code:`unix:@mykitty` (on Linux). Environment
variables are expanded and relative paths are resolved with respect to the variables are expanded and relative paths are resolved with respect to the
temporary directory. If :code:`{kitty_pid}` is present, then it is replaced temporary directory. If :code:`{kitty_pid}` is present, then it is replaced by
by the PID of the kitty process, otherwise the PID of the kitty process is the PID of the kitty process, otherwise the PID of the kitty process is
appended to the value, with a hyphen. See the help for appended to the value, with a hyphen. See the help for :option:`kitty
:option:`kitty --listen-on` for more details. Changing this option by reloading --listen-on` for more details. Note that this will be ignored unless :opt:`allow_remote_control`
the config is not supported. is set to either: :code:`yes`, :code:`socket` or :code:`socket-only`.
Changing this option by reloading the config is not supported.
''' '''
) )

31
kitty/options/parse.py generated
View File

@ -6,18 +6,18 @@ from kitty.conf.utils import (
unit_float unit_float
) )
from kitty.options.utils import ( from kitty.options.utils import (
action_alias, active_tab_title_template, allow_hyperlinks, allow_remote_control, bell_on_tab, action_alias, active_tab_title_template, allow_hyperlinks, bell_on_tab, box_drawing_scale,
box_drawing_scale, clear_all_mouse_actions, clear_all_shortcuts, clipboard_control, clear_all_mouse_actions, clear_all_shortcuts, clipboard_control, clone_source_strategies,
clone_source_strategies, config_or_absolute_path, copy_on_select, cursor_text_color, config_or_absolute_path, copy_on_select, cursor_text_color, deprecated_adjust_line_height,
deprecated_adjust_line_height, deprecated_hide_window_decorations_aliases, deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias,
deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures, deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations,
edge_width, env, font_features, hide_window_decorations, macos_option_as_alt, macos_titlebar_color, macos_option_as_alt, macos_titlebar_color, modify_font, narrow_symbols, optional_edge_width,
modify_font, narrow_symbols, optional_edge_width, parse_map, parse_mouse_map, paste_actions, parse_map, parse_mouse_map, paste_actions, remote_control_password, resize_draw_strategy,
remote_control_password, resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, scrollback_lines, scrollback_pager_history_size, shell_integration, store_multiple, symbol_map,
shell_integration, store_multiple, symbol_map, tab_activity_symbol, tab_bar_edge, tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade,
tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, tab_font_style, tab_separator, tab_title_template, titlebar_color, to_cursor_shape, to_font_size,
tab_title_template, titlebar_color, to_cursor_shape, to_font_size, to_layout_names, to_modifiers, to_layout_names, to_modifiers, url_prefixes, url_style, visual_window_select_characters,
url_prefixes, url_style, visual_window_select_characters, window_border_width, window_size window_border_width, window_size
) )
@ -54,7 +54,12 @@ class Parser:
ans['allow_hyperlinks'] = allow_hyperlinks(val) ans['allow_hyperlinks'] = allow_hyperlinks(val)
def allow_remote_control(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def allow_remote_control(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['allow_remote_control'] = allow_remote_control(val) val = val.lower()
if val not in self.choices_for_allow_remote_control:
raise ValueError(f"The value {val} is not a valid choice for allow_remote_control")
ans["allow_remote_control"] = val
choices_for_allow_remote_control = frozenset(('password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true'))
def background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: def background(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['background'] = to_color(val) ans['background'] = to_color(val)

View File

@ -14,6 +14,7 @@ import kitty.types
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
choices_for_allow_cloning = typing.Literal['yes', 'y', 'true', 'no', 'n', 'false', 'ask'] choices_for_allow_cloning = typing.Literal['yes', 'y', 'true', 'no', 'n', 'false', 'ask']
choices_for_allow_remote_control = typing.Literal['password', 'socket-only', 'socket', 'no', 'n', 'false', 'yes', 'y', 'true']
choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped'] choices_for_background_image_layout = typing.Literal['mirror-tiled', 'scaled', 'tiled', 'clamped']
choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand'] choices_for_default_pointer_shape = typing.Literal['arrow', 'beam', 'hand']
choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11'] choices_for_linux_display_server = typing.Literal['auto', 'wayland', 'x11']
@ -30,6 +31,7 @@ if typing.TYPE_CHECKING:
choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'] choices_for_window_logo_position = typing.Literal['top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right']
else: else:
choices_for_allow_cloning = str choices_for_allow_cloning = str
choices_for_allow_remote_control = str
choices_for_background_image_layout = str choices_for_background_image_layout = str
choices_for_default_pointer_shape = str choices_for_default_pointer_shape = str
choices_for_linux_display_server = str choices_for_linux_display_server = str
@ -467,7 +469,7 @@ class Options:
active_tab_title_template: typing.Optional[str] = None active_tab_title_template: typing.Optional[str] = None
allow_cloning: choices_for_allow_cloning = 'ask' allow_cloning: choices_for_allow_cloning = 'ask'
allow_hyperlinks: int = 1 allow_hyperlinks: int = 1
allow_remote_control: str = 'n' allow_remote_control: choices_for_allow_remote_control = 'password'
background: Color = Color(0, 0, 0) background: Color = Color(0, 0, 0)
background_image: typing.Optional[str] = None background_image: typing.Optional[str] = None
background_image_layout: choices_for_background_image_layout = 'tiled' background_image_layout: choices_for_background_image_layout = 'tiled'