ACC SHELL
/**
* File: modules/SuSEFirewallServices.ycp
* Package: Firewall Services, Ports Aliases.
* Summary: Definition of Supported Firewall Services and Port Aliases.
* Authors: Lukas Ocilka <locilka@suse.cz>
*
* $Id: SuSEFirewallServices.ycp 59655 2009-11-20 11:54:50Z locilka $
*
* Global Definition of Firewall Services
* Defined using TCP, UDP and RPC ports and IP protocols and Broadcast UDP
* ports. Results are cached, so repeating requests are answered faster.
*/
{
module "SuSEFirewallServices";
textdomain "base";
import "FileUtils";
//
//
// PLEASE, DO NOT ADD MORE SERVICES.
// ADD THE SERVICE DEFINITION TO THE PACKAGE TO WHICH IT BELONGS.
// USE /etc/sysconfig/SuSEfirewall2.d/services/TEMPLATE FOR THAT.
// MORE INFORMATION IN FEATURE #300687: Ports for SuSEfirewall added via packages.
// ANOTHER REFERENCE: Bugzilla #246911.
//
// See also http://en.opensuse.org/SuSEfirewall2/Service_Definitions_Added_via_Packages
//
/***
* Names assigned to Port and Protocol numbers can be found
* here:
*
* http://www.iana.org/assignments/protocol-numbers
* http://www.iana.org/assignments/port-numbers
*/
/**
*
* Format of SERVICES
*
* "service-id" : $[
* "name" : _("Service Name"),
* "tcp_ports" : list <tcp_ports>,
* "udp_ports" : list <udp_ports>,
* "rpc_ports" : list <rpc_ports>,
* "ip_protocols" : list <ip_protocols>,
* "broadcast_ports" : list <broadcast_ports>,
* ],
*
*/
string services_definitions_in = "/etc/sysconfig/SuSEfirewall2.d/services/";
// please, check it with configuration in refresh-srv-def-by-pkgs-trans.sh script
string fw_services_textdomain = "firewall-services";
// firewall needs restarting
boolean sfws_modified = false;
map <string, string> known_services_features = $[
"TCP" : "tcp_ports",
"UDP" : "udp_ports",
"RPC" : "rpc_ports",
"IP" : "ip_protocols",
"BROADCAST" : "broadcast_ports",
];
map <string, string> known_metadata = $[
"Name" : "name",
"Description" : "description",
];
/* this is how services defined by package are distinguished */
string ser_def_by_pkg_string = "service:";
/**
* Services definitions for conversion to the new ones.
*/
global define map <string, map<string, any> > OLD_SERVICES = $[
"http" : $[
"tcp_ports" : [ "http" ],
"convert_to" : [ "service:apache2", "service:lighttpd" ],
],
"https" : $[
"tcp_ports" : [ "https" ],
"convert_to" : [ "service:apache2-ssl", "service:lighttpd-ssl" ],
],
"smtp" : $[
"tcp_ports" : [ "smtp" ],
"convert_to" : [],
],
"pop3" : $[
"tcp_ports" : [ "pop3" ],
"convert_to" : [],
],
"pop3s" : $[
"tcp_ports" : [ "pop3s" ],
"convert_to" : [],
],
"imap" : $[
"tcp_ports" : [ "imap" ],
"convert_to" : [ "service:courier-imapd" ],
],
"imaps" : $[
"tcp_ports" : [ "imaps" ],
"convert_to" : [ "service:courier-imap-ssl" ],
],
"samba-server" : $[
"tcp_ports" : [ "netbios-ssn", "microsoft-ds" ], // TCP: 139, 445
"udp_ports" : [ "netbios-ns", "netbios-dgm" ], // UDP: 137, 138
"broadcast_ports" : [ "netbios-ns", "netbios-dgm" ], // UDP: 137, 138
"convert_to" : [],
],
"ssh" : $[
"tcp_ports" : [ "ssh" ],
"convert_to" : [ "service:sshd" ],
],
"rsync" : $[
"tcp_ports" : [ "rsync" ],
"convert_to" : [],
],
"dhcp-server" : $[
"udp_ports" : [ "bootps" ],
"broadcast_ports" : [ "bootps" ],
"convert_to" : [ "service:dhcp-server" ],
],
"dhcp-client" : $[
"udp_ports" : [ "bootpc" ],
"convert_to" : [],
],
"dns-server" : $[
"tcp_ports" : [ "domain" ],
"udp_ports" : [ "domain" ],
"convert_to" : [ "service:bind" ],
],
"nfs-client" : $[
"rpc_ports" : [ "portmap", "status", "nlockmgr" ],
"convert_to" : [ "service:nfs-client" ],
],
"nfs-server" : $[
"rpc_ports" : [ "portmap", "status", "nlockmgr", "mountd", "nfs", "nfs_acl" ],
"convert_to" : [],
],
"nis-client" : $[
"rpc_ports" : [ "portmap", "ypbind" ],
"convert_to" : [ "service:ypserv" ],
],
"nis-server" : $[
"rpc_ports" : [ "portmap", "ypserv", "fypxfrd", "ypbind", "yppasswdd" ],
"convert_to" : [],
],
// Default SUSE installation
"vnc" : $[
"tcp_ports" : [ "5801", "5901" ],
"convert_to" : [],
],
"tftp" : $[
"udp_ports" : [ "tftp" ],
"convert_to" : [],
],
// Internet Printing Protocol as a Server
"ipp-tcp" : $[
"tcp_ports" : [ "ipp" ],
"convert_to" : [],
],
// Internet Printing Protocol as a Client
// IPP Client needs to listen for broadcast messages
"ipp-udp" : $[
"udp_ports" : [ "ipp" ],
"broadcast_ports" : [ "ipp" ],
"convert_to" : [],
],
"ntp-server" : $[
"udp_ports" : [ "ntp" ],
"broadcast_ports" : [ "ntp" ],
"convert_to" : [ "service:ntp" ],
],
"ldap" : $[
"tcp_ports" : [ "ldap" ],
"convert_to" : [ "service:openldap" ],
],
"ldaps" : $[
"tcp_ports" : [ "ldaps" ],
"convert_to" : [],
],
"ipsec" : $[
"udp_ports" : [ "isakmp", "ipsec-nat-t" ],
"ip_protocols" : [ "esp" ],
"convert_to" : [],
],
"slp-daemon" : $[
"tcp_ports" : [ "svrloc" ],
"udp_ports" : [ "svrloc" ],
"broadcast_ports" : [ "svrloc" ],
"convert_to" : [],
],
// See bug #118200 for more information
"xdmcp" : $[
"tcp_ports" : [ "xdmcp" ],
"udp_ports" : [ "xdmcp" ],
"broadcast_ports" : [ "xdmcp" ],
"convert_to" : [],
],
// See bug #118196 for more information
"fam" : $[
"rpc_ports" : [ "sgi_fam" ],
"convert_to" : [],
],
// requested by thofmann
"open-pbs" : $[
// /etc/services says: The following entries are invalid, but needed
"tcp_ports" : [ "pbs", "pbs_mom", "pbs_resmom", "pbs_sched" ],
"udp_ports" : [ "pbs_resmom" ],
"convert_to" : [],
],
"mysql-server" : $[
"tcp_ports" : [ "mysql" ],
"convert_to" : [ "service:mysql" ],
],
"iscsi-server" : $[
"tcp_ports" : [ "iscsi-target" ],
"convert_to" : [ "service:iscsitarget" ],
],
];
/**
* Definitions were moved to OLD_SERVICES for conversion
* and replaced by definitions in packages.
* FATE #300687: Ports for SuSEfirewall added via packages.
*/
define map <string, map<string, any> > SERVICES = $[];
/**
* Returns whether the service ID is defined by package.
* Returns 'false' if it isn't.
*
* @param string service
* @return boolean whether service is defined by package
*
* @example
* ServiceDefinedByPackage ("http-server") -> false
* ServiceDefinedByPackage ("service:http-server") -> true
*/
global boolean ServiceDefinedByPackage (string service) {
return regexpmatch (service, "^" + ser_def_by_pkg_string + ".*");
}
/**
* Creates a file name from service name defined by package.
* Service MUST be defined by package, otherwise it returns 'nil'.
*
* @param string service name (e.g., 'service:abc')
* @return string file name (e.g., 'abc')
*
* @example
* GetFilenameFromServiceDefinedByPackage ("service:abc") -> "abc"
* GetFilenameFromServiceDefinedByPackage ("abc") -> nil
*/
global string GetFilenameFromServiceDefinedByPackage (string service) {
if (! ServiceDefinedByPackage (service)) {
y2error ("Service %1 is not defined by package", service);
return nil;
}
string ret = regexpsub (service, "^" + ser_def_by_pkg_string + "(.*)$", "\\1");
if (ret == nil) y2error ("Wrong regexpsub definition");
return ret;
}
/**
* Returns SCR Agent definition.
*
* @return term with agent definition
* @param string full filename path (to read by this agent)
*/
term GetMetadataAgent (string filefullpath) {
return
`IniAgent(filefullpath, $[
"options" : [ "global_values", "flat", "read_only", "ignore_case_regexps" ],
"comments": [
// jail followed by anything but jail (immediately)
"^[ \t]*#[^#].*$",
// jail alone
"^[ \t]*#$",
// (empty space)
"^[ \t]*$",
// sysconfig entries
"^[ \t]*[a-zA-Z0-9_]+.*",
],
"params" : [
$[ "match" : [ "^##[ \t]*([^:]+):[ \t]*(.*)[ \t]*$", "%s: %s" ] ],
],
]);
}
/**
* Reads definition of services that can be used in FW_CONFIGURATIONS_[EXT|INT|DMZ]
* in SuSEfirewall2.
*
* @return boolean if successful
*/
global define boolean ReadServicesDefinedByRPMPackages () {
if (! FileUtils::Exists (services_definitions_in) || ! FileUtils::IsDirectory (services_definitions_in)) {
y2error ("Cannot read %1", services_definitions_in);
return false;
}
list <string> all_definitions = (list<string>) SCR::Read (.target.dir, services_definitions_in);
// skip the TEMPLATE file
all_definitions = filter (string filename, all_definitions, { return filename != "TEMPLATE"; });
string one_definition = nil;
string filefullpath = nil;
// for all files in that directory
foreach (string filename, all_definitions, {
// "service:abc_server" to distinguis between dynamic definition and the static one
one_definition = ser_def_by_pkg_string + filename;
// Do not read already defined service
// Just read only new definitions
if (SERVICES[one_definition]:$[] != $[]) {
return;
}
filefullpath = services_definitions_in + filename;
SERVICES[one_definition] = $[];
// Registering sysconfig agent for this file
if (! SCR::RegisterAgent (.firewall_service_definition, `ag_ini (`SysConfigFile (filefullpath)))) {
y2error ("Cannot register agent for %1", filefullpath);
return;
}
string definition = nil;
list <string> definition_values = nil;
foreach (string known_feature, string map_key, known_services_features, {
definition = (string) SCR::Read (add(.firewall_service_definition, known_feature));
if (definition == nil) definition = "";
// map of services contains list of entries
definition_values = splitstring (definition, " \t\n");
definition_values = filter (string one_value, definition_values, { return one_value != ""; });
SERVICES[one_definition, map_key] = definition_values;
});
// Unregistering sysconfig agent for this file
SCR::UnregisterAgent (.firewall_service_definition);
// Fallback for presented service
SERVICES[one_definition, "name"] = sformat (_("Service: %1"), filename);
SERVICES[one_definition, "description"] = "";
// Registering sysconfig agent for this file (to get metadata)
if (SCR::RegisterAgent (.firewall_service_metadata, `ag_ini (GetMetadataAgent(filefullpath)))) {
foreach (string metadata_feature, string metadata_key, known_metadata, {
definition = (string) SCR::Read (add(.firewall_service_metadata, metadata_feature));
if (definition == nil || definition == "") return;
// call gettext to translate the metadata
SERVICES[one_definition, metadata_key] = dgettext (fw_services_textdomain, definition);
});
SCR::UnregisterAgent (.firewall_service_metadata);
} else {
y2error ("Cannot register agent for %1 (metadata)", filefullpath);
}
y2debug ("'%1' -> %2", filename, SERVICES[one_definition]:$[]);
});
return true;
}
/**
* Function returns if the service_id is a known (defined) service
*
* @param string service_id
* @return boolean if is known (defined)
*/
global define boolean IsKnownService (string service_id) {
if (SERVICES[service_id]:$[] == $[]) {
return false;
} else {
return true;
}
}
/**
* Function returns the map of supported (known) services.
*
* @return map <string, string> supported services
*
* @struct
* $[ service_id : localized_service_name ]
* $[
* "dns-server" : "DNS Server",
* "vnc" : "Remote Administration",
* ]
*/
global define map <string, string> GetSupportedServices () {
map <string, string> supported_services = $[];
foreach (string service_id, map <string, any> service_definition, SERVICES, {
supported_services[service_id] =
// TRANSLATORS: Name of unknown service. This should never happen, just for cases..., %1 is a requested service id like nis-server
(string) service_definition["name"]:sformat(_("Unknown service '%1'"), service_id);
});
return supported_services;
}
/**
* Returns list of service-ids defined by packages.
*
* @return list <string> service ids
*/
global define list <string> GetListOfServicesAddedByPackage () {
list <string> ret = maplist (string service_id, map <string, any> service_definition, SERVICES, {
return service_id;
});
ret = filter (string service_id, ret, {
return ServiceDefinedByPackage (service_id);
});
return ret;
}
/**
* Function returns needed TCP ports for service
*
* @param string service
* @return list <string> of needed TCP ports
*/
global define list <string> GetNeededTCPPorts (string service) {
return SERVICES[service,"tcp_ports"]:[];
}
/**
* Function returns needed UDP ports for service
*
* @param string service
* @return list <string> of needed UDP ports
*/
global define list <string> GetNeededUDPPorts (string service) {
return SERVICES[service,"udp_ports"]:[];
}
/**
* Function returns needed RPC ports for service
*
* @param string service
* @return list <string> of needed RPC ports
*/
global define list <string> GetNeededRPCPorts (string service) {
return SERVICES[service,"rpc_ports"]:[];
}
/**
* Function returns needed IP protocols for service
*
* @param string service
* @return list <string> of needed IP protocols
*/
global define list <string> GetNeededIPProtocols (string service) {
return SERVICES[service,"ip_protocols"]:[];
}
/**
* Function returns description of a firewall service
*
* @param string service
* @return string service description
*/
global define string GetDescription (string service) {
return SERVICES[service,"description"]:"";
}
/**
* Sets that configuration was modified
*/
global void SetModified () {
sfws_modified = true;
}
/**
* Sets that configuration was not modified
*/
global void ResetModified () {
sfws_modified = false;
}
/**
* Returns whether configuration was modified
*
* @return boolean modified
*/
global boolean GetModified () {
return sfws_modified;
}
/**
* Function returns needed ports allowing broadcast
*
* @param string service
* @return list <string> of needed broadcast ports
*/
global define list <string> GetNeededBroadcastPorts (string service) {
return SERVICES[service,"broadcast_ports"]:[];
}
/**
* Function returns needed ports and protocols for service.
* Function cares about if the service is defined or not.
*
* @param string service
* @return map <string, list <string> > of needed ports and protocols
*
* @example
* GetNeededPortsAndProtocols ("service:aaa") -> $[
* "tcp_ports" : [ "122", "ftp-data" ],
* "udp_ports" : [ "427" ],
* "rpc_ports" : [ "portmap", "ypbind" ],
* "ip_protocols" : [],
* "broadcast_ports" : [ "427" ],
* ];
*/
global define map <string, list <string> > GetNeededPortsAndProtocols (string service) {
map <string, list <string> > needed = $[];
// Service defined by package, not known now
// Reading new definitions
if (ServiceDefinedByPackage (service) && ! IsKnownService (service)) {
y2milestone ("Service %1 is not known, searching for new definitions...", service);
ReadServicesDefinedByRPMPackages ();
}
if (! IsKnownService(service)) {
y2error("Uknown service '%1'", service);
y2milestone("Known services: %1", SERVICES);
return nil;
}
needed["tcp_ports"] = GetNeededTCPPorts(service);
needed["udp_ports"] = GetNeededUDPPorts(service);
needed["rpc_ports"] = GetNeededRPCPorts(service);
needed["ip_protocols"] = GetNeededIPProtocols(service);
needed["broadcast_ports"] = GetNeededBroadcastPorts(service);
return needed;
}
/**
* Immediately writes the configuration of service defined by package to the
* service definition file. Service must be defined by package, this function
* doesn't work for hard-coded services (SuSEFirewallServices).
*
* @param string service ID (e.g., "service:ssh")
* @param map <string, list <string> > of full service definition
* @returns boolean if successful (nil in case of developer's mistake)
*
* @see IsKnownService()
* @see ServiceDefinedByPackage()
*
* @example
* SetNeededPortsAndProtocols (
* "service:something",
* $[
* "tcp_ports" : [ "22", "ftp-data", "400:420" ],
* "udp_ports" : [ ],
* "rpc_ports" : [ "portmap", "ypbind" ],
* "ip_protocols" : [ "esp" ],
* "broadcast_ports" : [ ],
* ]
* );
*/
global boolean SetNeededPortsAndProtocols (string service, map <string, list <string> > store_definition) {
if (! ServiceDefinedByPackage (service)) {
y2error ("Service %1 is not defined by package", service);
return nil;
}
// fallback
if (! IsKnownService (service)) {
ReadServicesDefinedByRPMPackages ();
}
if (! IsKnownService (service)) {
y2error ("Service %1 is unknown", service);
return nil;
}
// create the filename from service name
string filename = GetFilenameFromServiceDefinedByPackage (service);
if (filename == nil || filename == "") {
y2error ("Can't operate with fileaname '%1' created from '%2'", filename, service);
return false;
}
// full path to the filename
string filefullpath = sformat ("%1/%2", services_definitions_in, filename);
if (! FileUtils::Exists (filefullpath)) {
y2error ("File '%1' doesn't exist", filefullpath);
return false;
}
// Registering sysconfig agent for that file
if (! SCR::RegisterAgent (.firewall_service_definition, `ag_ini (`SysConfigFile (filefullpath)))) {
y2error ("Cannot register agent for %1", filefullpath);
return false;
}
map <string, string> ks_features_backward =
mapmap (string sysconfig_id, string ycp_id, known_services_features, {
return $[ ycp_id : sysconfig_id ];
});
boolean write_ok = true;
// we can have this service already in memory
map <string, list <string> > new_store_definition = store_definition;
foreach (string ycp_id, list <string> one_def, store_definition, {
string sysconfig_id = ks_features_backward[ycp_id]:nil;
if (sysconfig_id == nil) {
y2error ("Unknown key '%1'", ycp_id);
write_ok = false;
return;
}
one_def = filter (string one_def_item, one_def, {
// filter out strange and wrong definitions
return (one_def_item != nil && one_def_item != "" && ! regexpmatch (one_def_item, "^ *$"));
});
if (! SCR::Write (
add (.firewall_service_definition, sysconfig_id),
mergestring (one_def, " ")
)) {
y2error ("Cannot write %1 to %2",
mergestring (one_def, " "),
add (.firewall_service_definition, sysconfig_id)
);
write_ok = false;
return;
}
// new definition of the service
new_store_definition[ycp_id] = one_def;
});
// flush the cache to the disk
if (write_ok) {
if (! SCR::Write (.firewall_service_definition, nil)) {
y2error ("Cannot write to disk!");
write_ok = false;
} else {
// not only store to disk but also to the memory
if (SERVICES[service]:nil == nil) SERVICES[service] = $[];
SERVICES[service] = new_store_definition;
SetModified();
}
}
// Unregistering sysconfig agent for that file
SCR::UnregisterAgent (.firewall_service_definition);
y2milestone ("Call SetNeededPortsAndProtocols(%1, ...) result is %2", service, write_ok);
return write_ok;
}
/**
* Function returns list of possibly conflicting services.
* Conflicting services are for instance nis-client and nis-server.
* DEPRECATED - we currently don't have such services - services are defined by packages.
*
* @return list <string> of conflicting services
*/
global define list <string> GetPossiblyConflictServices () {
return [];
}
/* EOF */
}
ACC SHELL 2018