Commit 9f6e718b authored by segfault's avatar segfault

Add Greeter option to enable the Unsafe Browser (refs: #17085)

... and disable it by default.
parent 0284ea59
...@@ -24,6 +24,7 @@ KBDSET=/etc/default/keyboard ...@@ -24,6 +24,7 @@ KBDSET=/etc/default/keyboard
CONSET=/etc/default/console-setup CONSET=/etc/default/console-setup
LOCALE_CFG=/etc/default/locale LOCALE_CFG=/etc/default/locale
CODSET="Uni1" # universal codeset to properly display glyphs in localized console CODSET="Uni1" # universal codeset to properly display glyphs in localized console
GREETER_EXPORTED_SETTINGS="tails.macspoof tails.network tails.unsafe-browser"
log() { log() {
echo "$1" >&2 echo "$1" >&2
...@@ -62,6 +63,17 @@ grep_n_set() { ...@@ -62,6 +63,17 @@ grep_n_set() {
log "Entering PostLogin" log "Entering PostLogin"
### Export the Greeter settings
# It's important we export the settings from tails.macspoof before
# unblocking the network below; doing so will make the user-set MAC
# spoofing option apply (via the custom udev rule) when loading the
# modules for the previously blocked network devices.
for setting in ${GREETER_EXPORTED_SETTINGS}; do \
/usr/bin/install -m 0640 -o root -g root \
"/var/lib/gdm3/settings/$setting" \
"/var/lib/live/config/$setting" ; \
done
### Gather general configuration ### Gather general configuration
# Import the name of the live user # Import the name of the live user
......
...@@ -7,17 +7,6 @@ Type=oneshot ...@@ -7,17 +7,6 @@ Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
EnvironmentFile=/var/lib/gdm3/settings/tails.network EnvironmentFile=/var/lib/gdm3/settings/tails.network
# It's important we "export" the settings from tails.macspoof before
# unblocking the network; doing so will make the user-set MAC spoofing
# option apply (via the custom udev rule) when loading the modules for the
# previously blocked network devices.
ExecStartPre=/bin/sh -c \
'for setting in macspoof network; do \
/usr/bin/install -m 0640 -o root -g root \
"/var/lib/gdm3/settings/tails.$setting" \
"/var/lib/live/config/tails.$setting" ; \
done'
ExecStartPre=/bin/sync
ExecStartPre=/bin/sh -c \ ExecStartPre=/bin/sh -c \
'if [ "${TAILS_NETCONF}" = "obstacle" ] ; then \ 'if [ "${TAILS_NETCONF}" = "obstacle" ] ; then \
. /usr/local/lib/tails-shell-library/tor.sh ; \ . /usr/local/lib/tails-shell-library/tor.sh ; \
......
...@@ -53,5 +53,8 @@ network_setting_path = os.path.join(settings_dir, 'tails.network') ...@@ -53,5 +53,8 @@ network_setting_path = os.path.join(settings_dir, 'tails.network')
# File where the MAC address spoofing setting is stored # File where the MAC address spoofing setting is stored
macspoof_setting_path = os.path.join(settings_dir, 'tails.macspoof') macspoof_setting_path = os.path.join(settings_dir, 'tails.macspoof')
# File where the unsafe browser setting is stored
unsafe_browser_setting_path = os.path.join(settings_dir, 'tails.unsafe-browser')
# World-readable file where Tails persistence status is stored # World-readable file where Tails persistence status is stored
persistence_state_file = '/var/lib/live/config/tails.persistence' persistence_state_file = '/var/lib/live/config/tails.persistence'
...@@ -30,8 +30,9 @@ from tailsgreeter.settings.localization_settings import LocalisationSettings ...@@ -30,8 +30,9 @@ from tailsgreeter.settings.localization_settings import LocalisationSettings
from tailsgreeter.settings.macspoof import MacSpoofSetting from tailsgreeter.settings.macspoof import MacSpoofSetting
from tailsgreeter.settings.network import NetworkSetting from tailsgreeter.settings.network import NetworkSetting
from tailsgreeter.settings.persistence import PersistenceSettings from tailsgreeter.settings.persistence import PersistenceSettings
from tailsgreeter.settings.unsafe_browser import UnsafeBrowserSetting
from tailsgreeter.translatable_window import TranslatableWindow from tailsgreeter.translatable_window import TranslatableWindow
from tailsgreeter.ui.additional_settings import AdminSettingUI, MACSpoofSettingUI, NetworkSettingUI from tailsgreeter.ui.additional_settings import AdminSettingUI, MACSpoofSettingUI, NetworkSettingUI, UnsafeBrowserSettingUI
from tailsgreeter.ui.main_window import GreeterMainWindow from tailsgreeter.ui.main_window import GreeterMainWindow
from tailsgreeter.ui.region_settings import LanguageSettingUI, KeyboardSettingUI, FormatsSettingUI from tailsgreeter.ui.region_settings import LanguageSettingUI, KeyboardSettingUI, FormatsSettingUI
from tailsgreeter.ui.settings_collection import GreeterSettingsCollection from tailsgreeter.ui.settings_collection import GreeterSettingsCollection
...@@ -73,8 +74,9 @@ class GreeterApplication(object): ...@@ -73,8 +74,9 @@ class GreeterApplication(object):
usermanager_loaded_cb=self.usermanager_loaded, usermanager_loaded_cb=self.usermanager_loaded,
) )
self.admin_setting = AdminSetting() self.admin_setting = AdminSetting()
self.network_setting = NetworkSetting()
self.macspoof_setting = MacSpoofSetting() self.macspoof_setting = MacSpoofSetting()
self.network_setting = NetworkSetting()
self.unsafe_browser_setting = UnsafeBrowserSetting()
# Initialize the settings # Initialize the settings
self.settings = GreeterSettingsCollection( self.settings = GreeterSettingsCollection(
...@@ -84,6 +86,7 @@ class GreeterApplication(object): ...@@ -84,6 +86,7 @@ class GreeterApplication(object):
AdminSettingUI(self.admin_setting), AdminSettingUI(self.admin_setting),
MACSpoofSettingUI(self.macspoof_setting), MACSpoofSettingUI(self.macspoof_setting),
NetworkSettingUI(self.network_setting), NetworkSettingUI(self.network_setting),
UnsafeBrowserSettingUI(self.unsafe_browser_setting),
) )
# Initialize main window # Initialize main window
......
import logging
import tailsgreeter.config
from tailsgreeter.settings import SettingNotFoundError
from tailsgreeter.settings.utils import read_settings, write_settings
class UnsafeBrowserSetting(object):
"""Setting controlling whether the Unsafe Browser is available or not"""
def __init__(self):
self.settings_file = tailsgreeter.config.unsafe_browser_setting_path
def save(self, value: bool):
write_settings(self.settings_file, {
'TAILS_UNSAFE_BROWSER_ENABLED': value,
})
logging.debug('unsafe-browser setting written to %s', self.settings_file)
def load(self) -> bool:
try:
settings = read_settings(self.settings_file)
except FileNotFoundError:
raise SettingNotFoundError("No persistent unsafe-browser settings file found (path: %s)" % self.settings_file)
value_str = settings.get('TAILS_UNSAFE_BROWSER_ENABLED')
if value_str is None:
raise SettingNotFoundError("No unsafe-browser setting found in settings file (path: %s)" % self.settings_file)
value = value_str == "true"
logging.debug("Loaded unsafe-browser setting '%s'", value)
return value
...@@ -47,6 +47,12 @@ class AdditionalSetting(GreeterSetting): ...@@ -47,6 +47,12 @@ class AdditionalSetting(GreeterSetting):
def load(self) -> bool: def load(self) -> bool:
pass pass
def cb_listbox_button_press(self, widget, event, user_data=None):
# On double-click: Close the window and apply chosen setting
if event.type == Gdk.EventType._2BUTTON_PRESS:
self.close_window(Gtk.ResponseType.YES)
return False
class AdminSettingUI(AdditionalSetting): class AdminSettingUI(AdditionalSetting):
@property @property
...@@ -194,7 +200,7 @@ class MACSpoofSettingUI(AdditionalSetting): ...@@ -194,7 +200,7 @@ class MACSpoofSettingUI(AdditionalSetting):
self.image_macspoof_off = self.builder.get_object('image_macspoof_off') self.image_macspoof_off = self.builder.get_object('image_macspoof_off')
self.listbox_macspoof_controls = self.builder.get_object('listbox_macspoof_controls') self.listbox_macspoof_controls = self.builder.get_object('listbox_macspoof_controls')
self.listbox_macspoof_controls.connect('row-activated', self.cb_listbox_macspoof_row_activated) self.listbox_macspoof_controls.connect('row-activated', self.cb_listbox_macspoof_row_activated)
self.listbox_macspoof_controls.connect('button-press-event', self.cb_listbox_macspoof_button_press) self.listbox_macspoof_controls.connect('button-press-event', self.cb_listbox_button_press)
self.listboxrow_macspoof_on = self.builder.get_object('listboxrow_macspoof_on') self.listboxrow_macspoof_on = self.builder.get_object('listboxrow_macspoof_on')
self.listboxrow_macspoof_off = self.builder.get_object('listboxrow_macspoof_off') self.listboxrow_macspoof_off = self.builder.get_object('listboxrow_macspoof_off')
...@@ -229,12 +235,6 @@ class MACSpoofSettingUI(AdditionalSetting): ...@@ -229,12 +235,6 @@ class MACSpoofSettingUI(AdditionalSetting):
self.popover.close(Gtk.ResponseType.YES) self.popover.close(Gtk.ResponseType.YES)
return False return False
def cb_listbox_macspoof_button_press(self, widget, event, user_data=None):
# On double-click: Close the window and apply chosen setting
if event.type == Gdk.EventType._2BUTTON_PRESS:
self.close_window(Gtk.ResponseType.YES)
return False
class NetworkSettingUI(AdditionalSetting): class NetworkSettingUI(AdditionalSetting):
@property @property
...@@ -267,7 +267,7 @@ class NetworkSettingUI(AdditionalSetting): ...@@ -267,7 +267,7 @@ class NetworkSettingUI(AdditionalSetting):
self.icon_network_specific_chosen = self.builder.get_object('image_network_specific') self.icon_network_specific_chosen = self.builder.get_object('image_network_specific')
self.icon_network_off_chosen = self.builder.get_object('image_network_off') self.icon_network_off_chosen = self.builder.get_object('image_network_off')
self.listbox_network_controls = self.builder.get_object('listbox_network_controls') self.listbox_network_controls = self.builder.get_object('listbox_network_controls')
self.listbox_network_controls.connect('button-press-event', self.cb_listbox_network_button_press) self.listbox_network_controls.connect('button-press-event', self.cb_listbox_button_press)
self.listbox_network_controls.connect('row-activated', self.cb_listbox_network_row_activated) self.listbox_network_controls.connect('row-activated', self.cb_listbox_network_row_activated)
self.listboxrow_network_clear = self.builder.get_object('listboxrow_network_clear') self.listboxrow_network_clear = self.builder.get_object('listboxrow_network_clear')
self.listboxrow_network_specific = self.builder.get_object('listboxrow_network_specific') self.listboxrow_network_specific = self.builder.get_object('listboxrow_network_specific')
...@@ -299,12 +299,6 @@ class NetworkSettingUI(AdditionalSetting): ...@@ -299,12 +299,6 @@ class NetworkSettingUI(AdditionalSetting):
self.value = value self.value = value
return True return True
def cb_listbox_network_button_press(self, widget, event, user_data=None):
# On double-click: Close the window and apply chosen setting
if event.type == Gdk.EventType._2BUTTON_PRESS:
self.close_window(Gtk.ResponseType.YES)
return False
def cb_listbox_network_row_activated(self, listbox, row, user_data=None): def cb_listbox_network_row_activated(self, listbox, row, user_data=None):
self.icon_network_clear_chosen.set_visible(False) self.icon_network_clear_chosen.set_visible(False)
self.icon_network_specific_chosen.set_visible(False) self.icon_network_specific_chosen.set_visible(False)
...@@ -325,6 +319,69 @@ class NetworkSettingUI(AdditionalSetting): ...@@ -325,6 +319,69 @@ class NetworkSettingUI(AdditionalSetting):
return False return False
class UnsafeBrowserSettingUI(AdditionalSetting):
@property
def id(self) -> str:
return "unsafe_browser"
@property
def title(self) -> str:
return _("_Unsafe Browser")
@property
def icon_name(self) -> str:
return "web-browser-symbolic"
@property
def value_for_display(self) -> str:
return get_on_off_string(self.unsafe_browser_enabled, default=False)
def __init__(self, unsafe_browser_setting):
self._unsafe_browser_setting = unsafe_browser_setting
self.unsafe_browser_enabled = False
super().__init__()
self.accel_key = Gdk.KEY_u
self.listbox_unsafe_browser_controls = self.builder.get_object('listbox_unsafe_browser_controls')
self.listbox_unsafe_browser_controls.connect('button-press-event', self.cb_listbox_button_press)
self.listbox_unsafe_browser_controls.connect('row-activated', self.cb_listbox_unsafe_browser_row_activated)
self.listboxrow_unsafe_browser_off = self.builder.get_object('listboxrow_unsafe_browser_off')
self.listboxrow_unsafe_browser_on = self.builder.get_object('listboxrow_unsafe_browser_on')
self.icon_unsafe_browser_off = self.builder.get_object('image_unsafe_browser_off')
self.icon_unsafe_browser_on = self.builder.get_object('image_unsafe_browser_on')
self.label_unsafe_browser_value = self.builder.get_object('label_unsafe_browser_value')
def apply(self):
self._unsafe_browser_setting.save(self.unsafe_browser_enabled)
super().apply()
def load(self) -> bool:
try:
value = self._unsafe_browser_setting.load()
except SettingNotFoundError:
raise
# Select the correct listboxrow (used in the popover)
if value:
self.listbox_unsafe_browser_controls.select_row(self.listboxrow_unsafe_browser_on)
else:
self.listbox_unsafe_browser_controls.select_row(self.listboxrow_unsafe_browser_off)
if self.unsafe_browser_enabled == value:
return False
self.unsafe_browser_enabled = value
return True
def cb_listbox_unsafe_browser_row_activated(self, listbox, row, user_data=None):
self.unsafe_browser_enabled = row == self.listboxrow_unsafe_browser_on
self.icon_unsafe_browser_on.set_visible(self.unsafe_browser_enabled)
self.icon_unsafe_browser_off.set_visible(not self.unsafe_browser_enabled)
if self.has_popover() and self.popover.is_open():
self.popover.close(Gtk.ResponseType.YES)
return False
def get_on_off_string(value, default=None) -> str: def get_on_off_string(value, default=None) -> str:
"""Return "On", "Off", "On (default)", or "Off (default)""" """Return "On", "Off", "On (default)", or "Off (default)"""
if value and default: if value and default:
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
PERSISTENCE_SETTING='/var/lib/live/config/tails.persistence' PERSISTENCE_SETTING='/var/lib/live/config/tails.persistence'
MACSPOOF_SETTING='/var/lib/live/config/tails.macspoof' MACSPOOF_SETTING='/var/lib/live/config/tails.macspoof'
NETWORK_SETTING='/var/lib/live/config/tails.network' NETWORK_SETTING='/var/lib/live/config/tails.network'
UNSAFE_BROWSER_SETTING='/var/lib/live/config/tails.unsafe-browser'
_get_tg_setting() { _get_tg_setting() {
if [ -r "${1}" ]; then if [ -r "${1}" ]; then
...@@ -33,3 +34,7 @@ mac_spoof_is_enabled() { ...@@ -33,3 +34,7 @@ mac_spoof_is_enabled() {
tails_netconf() { tails_netconf() {
_get_tg_setting "${NETWORK_SETTING}" TAILS_NETCONF _get_tg_setting "${NETWORK_SETTING}" TAILS_NETCONF
} }
unsafe_browser_is_enabled() {
[ "$(_get_tg_setting "${UNSAFE_BROWSER_SETTING}" TAILS_UNSAFE_BROWSER_ENABLED)" = true ]
}
\ No newline at end of file
...@@ -20,6 +20,9 @@ export TEXTDOMAIN ...@@ -20,6 +20,9 @@ export TEXTDOMAIN
# and run_browser_in_chroot(). # and run_browser_in_chroot().
. /usr/local/lib/tails-shell-library/chroot-browser.sh . /usr/local/lib/tails-shell-library/chroot-browser.sh
# Import unsafe_browser_is_enabled
. /usr/local/lib/tails-shell-library/tails-greeter.sh
error () { error () {
local cli_text="${CMD}: `gettext \"error:\"` ${@}" local cli_text="${CMD}: `gettext \"error:\"` ${@}"
local dialog_text="<b><big>`gettext \"Error\"`</big></b> local dialog_text="<b><big>`gettext \"Error\"`</big></b>
...@@ -82,6 +85,13 @@ HUMAN_READABLE_NAME="`gettext \"Unsafe Browser\"`" ...@@ -82,6 +85,13 @@ HUMAN_READABLE_NAME="`gettext \"Unsafe Browser\"`"
WARNING_PAGE='/usr/share/doc/tails/website/misc/unsafe_browser_warning' WARNING_PAGE='/usr/share/doc/tails/website/misc/unsafe_browser_warning'
HOME_PAGE="$(localized_tails_doc_page "${WARNING_PAGE}")" HOME_PAGE="$(localized_tails_doc_page "${WARNING_PAGE}")"
# Check if the Unsafe Browser was disabled in the startup options
if ! unsafe_browser_is_enabled; then
error "`gettext \"The Unsafe Browser was not enabled on the Welcome Screen.\n\n\
If you want to use the Unsafe Browser, you have to restart Tails and enable \
it in the settings on the Welcome Screen.\"`"
fi
# Prevent multiple instances of the script. # Prevent multiple instances of the script.
exec 9>"${LOCK}" exec 9>"${LOCK}"
if ! flock -x -n 9; then if ! flock -x -n 9; then
......
...@@ -494,4 +494,161 @@ ...@@ -494,4 +494,161 @@
</packing> </packing>
</child> </child>
</object> </object>
<object class="GtkBox" id="box_unsafe_browser_popover">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">18</property>
<property name="margin_right">18</property>
<property name="margin_top">18</property>
<property name="margin_bottom">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkLabel" id="label_unsafe_browser_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Unsafe Browser</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.5"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_unsafe_browser_description">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">The Unsafe Browser allows you to log in to captive portals before starting Tor. It is also a security risk, because it could be used to deanonymize you.\nYou can enable the Unsafe Browser here if you have to log in to captive portals.</property>
<property name="justify">fill</property>
<property name="wrap">True</property>
<property name="width_chars">50</property>
<property name="max_width_chars">50</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame_unsafe_browser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">18</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkListBox" id="listbox_unsafe_browser_controls">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">browse</property>
<child>
<object class="GtkListBoxRow" id="listboxrow_unsafe_browser_off">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox" id="box_unsafe_browser_off">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label_unsafe_browser_off">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Disable the Unsafe Browser (default)</property>
<property name="wrap">True</property>
<property name="max_width_chars">45</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="image_unsafe_browser_off">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-ok-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow" id="listboxrow_unsafe_browser_on">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkBox" id="box_unsafe_browser_on">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">6</property>
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label_unsafe_browser_on">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Enable the Unsafe Browser</property>
<property name="justify">fill</property>
<property name="wrap">True</property>
<property name="max_width_chars">45</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="image_unsafe_browser_on">
<property name="can_focus">False</property>
<property name="icon_name">emblem-ok-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</interface> </interface>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment