ACC SHELL

Path : /usr/share/YaST2/include/security/
File Upload :
Current File : //usr/share/YaST2/include/security/dialogs.ycp

/**
 * File:	include/security/dialogs.ycp
 * Package:	Security configuration
 * Summary:	Dialogs definitions
 * Authors:	Michal Svec <msvec@suse.cz>
 *
 * $Id: dialogs.ycp 58880 2009-10-01 11:48:57Z jsuchome $
 */

{

textdomain "security";

import "Label";
import "Popup";
import "Security";
import "Wizard";

include "security/helps.ycp";
include "security/routines.ycp";

list tree_dialogs = [ "main", "overview", "password", "boot", "login", "users", "misc", `wizardTree ];

const list<string> configurable_options = [ "PERMISSION_SECURITY", "RUNLEVEL3_MANDATORY_SERVICES",
    "RUNLEVEL5_MANDATORY_SERVICES", "RUNLEVEL3_EXTRA_SERVICES", "RUNLEVEL5_EXTRA_SERVICES" ];

const string UNKNOWN_STATUS = _("Unknown");

string SecurityStatus(string option, boolean plaintext)
{
    string ret = "";

    string value = Security::Settings[option]:"";

    y2milestone("Option: %1, value: %2", option, value);

    // handle the special cases at first
    if (contains(configurable_options, option))
    {
	ret = _("Configure");
    }
    else if (value == "yes")
    {
	ret = _("Enabled");
    }
    else if (value == "no")
    {
	ret = _("Disabled");
    }
    else
    {
	return UNKNOWN_STATUS;
    }

    if (plaintext)
    {
	return ret;
    }

    ret = sformat("<A HREF=\"%1\">%2</A>", option, ret);

    return ret;
}

map<string,string> label_mapping = $[
    "ENABLE_SYSRQ" : _("Use magic SysRq keys"),
    "PERMISSION_SECURITY" : _("Use secure file permissions"),
    "DISPLAYMANAGER_REMOTE_ACCESS" : _("Remote access to the display manager"),
    "CWD_IN_ROOT_PATH" : _("Use current directory in root's path"),
    "CWD_IN_USER_PATH" : _("Use current directory in path of regular users"),
    "SYSTOHC" : _("Write back system time to the hardware clock"),
    "SYSLOG_ON_NO_ERROR" : _("Always generate syslog message for cron scripts"),
    "DHCPD_RUN_CHROOTED" : _("Run the DHCP daemon in a chroot"),
    "DHCPD_RUN_AS" : _("Run the DHCP daemon as dhcp user"),
    "DISPLAYMANAGER_ROOT_LOGIN_REMOTE" : _("Disable remote root login in the display manager"),
    "DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN" : _("Disable remote access to the X server"),
    "SMTPD_LISTEN_REMOTE" : _("Remote access to the email delivery subsystem"),
    "DISABLE_RESTART_ON_UPDATE" : _("Disable service restart on update"),
    "DISABLE_STOP_ON_REMOVAL" : _("Disable service stop on removal"),
    "IP_TCP_SYNCOOKIES" : _("Enable TCP syncookies"),
    "IP_FORWARD" : _("Disable IPv4 forwarding"),
    "IPV6_FORWARD" : _("Disable IPv6 forwarding"),
    "RUNLEVEL3_MANDATORY_SERVICES" : _("Enable basic system services in runlevel 3\n (multiuser with network)"),
    "RUNLEVEL5_MANDATORY_SERVICES" : _("Enable basic system services in runlevel 5\n (multiuser with network and graphical login)"),
    "RUNLEVEL3_EXTRA_SERVICES" : _("Enable extra services in runlevel 3"),
    "RUNLEVEL5_EXTRA_SERVICES" : _("Enable extra services in runlevel 5"),
];


any OverviewText(symbol type)
{
    string ret = "";
    list<term> ret_table = [];

    if (type == `richtext)
    {
	// open a table
	ret = sformat("<TABLE><TR> <TD><BIG><B>%1</B></BIG></TD>
<TD ALIGN=center><BIG><B>&nbsp;&nbsp;&nbsp;&nbsp;%2&nbsp;&nbsp;&nbsp;&nbsp;</B></BIG></TD>
<TD ALIGN=center><BIG><B>&nbsp;&nbsp;&nbsp;&nbsp;%3&nbsp;&nbsp;&nbsp;&nbsp;</B></BIG></TD>
<TD></TD>
</TR> <TR></TR>",
	// table header
	_("Security Setting"), _("Status"), _("Security Status"));
    }

    list<map> security_mapping = [
	$[
	    "id" : "ENABLE_SYSRQ",
	    "is_secure" : (Security::Settings["ENABLE_SYSRQ"]:"" == "no")
	],
	$[
	    "id" : "PERMISSION_SECURITY",
	    "is_secure" : (Security::Settings["PERMISSION_SECURITY"]:"" == "secure"
		|| Security::Settings["PERMISSION_SECURITY"]:"" == "paranoid")
	],
	$[
	    "id" : "DISPLAYMANAGER_REMOTE_ACCESS",
	    "is_secure" : (Security::Settings["DISPLAYMANAGER_REMOTE_ACCESS"]:"" == "no"),
	],
	$[
	    "id" : "CWD_IN_ROOT_PATH",
	    "is_secure" : (Security::Settings["CWD_IN_ROOT_PATH"]:"" == "no")
	],
	$[
	    "id" : "CWD_IN_USER_PATH",
	    "is_secure" : (Security::Settings["CWD_IN_USER_PATH"]:"" == "no")
	],
	$[
	    "id" : "SYSTOHC",
	    "is_secure" : (Security::Settings["SYSTOHC"]:"" == "yes"),
	],
	$[
	    "id" : "SYSLOG_ON_NO_ERROR",
	    "is_secure" : (Security::Settings["SYSLOG_ON_NO_ERROR"]:"" == "yes"),
	],
	$[
	    "id" : "DHCPD_RUN_CHROOTED",
	    "is_secure" : (Security::Settings["DHCPD_RUN_CHROOTED"]:"" == "yes"),
	],
	$[
	    "id" : "DHCPD_RUN_AS",
	    "is_secure" : (Security::Settings["DHCPD_RUN_AS"]:"" == "dhcp"),
	],
	$[
	    "id" : "DISPLAYMANAGER_ROOT_LOGIN_REMOTE",
	    "is_secure" : (Security::Settings["DISPLAYMANAGER_ROOT_LOGIN_REMOTE"]:"" == "no"),
	],
	$[
	    "id" : "DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN",
	    "is_secure" : (Security::Settings["DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN"]:"" == "no"),
	],
	$[
	    "id" : "SMTPD_LISTEN_REMOTE",
	    "is_secure" : (Security::Settings["SMTPD_LISTEN_REMOTE"]:"" == "no"),
	],
	$[
	    "id" : "DISABLE_RESTART_ON_UPDATE",
	    "is_secure" : (Security::Settings["DISABLE_RESTART_ON_UPDATE"]:"" == "no"),
	],
	$[
	    "id" : "DISABLE_STOP_ON_REMOVAL",
	    "is_secure" : (Security::Settings["DISABLE_STOP_ON_REMOVAL"]:"" == "no"),
	],
	$[
	    "id" : "IP_TCP_SYNCOOKIES",
	    "is_secure" : (Security::Settings["IP_TCP_SYNCOOKIES"]:"" == "yes"),
	],
	$[
	    "id" : "IP_FORWARD",
	    "is_secure" : (Security::Settings["IP_FORWARD"]:"" == "no"),
	],
	$[
	    "id" : "IPV6_FORWARD",
	    "is_secure" : (Security::Settings["IPV6_FORWARD"]:"" == "no"),
	],
	$[
	    "id" : "RUNLEVEL3_MANDATORY_SERVICES",
	    "is_secure" : (Security::Settings["RUNLEVEL3_MANDATORY_SERVICES"]:"" == "secure"),
	],
	$[
	    "id" : "RUNLEVEL5_MANDATORY_SERVICES",
	    "is_secure" : (Security::Settings["RUNLEVEL5_MANDATORY_SERVICES"]:"" == "secure"),
	],
	$[
	    "id" : "RUNLEVEL3_EXTRA_SERVICES",
	    "is_secure" : (Security::Settings["RUNLEVEL3_EXTRA_SERVICES"]:"" == "secure"),
	],
	$[
	    "id" : "RUNLEVEL5_EXTRA_SERVICES",
	    "is_secure" : (Security::Settings["RUNLEVEL5_EXTRA_SERVICES"]:"" == "secure"),
	],
    ];

    foreach(map setting, security_mapping,
	{
	    string current_value = Security::Settings[setting["name"]:""]:"";

	    string id = setting["id"]:"";

	    if (type == `table)
	    {
		ret_table = add(ret_table, `item(`id(id), label_mapping[id]:"", SecurityStatus(id, true),
		    setting["is_secure"]:false ? "✔" : "✘"));
	    }
	    else if (type == `richtext)
	    {
		// add one line for each security setting
		ret = ret + sformat("<TR><TD>%1&nbsp;&nbsp;&nbsp;&nbsp;</TD><TD ALIGN=center>%2</TD><TD ALIGN=center>&nbsp;&nbsp;&nbsp;%3</TD><TD>%4</TD></TR>",
		    label_mapping[id]:"",
		    SecurityStatus(id, false),
		    setting["is_secure"]:false ?
			"<SUP><FONT COLOR=green SIZE=20>✔</FONT></SUP>" : "<FONT COLOR=red SIZE=20><SUP>✘</SUP></FONT>",
		    haskey(help_mapping, id) ? sformat("<A HREF=\"help_%1\">%2</A>&nbsp;&nbsp;<BR>", id, _("Help")) : ""
		);
	    }
	}
    );

    if (type == `table)
    {
	y2milestone("Overview table: %1", ret_table);
	return ret_table;
    }
    else if (type == `richtext)
    {
	// close the table
	ret = ret + "</TABLE>";

	y2milestone("Overview text: %1", ret);
	return ret;
    }

    y2error("Unknown type: %1", type);

    return nil;;
}

// mapping for "Enable" and "Disable" links
// current value -> new value
map link_value_mapping = $[
    "yes" : "no",
    "no"  : "yes"
];

// mapping for "Configure" links
// config name -> dialog name
map link_config_mapping = $[
    "PERMISSION_SECURITY" : "misc"
];

// mapping for "Configure" links
// config name -> yast client
map link_client_mapping = $[
    "RUNLEVEL3_MANDATORY_SERVICES" : "runlevel",
    "RUNLEVEL5_MANDATORY_SERVICES" : "runlevel",
    "RUNLEVEL3_EXTRA_SERVICES" : "runlevel",
    "RUNLEVEL5_EXTRA_SERVICES" : "runlevel",
];

map link_update_mapping = $[
    "RUNLEVEL3_MANDATORY_SERVICES" : ``(Security::ReadServiceSettings()),
    "RUNLEVEL5_MANDATORY_SERVICES" : ``(Security::ReadServiceSettings()),
    "RUNLEVEL3_EXTRA_SERVICES" : ``(Security::ReadServiceSettings()),
    "RUNLEVEL5_EXTRA_SERVICES" : ``(Security::ReadServiceSettings()),
];

void DisplayHelpPopup(string help_id)
{
    string help = help_mapping[help_id]:"";

    // add the warning if the option is unknown
    if (SecurityStatus(help_id, true) == UNKNOWN_STATUS)
    {
	help = help + HELPS["unknown_status"]:"";
    }

    // add extra help to service related options
    if (help_id == "RUNLEVEL3_MANDATORY_SERVICES" || help_id == "RUNLEVEL5_MANDATORY_SERVICES")
    {
	integer runlevel = (help_id == "RUNLEVEL3_MANDATORY_SERVICES") ? 3 : 5;

	list<list<string> > missing = Security::MissingMandatoryServices(runlevel);

	if (missing != nil && missing != [])
	{
	    string srvs = "";

	    foreach(list<string> l, missing,
		{
		    // this is a separator between service names
		    // e.g.: "postfix" + " or " + "sendmail"
		    string group = mergestring(l , _(" or "));

		    srvs = srvs + group + "<BR>";
		}
	    );

	    // richtext message: %1 = runlevel ("3" or "5"), %2 = list of services
	    help = help + sformat(_("<P>These basic system services are not enabled in runlevel %1:<BR><B>%2</B></P>"), runlevel, srvs);
	}
	else
	{
	    help = help + _("<P>All basic services are enabled.</P>");
	}
    }
    else if (help_id == "RUNLEVEL3_EXTRA_SERVICES" || help_id == "RUNLEVEL5_EXTRA_SERVICES")
    {
	integer runlevel = (help_id == "RUNLEVEL3_EXTRA_SERVICES") ? 3 : 5;
	list<string> extra = Security::ExtraServices(runlevel);

	if (extra != nil && extra != [])
	{
	    string srvs = mergestring(extra, "<BR>");
	    help = help + sformat(_("<P>These extra services are enabled in runlevel %1:<BR><B>%2</B></P>"), runlevel, srvs);
	    help = help + _("<P>Check the list of services and disable all unused services.</P>");
	}
	else
	{
	    help = help + _("<P>Only basic system services are enabled.</P>");
	}
    }

    if (help != nil && help != "")
    {
	Popup::LongText(label_mapping[help_id]:_("Description"), `RichText(help), 70, 15);
    }
}

define any OverviewDialog()
{
    /* Overview dialog caption */
    string caption = _("Security Overview");
    string help = HELPS["overview"]:"";
    boolean no_richtext = !(UI::GetDisplayInfo()["RichTextSupportsTable"]:true);

    // table header
    term tabheader = `header(_("Security Setting"), _("Status"), `Center(_("Security Status")));
    term contents = no_richtext ?
	`Table(`id(`table), `opt(`immediate), tabheader, OverviewText(`table)) :
	`RichText(`id(`rtext), OverviewText(`richtext));

    if (no_richtext)
    {
	// add a button box below the table
	contents = `VBox(
	    contents,
	    `VSpacing(1),
	    `HBox(
		// push button label
		`PushButton(`id(`change), _("Change &Status")),
		`HSpacing(2),
		// push button label
		`PushButton(`id(`descr), _("&Description"))
	    ),
	    `VSpacing(1)
	);
    }

    Wizard::SetContentsButtons(caption, contents, help,
	    Label::BackButton(), Label::OKButton());

    Wizard::HideBackButton();
    Wizard::SetAbortButton( `abort, Label::CancelButton() );

    // select the dialog in the tree navigation
    Wizard::SelectTreeItem("overview");

    any ret = nil;
    while(true) {
	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
	else if(ret == `back || ret == `next || contains(tree_dialogs, ret)) {
	    // the current item has been selected, do not change to the same dialog
	    if (ret == "overview")
	    {
		// preselect the item if it has been unselected
		if (Wizard::QueryTreeItem() != "overview")
		{
		    Wizard::SelectTreeItem("overview");
		}

		continue;
	    }

	    break;
	}
	// user clicked a link in the richtext
	else if ((is(ret, string) && haskey(Security::Settings, ret)) || ret == `change)
	{
	    if (ret == `change)
	    {
		// query the table in textmode
		ret = (string)UI::QueryWidget(`id(`table), `CurrentItem);
	    }

	    y2milestone("Clicked %1 link", ret);

	    string current_value = Security::Settings[(string)ret]:"";

	    string new_value = link_value_mapping[current_value]:current_value;

	    // set the new value and refresh the overview
	    if (haskey(link_value_mapping, current_value) && new_value != current_value)
	    {
		y2milestone("New value for %1: %2", ret, new_value);
		Security::Settings[(string)ret] = new_value;
		// the config has been changed
		Security::SetModified();

		if (no_richtext)
		{
		    UI::ChangeWidget(`id(`table), `Items, OverviewText(`table));
		    UI::ChangeWidget(`id(`table), `CurrentItem, ret);
		    UI::SetFocus(`id(`table));
		}
		else
		{
		    UI::ChangeWidget(`id(`rtext), `Value, OverviewText(`richtext));
		}
	    }
	    else if (haskey(link_config_mapping, ret))
	    {
		string new_dialog = link_config_mapping[ret]:"";

		y2milestone("Switching to dialog %1", new_dialog);
		return new_dialog;
	    }
	    else if (haskey(link_client_mapping, ret))
	    {
		string client = link_client_mapping[ret]:"";

		if (client != "")
		{
		    y2milestone("Calling Yast client %1", client);
		    any client_ret = WFM::CallFunction(client, []);
		    y2milestone("Client returned %1", client_ret);

		    if (client_ret == `next || client_ret == `ok || client_ret == `finish)
		    {
			// update the current value
			if (haskey(link_update_mapping, ret))
			{
			    eval(link_update_mapping[ret]:nil);
			}

			// update the overview
			if (no_richtext)
			{
			    UI::ChangeWidget(`id(`table), `Items, OverviewText(`table));
			    UI::ChangeWidget(`id(`table), `CurrentItem, ret);
			    UI::SetFocus(`id(`table));
			}
			else
			{
			    UI::ChangeWidget(`id(`rtext), `Value, OverviewText(`richtext));
			}
		    }
		}
	    }
	    else
	    {
		y2error("Unknown action for link %1", ret);
	    }
	}
	else if ((is(ret, string) && regexpmatch((string)ret, "^help_")) || ret == `descr)
	{
	    string help_id = no_richtext ?
		(string)UI::QueryWidget(`id(`table), `CurrentItem)
		: regexpsub((string)ret, "^help_(.*)", "\\1");
	    y2milestone("Clicked help link: %1", help_id);

	    DisplayHelpPopup(help_id);

	    // switch the focus back to the table in text/GTK UI
	    if (no_richtext)
	    {
		UI::SetFocus(`id(`table));
	    }
	}
	else if (ret == `table)
	{
	    // disable "Change Status" button if the action is unknown
	    string current_item = (string)UI::QueryWidget(`id(`table), `CurrentItem);
	    string status = SecurityStatus(current_item, true /* plaintext */);

	    UI::ChangeWidget(`id(`change), `Enabled, status != UNKNOWN_STATUS);
	}
	else {
	    y2error("Unexpected return code: %1", ret);
	    continue;
	}
    }

    return ret;
}

/**
 * Boot dialog
 * @return dialog result
 */
define any BootDialog() ``{

    /* Boot dialog caption */
    string caption = _("Boot Settings");
    string help = HELPS["boot"]:"";

    /* Boot dialog contents */
    term contents = `HVCenter(`HVSquash(`HBox(
	`HSpacing(5),
	`VBox(
	    `VSpacing(2),
	    /* Frame label */
	    `Frame(_("Boot Permissions"),`HBox(
		`HSpacing(3),
		`VBox(
		    `VSpacing(1),
		    settings2widget("CONSOLE_SHUTDOWN"),
		    `VSpacing(1.0),
		    settings2widget("DISPLAYMANAGER_SHUTDOWN"),
		    `VSpacing(1)
		),
		`HSpacing(3)
	    )),
	    `VSpacing(2)
	),
	`HSpacing(5)
    )));

    Wizard::SetContentsButtons(caption, contents, help,
	    Label::BackButton(), Label::OKButton());

    Wizard::HideBackButton();
    Wizard::SetAbortButton( `abort, Label::CancelButton() );

    // select the dialog in the tree navigation
    Wizard::SelectTreeItem("boot");

    any ret = nil;
    while(true) {
	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
	else if(ret == `back || ret == `next || contains(tree_dialogs, ret)) {
	    // the current item has been selected, do not change to the same dialog
	    if (ret == "boot")
	    {
		// preselect the item if it has been unselected
		if (Wizard::QueryTreeItem() != "boot")
		{
		    Wizard::SelectTreeItem("boot");
		}

		continue;
	    }

	    break;
	}
	else {
	    y2error("Unexpected return code: %1", ret);
	    continue;
	}
    }

    if(ret == `next || contains(tree_dialogs, ret)) {
	widget2settings("CONSOLE_SHUTDOWN");
	widget2settings("DISPLAYMANAGER_SHUTDOWN");
    }

    return ret;
}

/**
 * Misc dialog
 * @return dialog result
 */
define any MiscDialog() ``{

    /* Misc dialog caption */
    string caption = _("Miscellaneous Settings");
    string help = HELPS["misc"]:"";

    /* Misc dialog contents */
    term contents = `VBox(
	VSeparator(),
	settings2widget("PERMISSION_SECURITY"),
	`VSpacing(1.0),
	settings2widget("RUN_UPDATEDB_AS"),
	`VSpacing(1.0),
	settings2widget("CWD_IN_ROOT_PATH"),
	VSeparator(),
	settings2widget("CWD_IN_USER_PATH"),
	`VSpacing(1.0),
	settings2widget("ENABLE_SYSRQ"),
	`VSpacing(1.8)
    );
    contents = `HVCenter(`HVSquash(`HBox(`HSpacing(5),`VBox(`VSpacing(2),`ReplacePoint(`id(`rp_main),contents),`VSpacing(2)),`HSpacing(5))));

    Wizard::SetContentsButtons(caption, contents, help,
	    Label::BackButton(), Label::OKButton());

    Wizard::HideBackButton();
    Wizard::SetAbortButton( `abort, Label::CancelButton() );

    // select the dialog in the tree navigation
    Wizard::SelectTreeItem("misc");

    any ret = nil;
    while(true) {
	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
	else if(ret == `back) {
	    break;
	}
	else if(ret == `next || contains(tree_dialogs, ret)) {
	    // the current item has been selected, do not change to the same dialog
	    if (ret == "misc")
	    {
		// preselect the item if it has been unselected
		if (Wizard::QueryTreeItem() != "misc")
		{
		    Wizard::SelectTreeItem("misc");
		}

		continue;
	    }

	    /* check_* */
	    break;
	}
	else {
	    y2error("Unexpected return code: %1", ret);
	    continue;
	}
    }

    if(ret == `next || contains(tree_dialogs, ret)) {
	widget2settings("PERMISSION_SECURITY");
	widget2settings("CWD_IN_ROOT_PATH");
	widget2settings("CWD_IN_USER_PATH");
	widget2settings("RUN_UPDATEDB_AS");
	widget2settings("ENABLE_SYSRQ");
    }

    return ret;
}

/**
 * Password dialog
 * @return dialog result
 */
define any PassDialog() ``{

    /* Password dialog caption */
    string caption = _("Password Settings");
    string help = HELPS["password"]:"";

    /* Password dialog contents */
    term contents = `VBox(
	/* Frame label */
	XFrame(0.3,0.15,_("Checks"),`VBox(
	    settings2widget("PASSWD_USE_CRACKLIB"),
	    VSeparator(),
	    settings2widget("PASS_MIN_LEN"),
	    VSeparator(),
	    settings2widget("PASSWD_REMEMBER_HISTORY"),
	    VSeparator ()
	)),
	`VSpacing(0.4),
	settings2widget("PASSWD_ENCRYPTION"),
	`VSpacing(0.4),
	/* Frame label */
	`Frame(_("Password Age"),`HBox(
	    `HSpacing(0.4),
	    settings2widget("PASS_MIN_DAYS"),
	    `HSpacing(0.4),
	    settings2widget("PASS_MAX_DAYS"),
	    `HSpacing(0.4)
	)),
	`VSpacing(0.15),
	settings2widget("PASS_WARN_AGE"),
	`VSpacing(0.0)
    );
    contents = `HVCenter(`HVSquash(`HBox(`HSpacing(5),`VBox(`VSpacing(2),`ReplacePoint(`id(`rp_main),contents),`VSpacing(2)),`HSpacing(5))));

    Wizard::SetContentsButtons(caption, contents, help,
	    Label::BackButton(), Label::OKButton());

    Wizard::HideBackButton();
    Wizard::SetAbortButton( `abort, Label::CancelButton() );

    // select the dialog in the tree navigation
    Wizard::SelectTreeItem("password");

    UI::ChangeWidget (`id ("PASS_MIN_LEN"), `Enabled,
	Security::Settings["PASSWD_USE_CRACKLIB"]:"" == "yes");

    any ret = nil;
    while(true) {
	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
	else if(ret == `back) {
	    break;
	}
	else if (ret == "PASSWD_USE_CRACKLIB")
	{
	    // minlen is an option for pam_cracklib
	    UI::ChangeWidget (`id ("PASS_MIN_LEN"), `Enabled,
		UI::QueryWidget (`id (ret), `Value) == true);
	}
	else if(ret == `next || contains(tree_dialogs, ret)) {
	    // the current item has been selected, do not change to the same dialog
	    if (ret == "password")
	    {
		// preselect the item if it has been unselected
		if (Wizard::QueryTreeItem() != "password")
		{
		    Wizard::SelectTreeItem("password");
		}

		continue;
	    }

	    /* check_* */
	    if(checkMinMax("PASS_MIN_DAYS","PASS_MAX_DAYS") != true) {
		/* Popup text */
		Popup::Error(_("The minimum number of days cannot be larger
than the maximum."));
		continue;
	    }
	    string enc	=
		(string) UI::QueryWidget(`id("PASSWD_ENCRYPTION"), `Value);
	    integer min = (integer) UI::QueryWidget(`id("PASS_MIN_LEN"),`Value);
	    if (min > Security::PasswordMaxLengths[enc]:8)
	    {
		// Popup text, %1 is number
		Popup::Error (sformat (_("The minimum password length cannot be larger than the maximum.
The maximum password length for the selected encryption method is %1."),
		Security::PasswordMaxLengths[enc]:8));
		continue;
	    }
	    break;
	}
	else if (ret != "PASSWD_ENCRYPTION") {
	    y2error("Unexpected return code: %1", ret);
	    continue;
	}
    }

    if(ret == `next || contains(tree_dialogs, ret)) {
	widget2settings("PASS_MIN_DAYS");
	widget2settings("PASS_MAX_DAYS");
	widget2settings("PASS_MIN_LEN");
	widget2settings("PASSWD_USE_CRACKLIB");
	widget2settings("PASS_WARN_AGE");
	widget2settings("PASSWD_ENCRYPTION");
	widget2settings("PASSWD_REMEMBER_HISTORY");
    }

    return ret;
}

/**
 * Login dialog
 * @return dialog result
 */
define any LoginDialog() ``{

    /* Login dialog caption */
    string caption = _("Login Settings");
    string help = HELPS["login"]:"";

    /* Login dialog contents */
    term contents = `VBox(
	/* Frame label */
	XFrame(3.0,1.0,_("Login"),`VBox(
	    //VSeparator(),
	    settings2widget("FAIL_DELAY"),
	    //VSeparator(),
	    `VSpacing(0.5),
	    settings2widget("LASTLOG_ENAB"),
	    VSeparator(),
	    settings2widget("DISPLAYMANAGER_REMOTE_ACCESS")
	    //VSeparator()
	))
	//,`VSpacing(1.7)
    );
    contents = `HVCenter(`HVSquash(`HBox(`HSpacing(5),`VBox(`VSpacing(2),`ReplacePoint(`id(`rp_main),contents),`VSpacing(2)),`HSpacing(5))));

    Wizard::SetContentsButtons(caption, contents, help,
	    Label::BackButton(), Label::OKButton());

    Wizard::HideBackButton();
    Wizard::SetAbortButton( `abort, Label::CancelButton() );

    // select the dialog in the tree navigation
    Wizard::SelectTreeItem("login");

    any ret = nil;
    while(true) {
	ret = UI::UserInput();

	/* abort? */
	if(ret == `abort || ret == `cancel) {
	    if(ReallyAbort()) break;
	    else continue;
	}
	else if(ret == `back) {
	    break;
	}
	else if(ret == `next || contains(tree_dialogs, ret)) {
	    // the current item has been selected, do not change to the same dialog
	    if (ret == "login")
	    {
		// preselect the item if it has been unselected
		if (Wizard::QueryTreeItem() != "login")
		{
		    Wizard::SelectTreeItem("login");
		}

		continue;
	    }

	    /* check_* */
	    break;
	}
	else {
	    y2error("Unexpected return code: %1", ret);
	    continue;
	}
   }

    if(ret == `next || contains(tree_dialogs, ret)) {
	widget2settings("LASTLOG_ENAB");
	widget2settings("FAIL_DELAY");
	widget2settings("DISPLAYMANAGER_REMOTE_ACCESS");
    }

    return ret;
}

/* EOF */
}

ACC SHELL 2018