ACC SHELL

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

/**
 * File:
 *   modules/Nis.ycp
 *
 * Module:
 *   Configuration of NIS client
 *
 * Summary:
 *   NIS client configuration data, I/O functions.
 *
 * Authors:
 *   Jan Holesovsky <kendy@suse.cz>
 *   Dan Vesely <dan@suse.cz>
 *   Martin Vidner <mvidner@suse.cz>
 *
 * $Id: Nis.ycp 57495 2009-06-08 13:06:03Z jsuchome $
 *
 */

{
    module "Nis";
    textdomain "nis";

    import "Address";
    import "Autologin";
    import "IP";
    import "Message";
    import "Nsswitch";
    import "Package";
    import "Progress";
    import "Report";
    import "Service";
    import "Summary";
    import "SuSEFirewall";
    import "Wizard";

    /* default value of settings modified */
    global boolean modified = false;


    /**
     * Function sets internal variable, which indicates, that any
     * settings were modified, to "true"
     */
    global define void SetModified () {
        modified = true;
    }

    /**
     * Functions which returns if the settings were modified
     * @return boolean  settings were modified
     */
    global define boolean GetModified () {
        return modified;
    }
    /**
     * Required packages for this module to operate
     *
     */
    global list<string> required_packages = ["ypbind"];

    /**
     * Should ypbind be started at boot?
     * If not, other settings are not touched.
     */
    global boolean start = false;

    /**
     * IP addresses of NIS servers.
     */
    global list <string> servers = [];

    /**
     * @return Access the servers as a string
     */
    global string GetServers () {
	return mergestring (servers, " ");
    }

    /**
     * Set the servers from a string
     * @param servers_s a whitespace separated list
     */
    global void SetServers (string servers_s) {
	servers = filter (string s, splitstring (servers_s, " \t"),``(s != ""));
    }

    /**
     * Broadcast for the default domain?
     * (New in ypbind-1.12)
     */
    global boolean default_broadcast = false;

    /**
     * Servers for a multiple-domain configuration.
     * Keys are domains, values are lists of servers (strings).
     * The domains must be the same as for multidomain_broadcast
     * @see multidomain_broadcast
     */
    global map<string,list> multidomain_servers = $[];

    /**
     * Servers for a multiple-domain configuration.
     * Whether a broadcast will be done if the servers don't respond.
     * Keys are domains, values are booleans.
     * The domains must be the same as for multidomain_servers
     * @see multidomain_servers
     * @see global_broadcast
     */
    global map<string,boolean> multidomain_broadcast = $[];

    /**
     * If this option is set, ypbind will ignore /etc/yp.conf and use
     * a broadcast call to find a NIS server in the local subnet. You
     * should avoid to use this, it is a big security risk.
     * @see multidomain_broadcast
     * @see default_broadcast
     */
    global boolean global_broadcast = false;

    global map slp_domain = $[];

    // netconfig policy
    global string policy = "auto";

    // which service mapper is used (rpcbind/portmap)
    string rpc_mapper	= "rpcbind";

    string domain = "";
    string old_domain = nil;
    boolean domain_changed = false;

    list<string> static_keylist = [];

    /**
     * Read Netconfig configuration
     */
    global void getNetconfigValues() {

	y2milestone("getNetconfigValues called");

	// reset the values
	multidomain_servers	= $[];
	multidomain_broadcast	= $[];
	slp_domain		= $[];
	servers			= [];

	policy = (string)SCR::Read(.sysconfig.network.config.NETCONFIG_NIS_POLICY);
	y2milestone("policy : %1", policy);
	if (policy == nil) policy = "";

	map<string, map<string, string> > staticVals = $[];
	list<string> keylist = SCR::Dir (.sysconfig.network.config);

	y2milestone("KEYLIST: %1", keylist);

	if (keylist == nil) keylist	= [];

	foreach (string key, keylist, {

	    if (!issubstring(key, "NETCONFIG_NIS_STATIC_DOMAIN") &&
		!issubstring(key, "NETCONFIG_NIS_STATIC_SERVERS"))
		continue;

	    string value =(string)SCR::Read(add(.sysconfig.network.config,key));

	    y2milestone("Found %1 = %2", key, value);
	    string num = "";

	    if (key == "NETCONFIG_NIS_STATIC_DOMAIN")
	    {
		staticVals["0"] = add (staticVals["0"]:$[], "DOMAIN", value);
	    }
	    else if (key == "NETCONFIG_NIS_STATIC_SERVERS")
	    {
		staticVals["0"] = add (staticVals["0"]:$[], "SERVERS", value);
	    }
	    else
	    {
		static_keylist = add (static_keylist, key);
		num = regexpsub(key, "^NETCONFIG_NIS_STATIC_(DOMAIN|SERVERS)_(.*)", "\\2");
		y2milestone("try to get the number: %1", num);
		if (issubstring(key, "NETCONFIG_NIS_STATIC_DOMAIN"))
		{
		    staticVals[num] = add(staticVals[num]:$[], "DOMAIN", value);		}
		else if (issubstring(key, "NETCONFIG_NIS_STATIC_SERVERS"))
		{
		    staticVals[num] = add(staticVals[num]:$[], "SERVERS",value);
		}
	    }
	});

	y2milestone("STATIC VALS: %1", staticVals);

	foreach (string key, map<string, string> value, staticVals, {
	    if (value["DOMAIN"]:nil == "")
	    {
		if (value["SERVERS"]:"" != "")
		{
		    string sr = GetServers() + " " + value["SERVERS"]:"";
		    SetServers (sr);
		}
	    }
	    else if (value["DOMAIN"]:nil == "broadcast")
	    {
		global_broadcast	= true;
	    }
	    else if (value["DOMAIN"]:"" != "")
	    {
		if (value["SERVERS"]:nil == "broadcast")
		{
		    if (key == "0")
		    {
			default_broadcast = true;
		    }
		    multidomain_broadcast[value["DOMAIN"]:""]	= true;
		}
		else if (value["SERVERS"]:nil == "slp")
		{
		    slp_domain[value["DOMAIN"]:""]	= true;
		}
		else if (value["SERVERS"]:"" != "")
		{
		    multidomain_servers[value["DOMAIN"]:""] =
			splitstring (value["SERVERS"]:"", " ");
		}
	    }
	});

	foreach (string domain, list value, multidomain_servers, {
	    if (!haskey (multidomain_broadcast, domain))
	    {
		multidomain_broadcast[domain]	= false;
	    }
	});

	foreach (string domain, boolean value, multidomain_broadcast, {
	    if (!haskey(multidomain_servers, domain))
	    {
		multidomain_servers [domain]	= [];
	    }
	});

	foreach (string domain, any value, (map<string,any>) slp_domain, {
	    if (!haskey (multidomain_servers, domain))
	    {
		multidomain_servers[domain]	= [];
	    }
	});

	y2milestone("Servers: %1", servers);
	y2milestone("multidomain_servers: %1", multidomain_servers);
	y2milestone("multidomain_broadcast: %1", multidomain_broadcast);
	y2milestone("slp_domain: %1", slp_domain);
	y2milestone("default_broadcast: %1", default_broadcast);
    }

    /**
     * Write the netconfig configuration
     */
    global boolean setNetconfigValues() {

	SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_POLICY, policy);

	foreach (string domain, list value, multidomain_servers, {
	    if (!haskey (multidomain_broadcast, domain))
	    {
		multidomain_broadcast[domain]	= false;
	    }
	});

	foreach (string domain, boolean value, multidomain_broadcast, {
	    if (!haskey (multidomain_servers, domain))
	    {
		multidomain_servers[domain]	= [];
	    }
	});

	foreach (string domain, any value, (map<string, any>) slp_domain, {
	    if (!haskey (multidomain_servers, domain))
	    {
		multidomain_servers[domain]	= [];
	    }
	});

	foreach (string key, static_keylist, {
	    y2milestone("Remove : %1", key);
	    SCR::Write (add (.sysconfig.network.config, key), nil);
	});

        /* remove the content of this */
	SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, "");
	SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, "");


	y2milestone("Servers: %1", servers);
	y2milestone("multidomain_servers: %1", multidomain_servers);
	y2milestone("multidomain_broadcast: %1", multidomain_broadcast);
	y2milestone("slp_domain: %1", slp_domain);
	y2milestone("default_broadcast: %1", default_broadcast);

	integer cnt = 0;
	if (size (servers) > 0)
	{
	    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN,
		"");
	    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS,
		mergestring (servers, " "));
	    cnt = cnt + 1;
	}

	foreach (string dom, list<string> srvs, (map<string,list<string> >)
	    multidomain_servers,
	{
	    if (dom == "") continue;
	    if (size(srvs) > 0)
	    {
		if (cnt == 0)
		{
		    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, dom);
		    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, mergestring (srvs, " "));
		}
		else
		{
		    SCR::Write (add (.sysconfig.network.config, "NETCONFIG_NIS_STATIC_DOMAIN_"+cnt), dom);
		    SCR::Write (add (.sysconfig.network.config, "NETCONFIG_NIS_STATIC_SERVERS_"+cnt), mergestring(srvs, " "));
		}
		cnt	= cnt + 1;
	    }
	    if (multidomain_broadcast[dom]:false == true)
	    {
		if (cnt == 0)
		{
		    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, dom);
		    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, "broadcast");
		}
		else
		{
		    SCR::Write (add (.sysconfig.network.config, "NETCONFIG_NIS_STATIC_DOMAIN_"+cnt), dom);
		    SCR::Write (add (.sysconfig.network.config, "NETCONFIG_NIS_STATIC_SERVERS_"+cnt), "broadcast");
		}
		cnt	= cnt + 1;
	    }
	    if (slp_domain[dom]:false == true)
	    {
		if (cnt == 0)
		{
		    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, dom);
		    SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, "slp");
		}
		else
		{
		    SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_DOMAIN_"+cnt), dom);
		    SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_SERVERS_"+cnt), "slp");
		}
		cnt	= cnt + 1;
	    }
	});

	if (default_broadcast == true)
	{
	    if (cnt == 0)
	    {
		SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, domain);
		SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, "broadcast");
	    }
	    else
	    {
		SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_DOMAIN_"+cnt), domain);
		SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_SERVERS_"+cnt), "broadcast");
	    }
	    cnt = cnt + 1;
	}
	else if (global_broadcast == true)
	{
	    if (cnt == 0)
	    {
		SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_STATIC_DOMAIN, "broadcast");
		SCR::Write(.sysconfig.network.config.NETCONFIG_NIS_STATIC_SERVERS, "");
	    }
	    else
	    {
		SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_DOMAIN_"+cnt), "broadcast");
		SCR::Write(add(.sysconfig.network.config, "NETCONFIG_NIS_STATIC_SERVERS_"+cnt), "");
	    }
	    cnt = cnt + 1;
	}

	if (! SCR::Write(.sysconfig.network.config, nil))
	{
	    Report::Error (Message::ErrorWritingFile ("/etc/sysconfig/network/config"));
	    return false;
	}
	return true;
    }

    /**
     * If the domain has changed from a nonempty one, it may only be
     * changed at boot time. Use this to warn the user.
     * @return whether changed by SetDomain
     */
    global define boolean DomainChanged () ``{
	return domain_changed;
    }

    /**
     * @return Get the NIS domain.
     */
    global define string GetDomain () ``{
	return domain;
    }

    /**
     * Set the NIS domain.
     * @param new_domain a new domain
     */
    global define void SetDomain (string new_domain) ``{
	domain = new_domain;
	if (domain != old_domain && old_domain != "")
	{
	    domain_changed = true;
	}
    }

    // DHCP cooperation

    /**
     * #35654: if the server is running and sysconfig wants NIS data,
     * it's ok to FitIntoSingle
     */
    global boolean dhcpcd_running = false;

    /**
     * If dhcp_wanted changes, we need to restart the DHCP client
     */
    global boolean dhcp_restart = false;

    // The following four are from sysconfig/ypbind; the comments are
    // taken from there. The dialog help texts have "user friendlier"
    // descriptions.

    /**
     * If this option is set, ypbind will only bind to the loopback
     * interface and remote hosts cannot query it.
     */
    global boolean local_only = false;


    /**
     * You should set this to "yes" if you have a NIS server in your
     * network, which binds only to high ports over 1024. Since this
     * is a security risk, you should consider to replace the NIS
     * server with another implementation.
     */
    global boolean broken_server = false;

    /**
     * Extra options for ypbind. Here you can add options like
     * "-ypset", "-ypsetme", "-p port" or "-no-ping".
     */
    global string options = "";

    /**
     * If no, automounter will not be affected.
     */
    global boolean _autofs_allowed = true;

    /**
     * Start automounter and import the settings from NIS. (Bug 6092)
     */
    global boolean _start_autofs = false;

    /**
     * Output of "rcypbind start", if there was an error.
     * Read only.
     * This is currently used only in nis-server for its more advanced
     * error reporting. (Bug 14706)
     */
    global string YpbindErrors = "";

    /* ---------------------------------------------------------------- */
    // used also for nis-server

    /**
     * Check syntax of a NIS domain name
     * @param domain	a domain name
     * @return		true if correct
     */
    global define boolean check_nisdomainname (string domain) ``{
	// TODO
	// disallow whitespace and special characters...
	return domain != "" && domain != "(none)" && size (domain) <= 64;
    }

    /**
     * @return describe a valid NIS domain name
     */
    global define string valid_nisdomainname () ``{
	// Translators: do not translate (none)!
	return _("A NIS domain name must not be empty,
it must not be \"(none)\",
and it must be at most 64 characters long.
");
    }

    /**
     * If the hostname resolution is done over NIS,
     * names cannot be used to specify servers.
     */
    boolean hosts_by_nis = false;

    /**
     * Using NIS and LDAP simultaneously is not supported (#36981).
     */
    boolean users_by_ldap = false;

    /**
     * Used in the UI when NIS is turned on.
     */
    global define boolean UsersByLdap () ``{
	return users_by_ldap;
    }

    /**
     * Describe a valid address - ip4 or name, names only if
     * nsswitch.conf does not have hosts: nis
     * @return a description
     */
    global define string valid_address_nis () ``{
	y2debug ("hosts_by_nis %1", hosts_by_nis);
	if (hosts_by_nis)
	{
	    // message popup
	    return _("Only an IP address can be used
because host names are resolved using NIS.\n\n") + IP::Valid4();
	}
	else
	{
	    return Address::Valid4();
	}
    }

    /**
     * Check syntax of a network address (ip4 or name), names only if
     * nsswitch.conf does not have hosts: nis
     * @param a an address
     * @return true if correct
     */
    global define boolean check_address_nis (string a) ``{
	y2debug ("hosts_by_nis %1", hosts_by_nis);
	if (hosts_by_nis)
	{
	    return IP::Check4(a);
	}
	else
	{
	    return Address::Check(a);
	}
    }

    /* ---------------------------------------------------------------- */

    /**
     * Has the configuration been changed?
     * Can be used as an argument to Popup::ReallyAbort
     */
    global boolean touched = false;

    /**
     * A convenient shortcut for setting touched.
     * @param really	if true, set Nis::touched
     * @example Nis::Touch (Nis::var != ui_var);
     */
    global define void Touch (boolean really) ``{
	touched = touched || really;
    }

    /* ---------------------------------------------------------------- */

    /**
     * Read only, set by ProbePackages.
     * Use as an argument to DoInstallAndRemove
     */
    global list<string> install_packages = [];

    /**
     * Detect which packages have to be installed
     * and return a descriptive string for a plain text pop-up.
     * @return "" or "Foo will be installed.\nBar will be installed.\n"
     */
    global define string ProbePackages () {
	string message = "";
	install_packages = [];

	if (_autofs_allowed && _start_autofs)
	{
	    if (! Package::Installed ("autofs"))
	    {
		install_packages = add (install_packages, "autofs");
		// Translators: popup message part, ends with a newline
		message = message + _("The automounter package will be installed.\n");
	    }
	    if (!Package::Installed ("nfs-client"))
		install_packages = add (install_packages, "nfs-client");

	}

	return message;
    }

    /* ---------------------------------------------------------------- */

    /**
     * Set module data
     * @return void
     */
    global define void Set (map settings) ``{
	start = settings["start_nis"]:false;

	servers = settings["nis_servers"]:[];
	default_broadcast = settings["nis_broadcast"]:false;
	domain = settings["nis_domain"]:"";
	old_domain = domain;

	// we don't know what the state will be before Write, so restart it
	dhcp_restart = true;

	list<map> other_domains = settings["nis_other_domains"]:[];
	foreach (map other_domain, other_domains, ``{
	    string domain = other_domain["nis_domain"]:"";
	    list<string> servers = other_domain["nis_servers"]:[];
	    boolean b = other_domain["nis_broadcast"]:false;
	    multidomain_servers[domain]		= servers;
	    multidomain_broadcast[domain]	= b;
	});

	local_only = settings["nis_local_only"]:false;
	broken_server = settings["nis_broken_server"]:false;
	options = settings["nis_options"]:"";

	// autofs is not touched in Write if the map does not want it
	_autofs_allowed = haskey (settings, "start_autofs");
	_start_autofs = settings["start_autofs"]:false;
	if (_start_autofs)
	    required_packages = (list <string>)
		union (required_packages, ["autofs", "nfs-client"]);

	policy		= settings["netconfig_policy"]:policy;
	slp_domain	= settings["slp_domain"]:slp_domain;

	touched	= true;
    }

    // TODO update the map keys
    // better still: link to a current interface description
    /**
     * Get all the NIS configuration from a map.
     * When called by nis_auto (preparing autoinstallation data)
     * the map may be empty.
     * @param settings	$["start": "domain": "servers":[...] ]
     * @return	success
     */
    global define boolean Import (map settings) ``{
	if (size (settings) == 0)
	{
	    //Provide defaults for autoinstallation editing:
	    //Leave empty.
	    old_domain = domain;
	    // enable _autofs_allowed
	    // Injecting it into the defaults for the GUI
	    // but leaving the check in Set makes it possible
	    // to delete the element manually from the xml profile
	    // and leave autofs untouched
	    settings["start_autofs"] = false;
	    Set(settings);
	    return true;
	}

	boolean missing = false;
	// "nis_domain" can be omitted if nis_by_dhcp is true
	foreach (string k, ["start_nis"], ``{
	    if (! haskey (settings, k))
	    {
		y2error ("Missing at Import: '%1'.", k);
		missing = true;
	    }
	});
	if (missing)
	{
	    return false;
	}

	Set(settings);
	return true;
    }

    // TODO update the map keys
    // better still: link to a current interface description
    /**
     * Dump the NIS settings to a map, for autoinstallation use.
     * @return $["start":, "servers":[...], "domain":]
     */
    global define map Export () {
	list other_domains = maplist (string d, list s, multidomain_servers, {
	    return $[
		"nis_domain": d,
		"nis_servers": s,
		"nis_broadcast": multidomain_broadcast[d]:false,
		];
	});

	if (global_broadcast)
	{
	    y2error ("Attempt to export Nis::global_broadcast");
	}

	return $[
	    "start_nis": start,

	    "nis_servers": servers,
	    "nis_domain": domain,
	    "nis_broadcast": default_broadcast,

	    "nis_other_domains": other_domains,

	    "nis_local_only": local_only,
	    "nis_broken_server": broken_server,
	    "nis_options": options,

	    "start_autofs": _start_autofs,

	    "slp_domain"	: slp_domain,
	    "netconfig_policy"	: policy,
	    ];
    }

    // copied from Mail.ycp
    // replace with a custom list
    /**
     * Summarizes a list of data
     * @param title passed to Summary::AddHeader
     * @param value a list (of scalars, lists or maps)
     * @return Summary-formatted description
     */
    define string ListItem(string title, any value) ``{
	string summary = "";
	summary = Summary::AddHeader(summary, title);
	//enhancement BEGIN
	if (is (value, map))
	{
	    value = maplist (any k, any v, (map) value, ``(k));
	}
	//enhancement END
	if (is(value,list) && size((list) value)>0) {
	    summary = Summary::OpenList(summary);
	    foreach (any d, (list) value, ``{
		string entry = "";
		if (is(d,map) || is (d,list))
		    entry = sformat("%1 Entries configured", is(d, map) ? size((map) value) : size((list) value));
		else
		    entry = (string) d;

		summary = Summary::AddListItem(summary, entry);
	    });
	    summary = Summary::CloseList(summary);
	} else {
	    summary = Summary::AddLine(summary,Summary::NotConfigured ());
	}
	return summary;
    }

    /**
     * @return Html formatted configuration summary
     */
    global define string Summary () ``{
	// TODO multidomain_servers, multidomain_broadcast
	// OK, a dumb mapping is possible, but wouldn't it be
	// too complicated to write by hand?
	string summary = "";
	string nc = Summary::NotConfigured ();

	// summary: Domain or servers are retrieved by the
	// Dynamic Host Configuration Protocol.
	// Will be placed after NIS Domain/NIS Servers instead of the
	// actual settings.
	string dhcp = _("by DHCP");

	// summary header
	summary = Summary::AddHeader(summary, _("NIS Client enabled"));
	// summary item: an option is turned on
	summary = Summary::AddLine(summary, (start) ? _("Yes") : nc);
	// summary header
	summary = Summary::AddHeader(summary, _("NIS Domain"));
	summary = Summary::AddLine(summary,((domain != "") ? domain : nc));
	// summary header
	summary = Summary::AddHeader(summary, _("NIS Servers"));
	summary = Summary::AddLine(summary, ((servers !=[]) ? mergestring(servers,"<br>") : nc));
	// summary header
	summary = Summary::AddHeader(summary, _("Broadcast"));
	// summary item: an option is turned on
	summary = Summary::AddLine(summary, (default_broadcast) ? _("Yes") : nc);
	// TODO: a full list
	summary = summary + ListItem (_("Other domains"), multidomain_servers);
	// summary header
	summary = Summary::AddHeader(summary, _("Answer to local host only"));
	// summary item: an option is turned on
	summary = Summary::AddLine(summary, (local_only) ? _("Yes") : nc);
	// summary header
	summary = Summary::AddHeader(summary, _("Broken server"));
	// summary item: an option is turned on
	summary = Summary::AddLine(summary, (broken_server) ? _("Yes") : nc);
	// summary header
	summary = Summary::AddHeader(summary, _("ypbind options"));
	summary = Summary::AddLine(summary, (options!="") ? options : nc);
	// summary header
	summary = Summary::AddHeader(summary, _("Automounter enabled"));
	// summary item: an option is turned on
	summary = Summary::AddLine(summary, (_start_autofs) ? _("Yes") : nc);

	return summary;
    }

    /**
     * Makes an item for the short summary. I guess the users module
     * wants to avoid paragraph breaks.
     * @param title
     * @param value
     * @return [b]title[/b]: value[br]
     */
    global define string BrItem (string title, string value) ``{
	return sformat ("<b>%1</b>: %2<br>", title, value);
    }

    /**
     * Create a short textual summary with configuration abstract
     * It is called by "authentication/user sources" dialog in yast2-users
     * @return summary of the current configuration
     */
    global define string ShortSummary() ``{

	string summary = "";
	string nc = Summary::NotConfigured ();
	summary =
	    // summary item
	    BrItem (_("Servers"), ((servers !=[]) ? GetServers() : nc)) +
	    // summary item
	    BrItem (_("Domain"), ((domain != "") ? domain : nc)) +
	    // summary item (yes/no follows)
	    BrItem (_("Client Enabled"), start ? _("Yes"): _("No"));

	return summary;
    }

    /**
     * Reads NIS settings from the SCR
     * @return success
     */
    global define boolean Read () ``{
	start = Service::Enabled("ypbind");

	getNetconfigValues();

	if (servers == nil) servers = [];
	if (default_broadcast == nil) default_broadcast = false;
	if (multidomain_servers == nil) multidomain_servers = $[];
	if (multidomain_broadcast == nil) multidomain_broadcast = $[];
	if (slp_domain == nil) slp_domain = $[];

	map out = (map) SCR::Execute (.target.bash_output, "/bin/ypdomainname");
	domain = deletechars (out["stdout"]:"", "\n");
	old_domain = domain;

	dhcpcd_running =
	    SCR::Execute (.target.bash, "ls /var/run/dhcpcd-*.pid") == 0;

	local_only = SCR::Read (.sysconfig.ypbind.YPBIND_LOCAL_ONLY) == "yes";
	global_broadcast = SCR::Read (.sysconfig.ypbind.YPBIND_BROADCAST) == "yes";
	broken_server = SCR::Read (.sysconfig.ypbind.YPBIND_BROKEN_SERVER) == "yes";
	options = (string) SCR::Read (.sysconfig.ypbind.YPBIND_OPTIONS);

	// install on demand
	_start_autofs = _autofs_allowed && Service::Enabled("autofs");

	hosts_by_nis = contains (Nsswitch::ReadDb ("hosts"), "nis");

	list<string> nss_passwd = Nsswitch::ReadDb ("passwd");
	users_by_ldap =
	    contains (nss_passwd, "ldap") ||
	    (contains (nss_passwd, "compat") &&
	     contains (Nsswitch::ReadDb ("passwd_compat"), "ldap"));

	Autologin::Read ();

	boolean progress_orig = Progress::set (false);
	SuSEFirewall::Read ();
	Progress::set (progress_orig);

	return true;
    }

    /**
     * Make up data for screnshots.
     * To be used instead of @ref Read .
     */
    global define void Fake () ``{
	y2milestone ("Faking data for screenshots");
	start = true;
	servers = ["10.42.0.1"];
	default_broadcast = false;
	multidomain_servers = $[
	    "printer.example.com": [],
	    "test.example.com": ["10.42.1.1", "10.42.1.2"],
	    ];
	multidomain_broadcast = $[
	    "printer.example.com": true,
	    "test.example.com": false,
	    ];
	domain = "example.com";
	old_domain = domain;
	local_only = false;
	global_broadcast = false;
	broken_server = false;
	options = "";
	_autofs_allowed = true;
	_start_autofs = true;
	hosts_by_nis = false;
    }

    /**
     * @param file a pathname
     * @return is there a nis inclusion?
     */
    define boolean HasPlus (string file) ``{
	// does the file have a plus?
	y2milestone("file %1 has pluses", file);
	return (0 == SCR::Execute (.target.bash, "/usr/bin/grep -q '^[+-]' " + file));
    }

    /**
     * If a file does not contain a NIS entry, add it.
     * @param	file	pathname
     * @param	what	a "+" line without a '\n'
     * @return success?
     */
    define boolean WritePlusesTo (string file, string what) ``{
	boolean ok = true;
	if (!HasPlus (file))
	{
	    // backup the file:
	    SCR::Execute (.target.bash,sformat("/bin/cp %1 %1.YaST2save",file));
	    if (SCR::Execute (.target.bash, sformat ("/bin/echo '%1' >> %2", what, file)) != 0)
	    {
		ok = false;
	    }
	}
	// TODO only for passwd?
	// replace the 'nologin' occurence (#40571)
	else if (SCR::Execute (.target.bash, sformat ("/bin/grep -q '^%1/sbin/nologin' %2", what, file)) == 0)
	{
            ok = SCR::Execute (.target.bash, sformat ("/usr/bin/sed -i.YaST2save -e 's@%1/sbin/nologin@%1@' %2", what, file)) == 0;
	}
	if (!ok)
	{
	    Report::Error (Message::ErrorWritingFile (file));
	}
	return ok;
    }

    /**
     * Do we need compat? Is there a plus in any of the user databases?
     * @return true/false
     */
    define boolean HavePlus () ``{
	list<string> files = [
	    "/etc/passwd",
	    "/etc/shadow",
	    "/etc/group",
	    ];
	// find a file having a plus
	return nil != find (string file, files, ``( HasPlus (file) ));
    }

    /**
     * Add "+" lines to system files so that NIS entries get merged in.
     * (Formerly this was done in SuSEconfig.ypclient)
     * @return success?
     */
    define boolean WritePluses () ``{
	list<string> files = ["passwd", "shadow", "group"];
	//don't forget a newline
	map what_to_write = $[
	    "passwd":	"+::::::",
	    "group":	"+:::",
	    "shadow":	"+",
	    ];
	foreach (string f, files, {
	    y2milestone("Writing pluses to %1", f);
	    if (! WritePlusesTo (sformat ("/etc/%1", f), what_to_write[f]:""))
	    {
		return false;
	    }
	});
	return true;
    }

    /**
     * Configures the name service switch for the user databases
     * according to chosen settings
     * @return success?
     */
    global define boolean WriteNssConf () {
	list<string> dbs = ["passwd", "group", "shadow"];
	list<string> nis_dbs	= [ "services" ,"netgroup", "aliases" ];
	// Why bother with both compat and nis?
	// If there's no plus, we don't have to write passwd etc.
	// And it's supposed to be faster.
	// But then programs have to reread nsswitch :( #23203
	// so we stick with compat.
	if (start)
	{
		// we want to switch to "compat"
		foreach (string db, dbs, ``{
		    // what if a db is not mentioned?
		    // We get [] meaning compat, so it's ok to make it explicit
		    list<string> db_l = Nsswitch::ReadDb (db);

		    if (!contains (db_l, "compat"))
		    {
			// remove "files" and "nis", if there;
			db_l = filter (string s, db_l, ``(
					   s != "files" && s != "nis"));
			// put "compat" and the rest;
			db_l = prepend (db_l, "compat");
			Nsswitch::WriteDb (db, db_l);
		    }

		    // *_compat may be set to nisplus, nuke it (#16168)
		    string db_c = db + "_compat";
		    Nsswitch::WriteDb (db_c, []);
		});
		y2milestone("Writing pluses");
		WritePluses ();
		foreach (string db, nis_dbs, {
		    list<string> db_l = Nsswitch::ReadDb (db);
		    if (!contains (db_l, "nis"))
		    {
			if (db == "netgroup")
			    db_l	= ["nis"];
			else
			    db_l        = ["files", "nis"];
			Nsswitch::WriteDb (db, db_l);
		    }
		});
	}
	else // not start
	{

	    y2milestone("not writing pluses");
	    boolean have_plus = HavePlus ();

	    if (!have_plus)
	    {
		foreach (string db, dbs, ``{
		    list<string> db_l = Nsswitch::ReadDb (db);

		    // remove "nis" if there;
		    db_l = filter (string s, db_l, ``(s != "nis"));
		    // if nothing left, put "files";
		    // NOT. just remove it, meaning compat. #35299
		    Nsswitch::WriteDb (db, db_l);
		});
	    }
	    foreach (string db, nis_dbs, {
		list<string> db_l = Nsswitch::ReadDb (db);
		db_l = filter (string s, db_l, ``(s != "nis"));
		if (db_l == [])
		    db_l	= ["files"];
		Nsswitch::WriteDb (db, db_l);
	    });
	}

	if (!SCR::Write (.etc.nsswitch_conf, nil))
	{
	    Report::Error (Message::ErrorWritingFile ("/etc/nsswitch.conf"));
	    return false;
	}
	return true;
    }

    /**
     * Only write new configuration w/o starting any scripts
     * @return true on success
     */
    global define boolean WriteOnly()``{
	if (start)
	{
	    if (Package::Installed ("rpcbind"))
		rpc_mapper	= "rpcbind";
	    else
		rpc_mapper	= "portmap";

	    Service::Enable (rpc_mapper);
	    Service::Enable("ypbind");

	    if (!SCR::Write (.etc.defaultdomain, domain))
	    {
		Report::Error (Message::ErrorWritingFile("/etc/defaultdomain"));
		return false;
	    }

	    // so that dhcpcd cannot restore it
	    SCR::Execute (.target.remove, "/etc/yp.conf.sv");

	    setNetconfigValues();

	    SCR::Execute(.target.bash, "/sbin/netconfig update");

	    SCR::Write (.sysconfig.ypbind.YPBIND_LOCAL_ONLY, local_only? "yes":"no");
	    SCR::Write (.sysconfig.ypbind.YPBIND_BROADCAST, global_broadcast? "yes":"no");
	    SCR::Write (.sysconfig.ypbind.YPBIND_BROKEN_SERVER, broken_server? "yes":"no");
	    SCR::Write (.sysconfig.ypbind.YPBIND_OPTIONS, options);
	    if (! SCR::Write (.sysconfig.ypbind, nil))
	    {
		Report::Error (Message::ErrorWritingFile (
		    "/etc/sysconfig/ypbind"));
		return false;
	    }

	    SCR::Write (.sysconfig.network.config.NETCONFIG_NIS_SETDOMAINNAME,
			policy == "" ? "no" : "yes");

	    if (! SCR::Write (.sysconfig.network.dhcp, nil))
	    {
		Report::Error (Message::ErrorWritingFile (
		    "/etc/sysconfig/network/dhcp"));
		return false;
	    }
	    Autologin::Write (false);
	}
	else
	{
	    Service::Disable("ypbind");
	}

	// TODO do as much as possible if one thing fails
	// especially WRT nis/autofs independence
	WriteNssConf ();

	if (_autofs_allowed)
	{
	    if (! Nsswitch::WriteAutofs (start && _start_autofs,"nis"))
	    {
	        return false;
	    }

	    if (_start_autofs)
	    {
	        Service::Enable("autofs");
	    }
	    else
	    {
	        Service::Disable("autofs");
	    }
	}

	boolean progress_orig = Progress::set (false);
	SuSEFirewall::WriteOnly ();
	Progress::set (progress_orig);

	return true;
    }

    /**
     * Saves NIS configuration.
     * @return true on success
     */
    global define boolean Write () ``{
	if (!WriteOnly ())
	{
	    return false;
	}

	// dialog label
	Progress::New (_("Writing NIS Configuration..."), " ", 2, [
	    // progress stage label
	    _("Stop services"),
	    // progress stage label
	    _("Start services"),
	   ], [
	    // progress step label
	    _("Stopping services..."),
	    // progress step label
	    _("Starting services..."),
	    // final progress step label
	    _("Finished") ],
	    "" );

	// help text
	Wizard::RestoreHelp(_("Writing NIS client settings"));

	Progress::NextStage ();

	if (dhcp_restart)
	{
	    // Restart the dhcp client, if it is running, to parse the changed
	    // options
	    Service::RunInitScript ("network", "restart-all-dhcp-clients");
	}

	Service::Stop("ypbind");

	Progress::NextStage ();

	if (start)
	{
	    if (Service::Status (rpc_mapper) != 0 )
	    {
		if (Service::Start (rpc_mapper) == false)
		{
		    Message::CannotStartService (rpc_mapper);
		    return false;
		}
	    }
	    sleep(1000);	// workaround for bug #10428, ypbind restart

	    map out = (map) SCR::Execute (.target.bash_output, "/etc/init.d/ypbind start", $["TERM": "raw"]);
	    if (out["exit"]:1 == 0)
	    {
		YpbindErrors = "";
	    }
	    else
	    {
		YpbindErrors = out["stdout"]:"internal error";
		// error popup message
		Report::Error (_("Error while running ypclient."));
		return false;
	    }

	    // only test for a server if domain not changed
	    if (! domain_changed)
	    {
		if (SCR::Execute(.target.bash, "/usr/bin/ypwhich >/dev/null") != 0)
		{
		    // error popup message
		    Report::Error (_("NIS server not found."));
		    return false;
		}
	    }
	    if (Autologin::modified)
		SCR::Execute (.target.bash, "/sbin/SuSEconfig --module kdm3");
	}

	// remove nscd cache
	if (Package::Installed ("nscd") && modified)
	{
	    SCR::Execute (.target.bash, "/usr/sbin/nscd -i passwd");
	    SCR::Execute (.target.bash, "/usr/sbin/nscd -i group");
	}

	if (_autofs_allowed && touched)
	{
	    Service::Stop("autofs");

	    if (_start_autofs)
	    {
		Service::Start("autofs");
	    }
	}

	SuSEFirewall::ActivateConfiguration ();

	// final stage
	Progress::NextStage ();

	return true;
    }

    /**
     * Return needed packages and packages to be removed
     * during autoinstallation.
     * @return map of lists.
     *
     **/

    global  define map AutoPackages() ``{
      list install_pkgs = required_packages;
      list remove_pkgs = [];
      return ($["install": install_pkgs, "remove": remove_pkgs]);
    }


}

ACC SHELL 2018