library/network/src/modules/CWMFirewallInterfaces.rb
#
# ***************************************************************************
#
# Copyright (c) 2018 SUSE LLC.
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 or 3 of the GNU General
# Public License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact SUSE LLC.
#
# To contact SUSE about this file by physical or electronic mail,
# you may find current contact information at www.suse.com
#
# ***************************************************************************
# File: modules/CWMFirewallInterfaces.ycp
# Package: Common widget manipulation, firewall interfaces widget
# Summary: Routines for selecting interfaces opened in firewall
# Authors: Jiri Srain <jsrain@suse.cz>
#
# $Id$
#
# WARNING: If you want to use this functionality of this module
# you should allways call 'firewalld.read' in the
# Read() function of you module
# and you should call 'firewalld.write' in the
# Write() function.
#
# Functionality of this module only changes the firewalld
# settings in memory, it never Reads or Writes the settings.
require "yast"
require "y2firewall/firewalld"
require "y2firewall/helpers/interfaces"
module Yast
# This class provide a set of methods to define a widget for handling with
# firewall interfaces configuration.
#
# @example Open a service in the firewall
#
# # Obtain the firewalld widget description (a widget with the firewalld
# # status, a checkbox for opening the service in all the interfaces and
# # a details button to decide per interface where should be opened.
#
# CWMFireallInterfaces.CreateOpenFirewallWidget(["smtp"])
#
# # Require the new firewalld library
# require 'y2firewall/firewalld'
#
# # In your Read method call firewalld.read to initializate the firewalld
# # object and all of its zones.
#
# Y2Firewall::Firewalld.instance.read
#
# # And finally call firewalld.write to apply the changes done through the
# # widget.
#
# Y2Firewall::Firewalld.instance.write
class CWMFirewallInterfacesClass < Module
include Y2Firewall::Helpers::Interfaces
include Yast::Logger
# [Array<String>] List of all interfaces relevant for firewall settings
attr_reader :allowed_interfaces
# [Array<String>] List of all the system network interfaces
attr_reader :all_interfaces
# [Boolean] Information if configuration was changed by user
attr_reader :configuration_changed
def main
Yast.import "UI"
textdomain "base"
Yast.import "CWM"
Yast.import "Label"
Yast.import "Mode"
Yast.import "NetworkInterfaces"
Yast.import "Popup"
Yast.import "Report"
Yast.import "Stage"
Yast.import "String"
# private variables
# List of all items of interfaces to the selection box
@interface_items = nil
@configuration_changed = false
@buggy_ifaces = []
end
# private functions
# Enable or disable the firewall details widget according to the status
# of "open firewall" checkbox
def EnableOrDisableFirewallDetails
return if !UI.WidgetExists(Id("_cwm_open_firewall"))
return if !UI.WidgetExists(Id("_cwm_firewall_details"))
enabled = Convert.to_boolean(
UI.QueryWidget(Id("_cwm_open_firewall"), :Value)
)
enabled = false if enabled.nil? || all_interfaces.empty?
UI.ChangeWidget(Id("_cwm_firewall_details"), :Enabled, enabled)
nil
end
# Set the firewall status label
# @param [Symbol] status symbol one of `off, `closed, `open_all, `custom, `not_installed
def SetFirewallLabel(status)
UI.ReplaceWidget(Id(:_cwm_firewall_status_rp), Label(firewall_status_label(status)))
nil
end
# Initialize the list of all known interfaces
def InitAllInterfacesList
# Do not read NetworkInterfaces when they are already read
if !Mode.config && !Mode.installation && !Mode.update
log.info("Reading NetworkInterfaces...")
NetworkInterfaces.Read
end
@all_interfaces = NetworkInterfaces.List("").reject { |i| i == "lo" }
@interface_items = all_interfaces.map { |i| Item(Id(i), interface_label(i)) }
nil
end
# Update the firewall status label according to the current status
def UpdateFirewallStatus
InitAllInterfacesList() if all_interfaces.nil?
status = current_firewall_status
log.info("Status: #{status}, All: #{all_interfaces}, Allowed: #{allowed_interfaces}")
SetFirewallLabel(status)
open = [:open_all, :custom].include?(status)
UI.ChangeWidget(Id("_cwm_open_firewall"), :Value, open)
nil
end
# Get the list of all interfaces that will be selected
#
# @param [Array<String>] ifaces a list of interfaces selected by the user
# @param [Boolean] _nm_ifaces_have_to_be_selected defines whether also NetworkManager have to be selected too
# @return a list of interfaces that will be opened
def Selected2Opened(ifaces, _nm_ifaces_have_to_be_selected)
log.info("Selected ifaces: #{ifaces}")
zone_names = ifaces.map do |name|
zone = interface_zone(name)
zone ? zone.name : default_zone.name
end
zone_names.uniq!
log.info("Ifaces zone names: #{zone_names}")
zone_ifaces =
zone_names.map do |zone_name|
zone = firewalld.find_zone(zone_name)
next [] unless zone
interfaces = zone.interfaces
next(interfaces) unless zone_name == default_zone.name
interfaces += default_interfaces
left_explicitly = interfaces.select { |i| ifaces.include?(i) }.uniq
log.info("Ifaces left in zone: #{left_explicitly}")
next [] if left_explicitly.empty?
interfaces
end
zone_ifaces.flatten.uniq
end
# Display popup with firewall settings details
def DisplayFirewallDetailsPopupHandler(widget)
widget = deep_copy(widget)
common_details_handler = Convert.convert(
Ops.get(widget, "common_details_handler"),
from: "any",
to: "void (map <string, any>)"
)
common_details_handler&.call(widget)
nil
end
# public functions
# general functions
# Initialize the list of allowed interfaces
# Changes the internal variables
# @param [Array<String>] services a list of services
def InitAllowedInterfaces(services)
service_status = {}
zone_services(services).each do |_s, status|
status.each do |iface, en|
service_status[iface] = service_status.fetch(iface, true) && en
end
end
service_status.select! { |_iface, en| en == true }
log.info("Status: #{service_status}")
@allowed_interfaces = service_status.keys
log.info "Default zone name: #{default_zone.name}"
log.info "Default interfaces: #{default_interfaces}"
log.info "Default_zone services: #{default_zone.services}"
if !default_interfaces.empty?
services.each do |service|
service_status[firewalld.default_zone] =
default_zone&.services&.include?(service)
end
@allowed_interfaces = (allowed_interfaces + default_interfaces).uniq if service_status[firewalld.default_zone]
end
log.info "Allowed interfaces: #{allowed_interfaces}"
@configuration_changed = false
nil
end
# Store the list of allowed interfaces
# Users the internal variables
# @param [Array<String>] services a list of services
def StoreAllowedInterfaces(services)
services = deep_copy(services)
# do not save anything if configuration didn't change
return if !configuration_changed
zones =
known_interfaces.each_with_object([]) do |iface, memo|
if allowed_interfaces.include?(iface.name)
zone_name = iface.zone ? iface.zone.name : firewalld.default_zone
memo << zone_name
end
end
firewalld.zones.each do |zone|
if zones.include?(zone.name)
services.each do |service|
zone.add_service(service) unless zone.services.include?(service)
end
else
services.each do |service|
zone.remove_service(service) if zone.services.include?(service)
end
end
end
nil
end
# Init function of the widget
# @param [Hash<String, Object>] _widget a widget description map
# @param [String] _key strnig the widget key
def InterfacesInit(_widget, _key)
# set the list of ifaces
InitAllInterfacesList() if all_interfaces.nil?
UI.ReplaceWidget(
Id("_cwm_interface_list_rp"),
MultiSelectionBox(
Id("_cwm_interface_list"),
# transaltors: selection box title
_("&Network Interfaces with Open Port in Firewall"),
@interface_items
)
)
# mark open ifaces as open
UI.ChangeWidget(
Id("_cwm_interface_list"),
:SelectedItems,
allowed_interfaces
)
nil
end
# Handle function of the widget
# @param [Hash<String, Object>] _widget a widget description map
# @param [String] _key strnig the widget key
# @param [Hash] event map event to be handled
# @return [Symbol] for wizard sequencer or nil
def InterfacesHandle(_widget, _key, event)
event_id = Ops.get(event, "ID")
if event_id == "_cwm_interface_select_all"
UI.ChangeWidget(
Id("_cwm_interface_list"),
:SelectedItems,
all_interfaces
)
return nil
end
if event_id == "_cwm_interface_select_none"
UI.ChangeWidget(Id("_cwm_interface_list"), :SelectedItems, [])
return nil
end
nil
end
# Store function of the widget
# @param [Hash<String, Object>] _widget a widget description map
# @param [String] _key strnig the widget key
# @param [Hash] _event map that caused widget data storing
def InterfacesStore(_widget, _key, _event)
allowed_interfaces = Convert.convert(
UI.QueryWidget(Id("_cwm_interface_list"), :SelectedItems),
from: "any",
to: "list <string>"
)
@allowed_interfaces = Selected2Opened(allowed_interfaces, false)
@configuration_changed = true
nil
end
# Validate function of the widget
# @param [Hash<String, Object>] _widget a widget description map
# @param [String] _key strnig the widget key
# @param [Hash] _event map event that caused the validation
# @return true if validation succeeded, false otherwise
def InterfacesValidate(_widget, _key, _event)
trusted_zone = firewalld.find_zone("trusted")
ifaces = Convert.convert(
UI.QueryWidget(Id("_cwm_interface_list"), :SelectedItems),
from: "any",
to: "list <string>"
) || []
log.info("Selected ifaces: #{ifaces}")
trusted_interfaces = trusted_zone ? trusted_zone.interfaces : []
if !trusted_interfaces.empty?
int_not_selected = []
trusted_interfaces.each do |interface|
int_not_selected << interface unless ifaces.include?(interface)
end
if !int_not_selected.empty?
log.warn("Unprotected internal interfaces not selected: #{int_not_selected}")
Report.Message(
Builtins.sformat(
_(
"These network interfaces assigned to internal network cannot be deselected:\n%1\n"
),
int_not_selected.join("\n")
)
)
ifaces = Convert.convert(
Builtins.union(ifaces, int_not_selected),
from: "list",
to: "list <string>"
)
log.info("Selected interfaces: #{ifaces}")
UI.ChangeWidget(Id("_cwm_interface_list"), :SelectedItems, ifaces)
return false
end
end
if ifaces.empty? && !Popup.YesNo(
_(
"No interface is selected. Service will not\n" \
"be available for other computers.\n" \
"\n" \
"Continue?"
)
)
return false
end
firewall_ifaces = Selected2Opened(ifaces, false)
log.info("firewall_ifaces: #{firewall_ifaces}")
added_ifaces = firewall_ifaces.reject { |i| ifaces.include?(i) }
log.info("added_ifaces: #{added_ifaces}")
removed_ifaces = ifaces.reject { |i| firewall_ifaces.include?(i) }
log.info("removed_ifaces: #{removed_ifaces}")
# to hide that special string
if !added_ifaces.empty? && !Popup.YesNo(
Builtins.sformat(
# yes-no popup
_(
"Because of firewalld settings, the port\n" \
"on the following interfaces will additionally be open:\n" \
"%1\n" \
"\n" \
"Continue?"
),
added_ifaces.join("\n")
)
)
return false
end
# to hide that special string
if !removed_ifaces.empty? && !Popup.YesNo(
Builtins.sformat(
# yes-no popup
_(
"Because of firewalld settings, the port\n" \
"on the following interfaces cannot be opened:\n" \
"%1\n" \
"\n" \
"Continue?"
),
removed_ifaces.join("\n")
)
)
return false
end
true
end
# Init function of the widget
# @param [String] key strnig the widget key
def InterfacesInitWrapper(key)
InterfacesInit(CWM.GetProcessedWidget, key)
nil
end
# Handle function of the widget
# @param [String] key strnig the widget key
# @param [Hash] event map event to be handled
# @return [Symbol] for wizard sequencer or nil
def InterfacesHandleWrapper(key, event)
event = deep_copy(event)
InterfacesHandle(CWM.GetProcessedWidget, key, event)
end
# Store function of the widget
# @param [String] key strnig the widget key
# @param [Hash] event map that caused widget data storing
def InterfacesStoreWrapper(key, event)
event = deep_copy(event)
InterfacesStore(CWM.GetProcessedWidget, key, event)
nil
end
# Validate function of the widget
# @param [String] key strnig the widget key
# @param [Hash] event map event that caused the validation
# @return true if validation succeeded, false otherwise
def InterfacesValidateWrapper(key, event)
event = deep_copy(event)
InterfacesValidate(CWM.GetProcessedWidget, key, event)
end
# Get the widget description map
# @param [Hash{String => Object}] settings a map of all parameters needed to create the widget properly
# <pre>
#
# Behavior manipulating functions (mandatory)
# - "get_allowed_interfaces" : list<string>() -- function that returns
# the list of allowed network interfaces
# - "set_allowed_interfaces" : void (list<string>) -- function that sets
# the list of allowed interfaces
#
# Additional settings:
# - "help" : string -- help to the whole widget. If not specified, generic help
# is used (button labels are patched correctly)
# </pre>
# @return [Hash] the widget description map
def CreateInterfacesWidget(settings)
settings = deep_copy(settings)
widget = HBox(
HSpacing(1),
VBox(
HSpacing(48),
VSpacing(1),
ReplacePoint(
Id("_cwm_interface_list_rp"),
MultiSelectionBox(
Id("_cwm_interface_list"),
# translators: selection box title
_("Network &Interfaces with Open Port in Firewall"),
[]
)
),
VSpacing(1),
HBox(
HStretch(),
HWeight(
1,
PushButton(
Id("_cwm_interface_select_all"),
# push button to select all network intefaces for firewall
_("Select &All")
)
),
HWeight(
1,
PushButton(
Id("_cwm_interface_select_none"),
# push button to deselect all network intefaces for firewall
_("Select &None")
)
),
HStretch()
),
VSpacing(1)
),
HSpacing(1)
)
help = "" # TODO
help = Ops.get_string(settings, "help", "") if Builtins.haskey(settings, "help")
ret = Convert.convert(
Builtins.union(
settings,
"widget" => :custom,
"custom_widget" => widget,
"help" => help,
"init" => fun_ref(
method(:InterfacesInitWrapper),
"void (string)"
),
"store" => fun_ref(
method(:InterfacesStoreWrapper),
"void (string, map)"
),
"handle" => fun_ref(
method(:InterfacesHandleWrapper),
"symbol (string, map)"
),
"validate_type" => :function,
"validate_function" => fun_ref(
method(:InterfacesValidateWrapper),
"boolean (string, map)"
)
),
from: "map",
to: "map <string, any>"
)
deep_copy(ret)
end
# Display the firewall interfaces selection as a popup
# @return [Symbol] return value of the dialog
def DisplayDetailsPopup(settings)
settings = deep_copy(settings)
# FIXME: breaks help if run in dialog with Tab!!!!!!
# settings stack must be created in CWM::Run
w = CWM.CreateWidgets(
["firewall_ifaces"],
"firewall_ifaces" => CreateInterfacesWidget(settings)
)
contents = VBox(
"firewall_ifaces",
ButtonBox(
PushButton(Id(:ok), Opt(:okButton, :key_F10), Label.OKButton),
PushButton(
Id(:cancel),
Opt(:cancelButton, :key_F9),
Label.CancelButton
)
)
)
contents = CWM.PrepareDialog(contents, w)
UI.OpenDialog(contents)
ret = CWM.Run(w, {})
UI.CloseDialog
ret
end
# firewall openning widget
# Initialize the open firewall widget
# @param [Hash{String => Object}] widget a map describing the whole widget
def OpenFirewallInit(widget, _key)
return unless open_firewall_widget?
services = widget.fetch("services", [])
InitAllInterfacesList()
InitAllowedInterfaces(services)
open_firewall = !allowed_interfaces.empty?
firewall_enabled = firewalld.enabled? && !all_interfaces.empty?
if !firewall_enabled
open_firewall = false
UI.ChangeWidget(Id("_cwm_open_firewall"), :Enabled, false)
end
UI.ChangeWidget(Id("_cwm_open_firewall"), :Value, open_firewall)
UpdateFirewallStatus()
EnableOrDisableFirewallDetails()
nil
end
# Store function of the widget
# @param [Hash] widget widget description
# @param [String] _key strnig the widget key
# @param [Hash] _event map that caused widget data storing
def OpenFirewallStore(widget, _key, _event)
return unless open_firewall_widget?
services = widget.fetch("services", [])
StoreAllowedInterfaces(services)
nil
end
# Handle the immediate start and stop of the service
# @param [Hash<String, Object>] widget a map describing the widget
# @param [String] _key strnig the widget key
# @param [Hash<String, Object>] event event to handle
# @return always nil
def OpenFirewallHandle(widget, _key, event)
widget = deep_copy(widget)
event = deep_copy(event)
event_id = Ops.get(event, "ID")
if event_id == "_cwm_firewall_details"
handle_firewall_details = Convert.convert(
Ops.get(widget, "firewall_details_handler"),
from: "any",
to: "symbol ()"
)
Builtins.y2milestone("FD: %1", handle_firewall_details)
ret = nil
Builtins.y2milestone("RT: %1", ret)
if handle_firewall_details.nil?
w = Builtins.filter(widget) { |k, _v| "services" == k }
DisplayDetailsPopup(w)
else
ret = handle_firewall_details.call
end
UpdateFirewallStatus()
EnableOrDisableFirewallDetails()
return ret
end
if event_id == "_cwm_open_firewall"
value = Convert.to_boolean(
UI.QueryWidget(Id("_cwm_open_firewall"), :Value)
)
Builtins.y2milestone("OF: %1", value)
@allowed_interfaces = value ? deep_copy(all_interfaces) : []
@buggy_ifaces = []
# Filtering out buggy ifaces
Builtins.foreach(@buggy_ifaces) do |one_iface|
@allowed_interfaces = Builtins.filter(allowed_interfaces) do |one_allowed|
one_allowed != one_iface
end
end
UpdateFirewallStatus()
EnableOrDisableFirewallDetails()
@configuration_changed = true
end
nil
end
# Init function of the widget
# @param [String] key strnig the widget key
def OpenFirewallInitWrapper(key)
OpenFirewallInit(CWM.GetProcessedWidget, key)
nil
end
# Store function of the widget
# @param [String] key strnig the widget key
# @param [Hash] event map that caused widget data storing
def OpenFirewallStoreWrapper(key, event)
event = deep_copy(event)
OpenFirewallStore(CWM.GetProcessedWidget, key, event)
nil
end
# Handle the immediate start and stop of the service
# @param [String] key strnig the widget key
# @param [Hash<String, Object>] event to handle
# @return always nil
def OpenFirewallHandleWrapper(key, event)
event = deep_copy(event)
OpenFirewallHandle(CWM.GetProcessedWidget, key, event)
end
# Check if the widget was modified
# @param [String] _key the widget key
# @return [Boolean] true if widget was modified
def OpenFirewallModified(_key)
@configuration_changed
end
# Enable the whole firewal widget
def EnableOpenFirewallWidget
return if !UI.WidgetExists(Id("_cwm_open_firewall"))
return if !UI.WidgetExists(Id("_cwm_firewall_details"))
UI.ChangeWidget(Id("_cwm_open_firewall"), :Enabled, true)
EnableOrDisableFirewallDetails()
nil
end
# Disable the whole firewal widget
def DisableOpenFirewallWidget
return if !UI.WidgetExists(Id("_cwm_open_firewall"))
return if !UI.WidgetExists(Id("_cwm_firewall_details"))
UI.ChangeWidget(Id("_cwm_open_firewall"), :Enabled, false)
UI.ChangeWidget(Id("_cwm_firewall_details"), :Enabled, false)
nil
end
# Check whether the whole firewall widget ( open port checkbox
# and fw details button) exists
# @return [Boolean] true if both widgets exist
def OpenFirewallWidgetExists
UI.WidgetExists(Id("_cwm_open_firewall")) &&
UI.WidgetExists(Id("_cwm_firewall_details"))
end
# Get the template for the help text to the firewall opening widget
# @param [Boolean] restart_displayed shold be true if "Save and restart" is displayed
# @return [String] help text template with %1 and %2 placeholders
def OpenFirewallHelpTemplate(restart_displayed)
# help text for firewall settings widget 1/3,
# %1 is check box label, eg. "Open Port in Firewall" (without quotes)
help = _(
"<p><b><big>Firewall Settings</big></b><br>\n" \
"To open the firewall to allow access to the service from remote computers,\n" \
"set <b>%1</b>.<br>"
)
if restart_displayed
# help text for firewall port openning widget 2/3, optional
# %1 is push button label, eg. "Firewall &Details" (without quotes)
# note: %2 is correct, do not replace with %1!!!
help = Ops.add(
help,
_(
"To select interfaces on which to open the port,\nclick <b>%2</b>.<br>"
)
)
end
# help text for firewall settings widget 3/3,
Ops.add(
help,
_("This option is available only if the firewall\nis enabled.</p>")
)
end
# Get the help text to the firewall opening widget
# @param [Boolean] restart_displayed shold be true if "Save and restart" is displayed
# @return [String] help text
def OpenFirewallHelp(restart_displayed)
Builtins.sformat(
OpenFirewallHelpTemplate(restart_displayed),
# part of help text - check box label, NO SHORTCUT!!!
_("Open Port in Firewall"),
# part of help text - push button label, NO SHORTCUT!!!
_("Firewall Details")
)
end
# Get the widget description map of the firewall enablement widget
# @param [Hash{String => Object}] settings a map of all parameters needed to create the widget properly
# <pre>
#
# - "services" : list<string> -- services identifications for the Firewall.ycp
# module
# - "display_details" : boolean -- true if the details button should be
# displayed
# - "firewall_details_handler" : symbol () -- function to handle the firewall
# details button. If returns something else than nil, dialog is
# exited with the returned symbol as value for wizard sequencer.
# If not specified, but "display_details" is true, common popup
# is used.
# - "open_firewall_checkbox" : string -- label of the check box
# - "firewall_details_button" : string -- label of the push button for
# changing firewall details
# - "help" : string -- help to the widget. If not specified, generic help
# is used
# </pre>
# @return [Hash] the widget description map
def CreateOpenFirewallWidget(settings)
settings = deep_copy(settings)
services = adapt_settings_services!(settings)
if services.empty?
log.error("Firewall services not specified") if services.empty?
return { "widget" => :custom, "custom_widget" => VBox(), "help" => "" }
end
if !firewalld.installed?
log.error("Firewall is not installed") if !firewalld.installed?
return { "widget" => :custom, "custom_widget" => not_installed_widget, "help" => "" }
end
if services.any? { |s| !firewalld.current_service_names.include?(s) }
return {
"widget" => :custom,
"custom_widget" => services_not_defined_widget(services),
"help" => ""
}
end
open_firewall_checkbox =
settings.fetch("open_firewall_checkbox", _("Open Port in &Firewall"))
firewall_details_button =
settings.fetch("firewall_details_button", _("Firewall &Details..."))
display_firewall_details =
settings.fetch("firewall_details_handler", settings.fetch("display_details", false))
help = settings.fetch("help", OpenFirewallHelp(display_firewall_details))
firewall_settings = CheckBox(
Id("_cwm_open_firewall"),
Opt(:notify),
open_firewall_checkbox
)
if display_firewall_details
firewall_settings = HBox(
firewall_settings,
HSpacing(2),
PushButton(Id("_cwm_firewall_details"), firewall_details_button)
)
end
firewall_settings = VBox(
Frame(
format(_("Firewall Settings for %{firewall}"), firewall: Y2Firewall::Firewalld::SERVICE),
VBox(
Left(firewall_settings),
Left(
ReplacePoint(
Id(:_cwm_firewall_status_rp),
# label text
Label(_("Firewall is open"))
)
)
)
)
)
{
"widget" => :custom,
"custom_widget" => firewall_settings,
"help" => help,
"init" => fun_ref(
method(:OpenFirewallInitWrapper),
"void (string)"
),
"store" => fun_ref(
method(:OpenFirewallStoreWrapper),
"void (string, map)"
),
"handle" => fun_ref(
method(:OpenFirewallHandleWrapper),
"symbol (string, map)"
),
"handle_events" => ["_cwm_firewall_details", "_cwm_open_firewall"]
}.merge(settings)
end
# Check if settings were modified by the user
# @return [Boolean] true if settings were modified
def Modified
firewalld.modified?
end
# Return the current status of the firewall related to the interfaces
# opened or available
#
# @return [Symbol] current firewall status
def current_firewall_status
# bnc #429861
return :not_installed if Stage.initial || !firewalld.installed?
return :off unless firewalld.enabled?
return :no_ifaces if all_interfaces.empty?
return :open_all if all_interfaces.size == allowed_interfaces.size
return :closed if allowed_interfaces.empty?
:custom
end
# Return the firewall status label for the given status
#
# @param status [Symbol] current status
# @return [String] current firewall status label
def firewall_status_label(status)
case status
when :not_installed
# bnc #429861
if Stage.initial
# label
_(
"Firewall cannot be adjusted during first stage installation."
)
else
# label
_("Firewall package is not installed.")
end
when :off
# label
_("Firewall is disabled")
when :closed
# label
_("Firewall port is closed")
when :open_all
# label
_("Firewall port is open on all interfaces")
when :custom
# label
_("Firewall port is open on selected interfaces")
when :no_ifaces
# label
_("No network interfaces are configured")
end
end
publish function: :InitAllowedInterfaces, type: "void (list <string>)"
publish function: :StoreAllowedInterfaces, type: "void (list <string>)"
publish function: :InterfacesInit, type: "void (map <string, any>, string)"
publish function: :InterfacesHandle, type: "symbol (map <string, any>, string, map)"
publish function: :InterfacesStore, type: "void (map <string, any>, string, map)"
publish function: :InterfacesValidate, type: "boolean (map <string, any>, string, map)"
publish function: :InterfacesInitWrapper, type: "void (string)"
publish function: :InterfacesHandleWrapper, type: "symbol (string, map)"
publish function: :InterfacesStoreWrapper, type: "void (string, map)"
publish function: :InterfacesValidateWrapper, type: "boolean (string, map)"
publish function: :CreateInterfacesWidget, type: "map <string, any> (map <string, any>)"
publish function: :DisplayDetailsPopup, type: "symbol (map <string, any>)"
publish function: :OpenFirewallInit, type: "void (map <string, any>, string)"
publish function: :OpenFirewallStore, type: "void (map <string, any>, string, map)"
publish function: :OpenFirewallHandle, type: "symbol (map <string, any>, string, map)"
publish function: :OpenFirewallInitWrapper, type: "void (string)"
publish function: :OpenFirewallStoreWrapper, type: "void (string, map)"
publish function: :OpenFirewallHandleWrapper, type: "symbol (string, map)"
publish function: :OpenFirewallModified, type: "boolean (string)"
publish function: :EnableOpenFirewallWidget, type: "void ()"
publish function: :DisableOpenFirewallWidget, type: "void ()"
publish function: :OpenFirewallWidgetExists, type: "boolean ()"
publish function: :OpenFirewallHelpTemplate, type: "string (boolean)"
publish function: :OpenFirewallHelp, type: "string (boolean)"
publish function: :CreateOpenFirewallWidget, type: "map <string, any> (map <string, any>)"
publish function: :Modified, type: "boolean ()"
private
# Return whether the '_cwm_open_firewall' widget exists or not logging the
# error in case of non-existence.
#
# @return [Boolean] true if the open firewall widget exists
def open_firewall_widget?
unless UI.WidgetExists(Id("_cwm_open_firewall"))
log.error("Widget _cwm_open_firewall does not exist")
return false
end
true
end
# Return an instance of Y2Firewall::Firewalld
#
# @return [Y2Firewall::Firewalld] a firewalld instance
def firewalld
Y2Firewall::Firewalld.instance
end
def zone_services(services)
services_status = {}
services.each do |service|
service_supported = firewalld.current_service_names.include?(service)
services_status[service] = {}
firewalld.zones.each do |zone|
next if (zone.interfaces || []).empty?
zone.interfaces.each do |interface|
services_status[service][interface] =
service_supported ? zone.services.include?(service) : nil
end
end
end
services_status
end
# Return the label to show for the given interface name
#
# @param name [String] interface name
# @return [String] label for given interface name
def interface_label(name)
return name if Mode.config
label = NetworkInterfaces.GetValue(name, "BOOTPROTO")
ipaddr = NetworkInterfaces.GetValue(name, "IPADDR")
# BNC #483455: Interface zone name
zone = firewalld.zones.find { |z| z.interfaces.include?(name) }
zone_full_name = zone ? zone.full_name : _("Interface is not assigned to any zone")
if label == "static" || label == "" || label.nil?
label = ipaddr
else
label.upcase!
label << "/#{ipaddr}" if !ipaddr.nil? && ipaddr != ""
end
if label.nil? || label == ""
name
else
"#{name} (#{label} / #{zone_full_name})"
end
end
# Return a YaST::Term alerting that the firewall is not configurable
# because some services are not configurable and also with a list of the
# unsupported firewalld services.
#
# @return [Yast::Term] widget with a summary of supported services
def services_not_defined_widget(services)
services_list =
services.map do |service|
if firewalld.current_service_names.include?(service)
# TRANSLATORS: do not modify '%{service}', it will be replaced with service name.
# TRANSLATORS: item in a list, '-' is used as marker. Feel free to change it
HBox(HSpacing(2), Left(Label(format(_("- %{service}"), service: service))))
else
# TRANSLATORS: do not modify '%{service}', it will be replaced with service name.
# TRANSLATORS: item in a list, '-' is used as marker. Feel free to change it
HBox(HSpacing(2), Left(Label(format(_("- %{service} (Not available)"), service: service))))
end
end
VBox(
Frame(
_("Firewall not configurable"),
VBox(
Left(Label(_("Some firewalld services are not available:"))),
*services_list,
Left(Label(_("These services must be defined in order to configure the firewall.")))
)
)
)
end
# Return a YaST::Term alerting that the firewall is not configurable
# because it is not installed
#
# @return [Yast::Term] widget with not installed label
def not_installed_widget
VBox(
Frame(
_("Firewall not configurable"),
VBox(
Left(Label(firewall_status_label(:not_installed)))
)
)
)
end
# Modify the services of a given widget settings definition removing old
# "services:" prepend from them.
#
# @example
#
# settings = { "services" => ["service:apache2", "service:apache2-ssl"] }
# adapt_settings_services!(settings) #=> ["apache2", "apache2-ssl"]
# settings #=> { "services" => ["apache2", "apache2-ssl"] }
#
# @param settings[Hash{String => Object}] settings a map of all parameters needed
# to create the widget properly
# @return [Array<String>] converted widget settings services names
def adapt_settings_services!(settings)
services = settings.fetch("services", []) || []
return [] if services.empty?
services.each { |s| s.sub!(/service:/, "") }
settings["services"] = services.select { |s| s && !s.empty? }
end
end
CWMFirewallInterfaces = CWMFirewallInterfacesClass.new
CWMFirewallInterfaces.main
end