ACC SHELL

Path : /usr/share/YaST2/modules/
File Upload :
Current File : //usr/share/YaST2/modules/SuSEFirewallServices.ycp

/**
 * 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