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