ACC SHELL

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

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

{

module "Security";
textdomain "security";

import "FileUtils";
import "Pam";
import "PamSettings";
import "Progress";
import "Service";

include "security/levels.ycp";


// services to check - these must be running
// meaning [ [ || ] && && ]
global const list<list<string> > mandatory_services = [["ntp"], ["syslog"], ["auditd"], ["random"], ["kbd"], ["cron"], ["postfix", "sendmail"]];
// sevices to check - these can be ignored (if they are running it's OK)
global const list<string> optional_services = [
    "acpid", "boot.clock", "dbus", "ealysyslog", "fbset", "framebufferset", "isdn", "microcode.ctl", "random",
    "consolekit", "haldaemon", "network", "syslog", "auditd", "splash_early", "alsasound",
    "irq_balancer", "kbd", "powersaved", "splash", "sshd", "earlyxdm", "hotkey-setup", "atd", "nscd",
    "smpppd", "xend", "autofs", "libvirtd", "sendmail", "postfix", "xendomains", "cron", "ddclient",
    "smartd", "stopblktrace", "ntp", "SuSEfirewall", "earlysyslog"
];
// All other services should be turned off


// return list of missing mandatory services in a runlevel
global list<list<string> > MissingMandatoryServices(integer runlevel)
{
    y2milestone("Checking mandatory services in runlevel %1", runlevel);

    list<list<string> > ret = [];
    list<string> enabled_services = Service::EnabledServices(runlevel);

    y2milestone("enabled_services: %1", enabled_services);

    if (enabled_services == nil)
    {
	return nil;
    }

    foreach(list<string> services, mandatory_services,
	{
	    boolean enabled = false;

	    foreach(string service, services,
		{
		    enabled = enabled || contains(enabled_services, service);
		}
	    );

	    y2milestone("Mandatory services %1 are enabled: %2", services, enabled);

	    if (!enabled)
	    {
		ret = add(ret, services);
	    }
	}
    );

    y2milestone("Missing mandatory services in runlevel %1: %2", runlevel, ret);

    return ret;
}

global list<string> ExtraServices(integer runlevel)
{
    y2milestone("Searching for extra services in runlevel %1", runlevel);

    list<string> extra_services = [];
    list<string> enabled_services = Service::EnabledServices(runlevel);

    if (enabled_services == nil)
    {
	return nil;
    }

    foreach(string service, enabled_services,
	{
	    // the extra service is not mandatory and it's not optional
	    boolean extra = !contains(flatten(mandatory_services), service) && !contains(optional_services, service);

	    if (extra)
	    {
		y2milestone("Found extra service: %1", service);
		extra_services = add(extra_services, service);
	    }
	}
    );

    y2milestone("All extra services: %1", extra_services);

    return extra_services;
}

/**
 * All security settings
 */
global map<string,string> Settings = $[
    "CONSOLE_SHUTDOWN"			: "reboot",
    "CRACKLIB_DICT_PATH"		: "/usr/lib/cracklib_dict",
    "CWD_IN_ROOT_PATH"			: "yes",
    "CWD_IN_USER_PATH"			: "yes",
    "DISPLAYMANAGER_REMOTE_ACCESS"	: "no",
    "ENABLE_SYSRQ"			: "no",
    "IP_TCP_SYNCOOKIES"			: "yes",
    "IP_FORWARD"			: "no",
    "IPV6_FORWARD"			: "no",
    "FAIL_DELAY"			: "3",
    "GID_MAX"				: "60000",
    "GID_MIN"				: "1000",
    "DISPLAYMANAGER_SHUTDOWN"		: "all",
    "LASTLOG_ENAB"			: "yes",
    "PASSWD_ENCRYPTION"			: "blowfish",
    "GROUP_ENCRYPTION"			: "md5",
    "PASSWD_USE_CRACKLIB"		: "yes",
    "PASS_MAX_DAYS"			: "99999",
    "PASS_MIN_DAYS"			: "0",
    "PASS_MIN_LEN"			: "5",
    "PASS_WARN_AGE"			: "7",
    "PERMISSION_SECURITY"		: "secure",
    "DISABLE_RESTART_ON_UPDATE"		: "no",
    "DISABLE_STOP_ON_REMOVAL"		: "no",
    "RUN_UPDATEDB_AS"			: "nobody",
    "UID_MAX"				: "60000",
    "UID_MIN"				: "500",
    "SYSTEM_UID_MAX"			: "499",
    "SYSTEM_UID_MIN"			: "100",
    "SYSTEM_GID_MAX"			: "499",
    "SYSTEM_GID_MIN"			: "100",
    "USERADD_CMD"			: "/usr/sbin/useradd.local",
    "USERDEL_PRECMD"			: "/usr/sbin/userdel-pre.local",
    "USERDEL_POSTCMD"			: "/usr/sbin/userdel-post.local",
    "PASSWD_REMEMBER_HISTORY"		: "0",
    "SYSTOHC"				: "yes",
    "SYSLOG_ON_NO_ERROR"		: "yes",
    "DISPLAYMANAGER_ROOT_LOGIN_REMOTE"	: "no",
    "DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN" : "no",
    "SMTPD_LISTEN_REMOTE"		: "no",
    "RUNLEVEL3_MANDATORY_SERVICES"	: "yes",
    "RUNLEVEL5_MANDATORY_SERVICES"	: "yes",
    "RUNLEVEL3_EXTRA_SERVICES"		: "no",
    "RUNLEVEL5_EXTRA_SERVICES"		: "no",
];

// the original settings
map<string,string> Settings_bak = Settings;

// keys that should not be tested against predefined levels:
// - GROUP_ENCRYPTION does not have UI for changing
// - RUNLEVEL*_SERVICES have different syntax, are not saved in current form
global list<string> do_not_test = [ "GROUP_ENCRYPTION",
	"RUNLEVEL3_MANDATORY_SERVICES", "RUNLEVEL5_MANDATORY_SERVICES",
	"RUNLEVEL3_EXTRA_SERVICES", "RUNLEVEL5_EXTRA_SERVICES"
];

/**
 * Security settings locations
 */
map<string,list<string> > Locations = $[
    ".etc.login_defs" : [
	"FAIL_DELAY",
	"GID_MAX",
	"GID_MIN",
	"LASTLOG_ENAB",
	"PASS_MAX_DAYS",
	"PASS_MIN_DAYS",
	"PASS_WARN_AGE",
	"UID_MAX",
	"UID_MIN",
	"SYSTEM_UID_MAX",
	"SYSTEM_UID_MIN",
	"SYSTEM_GID_MAX",
	"SYSTEM_GID_MIN",
	"USERADD_CMD",
	"USERDEL_PRECMD",
	"USERDEL_POSTCMD",
    ],
    ".sysconfig.suseconfig" : [
	"CWD_IN_ROOT_PATH",
	"CWD_IN_USER_PATH",
    ],
    ".sysconfig.displaymanager" : [
	"DISPLAYMANAGER_REMOTE_ACCESS",
	"DISPLAYMANAGER_ROOT_LOGIN_REMOTE",
	"DISPLAYMANAGER_XSERVER_TCP_PORT_6000_OPEN",
	"DISPLAYMANAGER_SHUTDOWN",
    ],
    ".sysconfig.security" : [
	"PERMISSION_SECURITY",
    ],
    ".sysconfig.services" : [
	"DISABLE_RESTART_ON_UPDATE",
	"DISABLE_STOP_ON_REMOVAL",
    ],
    ".sysconfig.locate" : [
	"RUN_UPDATEDB_AS",
    ],
    ".sysconfig.sysctl" : [
	"ENABLE_SYSRQ",
	"IP_TCP_SYNCOOKIES",
	"IP_FORWARD",
	"IPV6_FORWARD",
    ],
    ".sysconfig.clock" : [
	"SYSTOHC",
    ],
    ".sysconfig.cron" : [
	"SYSLOG_ON_NO_ERROR",
    ],
    ".sysconfig.mail" : [
	"SMTPD_LISTEN_REMOTE",
    ],
];

/*
 * Remaining settings:
 * - CONSOLE_SHUTDOWN (/etc/inittab)
 * - PASSWD_ENCRYPTION (/etc/pam?)
 * - GROUP_ENCRYPTION FIXME cannot be set
 * - RUNLEVEL3_MANDATORY_SERVICES
 * - RUNLEVEL5_MANDATORY_SERVICES
 * - RUNLEVEL3_EXTRA_SERVICES
 * - RUNLEVEL5_EXTRA_SERVICES
 */

/**
 * Number of sigificant characters in the password
 */
global map PasswordMaxLengths = $[
    "des" : 8,
    "md5" : 127,
    "blowfish" : 72,
];

/**
 * List of supported password encryption ciphers
 */
list<string> Ciphers = [
    // "des",
    "md5",
    "blowfish",
];

/**
 * Abort function
 * return boolean return true if abort
 */
global block<boolean> AbortFunction = nil;

/**
 * Check for pending Abort press
 * @return true if pending abort
 */
global define boolean PollAbort() {
    return UI::PollInput() == `abort;
}

/**
 * Abort function
 * @return blah blah lahjk
 */
global define boolean Abort() {
    if(AbortFunction != nil)
	return eval(AbortFunction) == true;
    return false;
}

/**
 * Data was modified?
 */
global boolean modified = false;

global boolean proposal_valid = false;
global boolean write_only = false;


/**
 * Function which returns if the settings were modified
 * @return boolean  settings were modified
 */
global define boolean GetModified () {
    return modified;
}
/**
 * Function sets internal variable, which indicates, that any
 * settings were modified, to "true"
 */


global define void SetModified () {
    modified = true;
}


/**
 * Data was modified?
 * @return true if modified
 */
global define boolean Modified() {
    y2debug("modified=%1", modified);
    return modified;
}

global void ReadServiceSettings()
{
    Settings["RUNLEVEL3_MANDATORY_SERVICES"] = MissingMandatoryServices(3) == [] ? "secure" : "insecure";
    Settings["RUNLEVEL5_MANDATORY_SERVICES"] = MissingMandatoryServices(5) == [] ? "secure" : "insecure";
    Settings["RUNLEVEL3_EXTRA_SERVICES"] = ExtraServices(3) == [] ? "secure" : "insecure";
    Settings["RUNLEVEL5_EXTRA_SERVICES"] = ExtraServices(5) == [] ? "secure" : "insecure";
}

/**
 * Read all security settings
 * @return true on success
 */
global define boolean Read() {

    Settings = $[];

    /* Read security settings */

    mapmap(string file, list<string> vars, Locations, {
	maplist(string var, vars, {
	    string val = "";

	    string filename = nil;
	    if(issubstring(file, "sysconfig")) {
		filename = "/etc" + mergestring(splitstring(file, "."), "/");
		y2debug("filename=%1", filename);
	    }

	    if(filename == nil || SCR::Read(.target.size, filename) > 0) {
		val = (string) SCR::Read(topath(file + "." + var));
		y2debug("Reading: %1 (%2)", topath(file + "." + var), val);
	    }
	    if(val == nil) val = "";
	    Settings[var] = val;
	});
	return $[0: 0];
    });
    y2debug("Settings=%1", Settings);

    list inittab = SCR::Dir(.etc.inittab);
    if(contains(inittab, "ca")) {
	string ca = (string) SCR::Read(.etc.inittab.ca);
	if(issubstring(ca, "/bin/true") || issubstring(ca, "/bin/false"))
	    Settings["CONSOLE_SHUTDOWN"] = "ignore";
	else if(issubstring(ca, "reboot") || issubstring(ca, " -r"))
	    Settings["CONSOLE_SHUTDOWN"] = "reboot";
	else if(issubstring(ca, "halt") || issubstring(ca, " -h"))
	    Settings["CONSOLE_SHUTDOWN"] = "halt";
	else {
	    y2error("Unknown ca status: %1", ca);
	    Settings["CONSOLE_SHUTDOWN"] = "ignore";
	}
    }
    else
	Settings["CONSOLE_SHUTDOWN"] = "ignore";

    y2debug("Settings=%1", Settings);


    /* Read runlevel setting */
    ReadServiceSettings();

    /* Read pam settings */

    // read the password hash settings
    string method = PamSettings::GetDefaultValue ("CRYPT_FILES");
    if (method == nil || method == "" ||
	!contains (["des","md5","blowfish"],method))
    {
	method = PamSettings::GetHashMethod ();
    }
    if (method == "" || !contains (["des","md5","blowfish"],method))
	method = "des";
    Settings["PASSWD_ENCRYPTION"]	= method;
    Settings["GROUP_ENCRYPTION"]	= PamSettings::GetGroupHashMethod ();

    // cracklib and pwhistory settings
    Settings ["PASS_MIN_LEN"] = "5";
    Settings ["PASSWD_USE_CRACKLIB"] = "no";
    Settings ["PASSWD_REMEMBER_HISTORY"]	= "0";

    map pam_cracklib	= Pam::Query ("cracklib");
    if (size (pam_cracklib) > 0)
	Settings ["PASSWD_USE_CRACKLIB"]	= "yes";
    foreach (string val, pam_cracklib["password"]:[], {
	list lval	= splitstring (val, "=");
	if (issubstring (val, "dictpath=")) {
            Settings ["CRACKLIB_DICT_PATH"] = lval[1]:"/usr/lib/cracklib_dict";
	}
	if (issubstring (val, "minlen=") && lval[1]:"" != "")
	    Settings ["PASS_MIN_LEN"] = lval[1]:"5";
    });

    map pam_history	= Pam::Query ("pwhistory");
    foreach (string val, pam_history["password"]:[], {
	list lval	= splitstring (val, "=");
	if (issubstring (val, "remember=") && lval[1]:"" != "")
	    Settings ["PASSWD_REMEMBER_HISTORY"] = lval[1]:"0";
    });

    y2debug("Settings=%1", Settings);

    /* Local permissions hack */

    string perm = Settings["PERMISSION_SECURITY"]:"";
    if(issubstring(perm, "easy")) perm = "easy";
    else if(issubstring(perm, "paranoid")) perm = "paranoid";
    else if(issubstring(perm, "secure")) perm = "secure";
    else perm = "secure";
    Settings["PERMISSION_SECURITY"] = perm;
    y2debug("Settings=%1", Settings);

    modified = false;

    // remeber the read values
    Settings_bak = Settings;
    return true;
}


map<string,string> activation_mapping = $[
    "SYSLOG_ON_NO_ERROR" : "/etc/init.d/boot.clock start",
    "DHCPD_RUN_CHROOTED" : "/etc/init.d/dhcpd restart",
    "DHCPD_RUN_AS" : "/etc/init.d/dhcpd restart",
    // restart sendmail or postfix - whatever is installed
    "SMTPD_LISTEN_REMOTE" : "(test -e /etc/init.d/sendmail && /sbin/SuSEconfig --module sendmail && /etc/init.d/sendmail restart) || (test -e /etc/init.d/postfix && /sbin/SuSEconfig --module postfix && /etc/init.d/postfix restart)",
    "IP_TCP_SYNCOOKIES" : "/etc/init.d/boot.ipconfig start",
    "IP_FORWARD" : "/etc/init.d/boot.ipconfig start",
    "IPV6_FORWARD" : "/etc/init.d/boot.ipconfig start",
];

/**
 * Write all security settings
 * @return true on success
 */
global define boolean Write() {

    if(!modified) return true;
    y2milestone("Writing configuration");

    /* Security read dialog caption */
    string caption = _("Saving Security Configuration");
    integer steps = 4;

    Progress::New( caption, " ", steps, [
	    /* Progress stage 1/4 */
	    _("Write security settings"),
	    /* Progress stage 2/4 */
	    _("Write inittab settings"),
	    /* Progress stage 3/4 */
	    _("Write PAM settings"),
	    /* Progress stage 4/4 */
	    _("Run SuSEconfig"),
	], [
	    /* Progress step 1/5 */
	    _("Writing security settings..."),
	    /* Progress step 2/5 */
	    _("Writing inittab settings..."),
	    /* Progress step 3/5 */
	    _("Writing PAM settings..."),
	    /* Progress step 4/5 */
	    _("Running SuSEconfig"),
	    /* Progress step 5/5 */
	    _("Finished")
	],
	""
    );

    /* Write security settings */
    if(Abort()) return false;
    Progress::NextStage();

    y2debug("Settings=%1", Settings);
    Settings["PERMISSION_SECURITY"] = Settings["PERMISSION_SECURITY"]:"" + " local";

    list<string> commitlist = [];
    mapmap(string file, list<string> vars, Locations, {
	maplist(string var, vars, {
	    string val = Settings[var]:"";
	    if(val == nil) val = "";
	    if(val != SCR::Read(topath(file + "." + var))) {
		SCR::Write(topath(file + "." + var), val);
		commitlist = (list<string>) union(commitlist, [ file ]);
	    }
	});
	return $[0: 0];
    });

    maplist(string file, commitlist, {
	SCR::Write(topath(file), nil);
    });

    /* Write inittab settings */
    if(Abort()) return false;
    Progress::NextStage();

    string ca = Settings["CONSOLE_SHUTDOWN"]:"ignore";
    if(ca == "reboot")
	SCR::Write(.etc.inittab.ca, ":ctrlaltdel:/sbin/shutdown -r -t 4 now");
    else if(ca == "halt")
	SCR::Write(.etc.inittab.ca, ":ctrlaltdel:/sbin/shutdown -h -t 4 now");
    else
	SCR::Write(.etc.inittab.ca, ":ctrlaltdel:/bin/true");
    SCR::Write(.etc.inittab, nil);

    // re-read the modified inittab (#83480)
    SCR::Execute (.target.bash, "/sbin/telinit q");

    /* Write pam settings */
    if(Abort()) return false;
    Progress::NextStage();

    /* pam stuff */
    string encr = Settings["PASSWD_ENCRYPTION"]:"blowfish";
    PamSettings::SetDefaultValue ("CRYPT_FILES", encr);

    // use cracklib?
    if(Settings["PASSWD_USE_CRACKLIB"]:"no" == "yes") {
	Pam::Add ("cracklib");
	string pth = Settings["CRACKLIB_DICT_PATH"]:"/usr/lib/cracklib_dict";
	if (pth != "/usr/lib/cracklib_dict")
	    Pam::Add ("--cracklib-dictpath=" + pth);
    }
    else
	Pam::Remove ("cracklib");

    // save min pass length
    if (Settings["PASS_MIN_LEN"]:"5" != "5" && Settings["PASSWD_USE_CRACKLIB"]:"no" == "yes")
    {
	Pam::Add ("cracklib"); // minlen is part of cracklib
	Pam::Add (sformat ("cracklib-minlen=%1", Settings["PASS_MIN_LEN"]:"5"));
    }
    else
	Pam::Remove ("cracklib-minlen");

    // save "remember" value (number of old user passwords to not allow)
    if (Settings["PASSWD_REMEMBER_HISTORY"]:"0" != "0")
    {
	Pam::Add ("pwhistory");
	Pam::Add (sformat ("pwhistory-remember=%1",
	    Settings["PASSWD_REMEMBER_HISTORY"]:"0"));
    }
    else
	Pam::Remove ("pwhistory-remember");

    PamSettings::Write (false);

    /* enable sysrq? */
    boolean sysrq = Settings["ENABLE_SYSRQ"]:"no" == "yes";
    if(sysrq)
	SCR::Execute(.target.bash, "echo 1 > /proc/sys/kernel/sysrq");
    else
	SCR::Execute(.target.bash, "echo 0 > /proc/sys/kernel/sysrq");

    /* Finish him: SuSEconfig */
    if(Abort()) return false;
    Progress::NextStage();

    string dm = (string)SCR::Read(.sysconfig.displaymanager.DISPLAYMANAGER);
    string mod = (dm == "kdm" || dm == "") ? "kdm3" : dm;

    SCR::Execute(.target.bash, "/sbin/SuSEconfig --module kde3");
    SCR::Execute(.target.bash, "/sbin/SuSEconfig --module " + mod);
    SCR::Execute(.target.bash, "/sbin/SuSEconfig --module permissions");

    // ensure polkit privileges are applied (bnc #541393)
    if (FileUtils::Exists ("/sbin/set_polkit_default_privs"))
	SCR::Execute (.target.bash, "/sbin/set_polkit_default_privs");

    SCR::Execute(.target.bash, "/sbin/SuSEconfig --module profiles");

    if(Abort()) return false;
    Progress::NextStage();

    // activate the changes
    foreach(string setting, string action, activation_mapping,
	{
	    if (Settings[setting]:"" != Settings_bak[setting]:"")
	    {
		y2milestone("Option %1 has been modified, activating the change: %2", setting, action);

		integer res = (integer)SCR::Execute(.target.bash, action);
		if (res != 0)
		{
		    y2error("Activation failed");
		}
	    }
	}
    );

    if(Abort()) return false;
    modified = false;
    return true;
}

/**
 * Get all security settings from the first parameter
 * (For use by autoinstallation.)
 * @param settings The YCP structure to be imported.
 * @return boolean True on success
 */
global define boolean Import(map settings) {
    if(settings == $[]) return true;

    modified = true;
    map tmpSettings = $[];
    foreach(string k, string v, Settings, {
	if (!haskey(settings, k))
	    tmpSettings[k] = v;
	else
	    tmpSettings[k] = settings[k]:"";
    });
    Settings = (map<string,string>) eval(tmpSettings);
    return true;
}

/**
 * Dump the security settings to a single map
 * (For use by autoinstallation.)
 * @return map Dumped settings (later acceptable by Import ())
 */
global define map Export() {
    return (map) eval(Settings);
}

/**
 * Create a textual summary and a list of unconfigured cards
 * @return summary of the current configuration
 */
global define list Summary() {

    map<string,string> settings = Security::Settings;
    foreach (string key, Security::do_not_test, {
        settings        = remove (settings, key);
    });

    /* Determine current settings */
    any current = `custom;
    maplist(string key, map level, Levels, {
	y2debug("%1=%2", key, level);
	if(level == settings)
	    current = key;
    });
    y2debug("%1=%2", current, Settings);

    /* Summary text */
    string summary = _("Current Security Level: Custom settings");
    if(current != `custom)
	/* Summary text */
	summary = sformat(_("Current Security Level: %1"), LevelsNames[(string) current]:"");

    return [ summary, [] ];
}

/**
 * Create an overview table with all configured cards
 * @return table items
 */
global define list Overview() {
    return [];
}

/* EOF */
}

ACC SHELL 2018