def fixShadow(self): success = True if not os.path.exists(self.shadowfile): self.detailedresults += self.shadowfile + "does not exist. \ Will not perform fix on shadow file\n" return False if self.fixusers: contents = readFile(self.shadowfile, self.logger) if self.ph.manager == "apt-get": perms = [0, 42, 0o640] else: perms = [0, 0, 0o400] if not checkPerms(self.shadowfile, perms, self.logger) and \ not checkPerms(self.shadowfile, [0, 0, 0], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) setPerms(self.shadowfile, perms, self.logger, self.statechglogger, myid) tmpdate = strftime("%Y%m%d") tmpdate = list(tmpdate) date = tmpdate[0] + tmpdate[1] + tmpdate[2] + tmpdate[3] + "-" + \ tmpdate[4] + tmpdate[5] + "-" + tmpdate[6] + tmpdate[7] for user in self.fixusers: cmd = ["chage", "-d", date, "-m", "1", "-M", "180", "-W", "28", "-I", "35", user] self.ch.executeCommand(cmd) # We have to do some gymnastics here, because chage writes directly # to /etc/shadow, but statechglogger expects the new contents to # be in a temp file. newContents = readFile(self.shadowfile, self.logger) shadowTmp = "/tmp/shadow.stonixtmp" createFile(shadowTmp, self.logger) writeFile(shadowTmp, "".join(newContents) + "\n", self.logger) writeFile(self.shadowfile, "".join(contents) + "\n", self.logger) self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {'eventtype': 'conf', 'filepath': self.shadowfile} self.statechglogger.recordchgevent(myid, event) self.statechglogger.recordfilechange(self.shadowfile, shadowTmp, myid) shutil.move(shadowTmp, self.shadowfile) os.chmod(self.shadowfile, perms[2]) os.chown(self.shadowfile, perms[0], perms[1]) resetsecon(self.shadowfile) return success
def reportsolaris(self): '''because solaris has to be different :returns: bool @author bemalmbe ''' # set kve arguments for reportsolaris and fixsolaris compliant = True directive = {'permitrootlogin': '******'} kvpath = '/etc/ssh/sshd_config' kvtype = 'conf' kvtmppath = self.kvpath + '.stonixtmp' kvintent = 'present' kvconftype = 'space' if not checkPerms(kvpath, [0, 3, 420], self.logger): compliant = False self.editor = KVEditorStonix(self.statechglogger, self.logger, kvtype, kvpath, kvtmppath, directive, kvintent, kvconftype) if not self.editor.report(): compliant = False return compliant
def reportFreebsd1(self): '''Freebsd specific report method1 that ensures the items in the file exist in /etc/sysctl.conf. Sets self.compliant to True if all items exist in the file. Returns True if successful in updating the file :returns: bool ''' compliant = True if not os.path.exists(self.path): self.detailedresults += self.path + " does not exist\n" compliant = False else: ffc = {"net.inet.icmp.bmcastecho": "0", "net.inet.ip.redirect": "0", "net.inet.icmp.maskrepl": "0", "net.inet.ip.sourceroute": "0", "net.inet.ip.accept_sourceroute": "0", "net.inet.tcp.syncookies": "1"} kvtype = "conf" intent = "present" self.editor = KVEditorStonix(self.statechglogger, self.logger, kvtype, self.path, self.tmpPath, ffc, intent, "openeq") if not self.editor.report(): compliant = False if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions are incorrect on " + \ self.path + ": Expected 644, found " + \ str(getOctalPerms(self.path)) + "\n" compliant = False return compliant
def fixFreebsd(self): if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.path, [0, 0, 0o644], self.logger, self.statechglogger, myid): return False if self.networkTuning1.getcurrvalue() or \ self.networkTuning2.getcurrvalue(): if self.editor.fixables: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor.setEventID(myid) if not self.editor.fix(): return False elif not self.editor.commit(): return False os.chown(self.path, 0, 0) os.chmod(self.path, 0o644) resetsecon(self.path) cmd = ["/usr/sbin/service", "sysctl", "restart"] self.ch.executeCommand(cmd) if self.ch.getReturnCode() != 0: self.detailedresults = "Unable to restart sysctl\n" self.logger.log(LogPriority.DEBUG, self.detailedresults) return False else: return True else: return True
def reportFreebsd2(self): '''Freebsd specific report method1 that ensures the items in fileContents exist in /etc/sysctl.conf. Sets self.compliant to True if all items exist in the file. Returns True if successful in updating the file :returns: bool ''' compliant = True if not os.path.exists(self.path): self.detailedresults += self.path + " does not exist\n" compliant = False else: ffc = {"net.inet.ip.forwarding": "0", "net.inet.ip.fastforwarding": "0"} if not self.networkTuning1.getcurrvalue(): kvtype = "conf" intent = "present" self.editor = KVEditorStonix(self.statechglogger, self.logger, kvtype, self.path, self.tmpPath, ffc, intent, "closedeq") else: self.editor.setData(ffc) if not self.editor.report(): compliant = False if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions are incorrect on " + \ self.path + ": Expected 644, found " + \ str(getOctalPerms(self.path)) + "\n" compliant = False return compliant
def check_security_limits(self): '''check the limits.conf file for the configuration line * hard core 0 :returns: compliant :rtype: bool @author: ??? ''' compliant = True securitylimits = "/etc/security/limits.conf" coresetting = "(^\*)\s+hard\s+core\s+0?" if os.path.exists(securitylimits): if not checkPerms(securitylimits, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions incorrect on " + securitylimits + "\n" compliant = False contents = readFile(securitylimits, self.logger) if contents: found = False for line in contents: if re.search(coresetting, line.strip()): found = True if not found: self.detailedresults += "Correct configuration line * hard core 0 " + \ "not found in /etc/security/limits.conf\n" compliant = False else: self.detailedresults += securitylimits + " file doesn't exist\n" return compliant
def checklogindefs(self): '''report method for various distros of linux and solaris''' compliant = True debug = "" if not os.path.exists(self.logdeffile): compliant = False self.detailedresults += self.logdeffile + " file does not exist\n" elif not checkPerms(self.logdeffile, [0, 0, 0o644], self.logger): compliant = False self.detailedresults += self.logdeffile + " does not have " + \ "the correct permissions. Expected 644, found " + \ str(getOctalPerms(self.logdeffile)) + ".\n" tmpfile = self.logdeffile + ".tmp" self.editor1 = KVEditorStonix(self.statechglogger, self.logger, "conf", self.logdeffile, tmpfile, self.specs, "present", "space") if not self.editor1.report(): self.detailedresults += self.logdeffile + " does not " + \ "contain the correct contents\n" debug = self.logdeffile + " doesn't contain the correct " + \ "contents\n" self.logger.log(LogPriority.DEBUG, debug) compliant = False return compliant
def fixsolaris(self): '''because solaris has to be different @author bemalmbe ''' if not checkPerms(self.editor.getPath(), [0, 3, 420], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.editor.getPath(), [0, 3, 420], self.logger, self.statechglogger, myid): self.rulesuccess = False if self.editor.fixables or self.editor.removeables: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor.setEventID(myid) if not self.editor.fix(): self.detailedresults += "Unable to run fix for kveditor\n" self.rulesuccess = False return False elif not self.editor.commit(): self.detailedresults += "Unable to run commit for kveditor\n" self.rulesuccess = False return False return True
def checklogindefs(self): """ Method to check the password hash algorithm settings in login.defs :return: compliant :rtype: bool """ compliant = True if os.path.exists(self.logindefs): if not checkPerms(self.logindefs, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions incorrect for " + \ self.logindefs + " file\n" compliant = False data = {"MD5_CRYPT_ENAB": "no", "ENCRYPT_METHOD": "SHA512", "PASS_MAX_DAYS": "180", "PASS_MIN_DAYS": "1", "PASS_WARN_AGE": "7", "FAIL_DELAY": "4"} tmppath = self.logindefs + ".stonixtmp" self.editor2 = KVEditorStonix(self.statechglogger, self.logger, "conf", self.logindefs, tmppath, data, "present", "space") if not self.editor2.report(): debug = self.logindefs + " doesn't contain the correct " + \ "contents\n" self.detailedresults += self.logindefs + " doesn't contain " + \ "the correct contents\n" self.logger.log(LogPriority.DEBUG, debug) compliant = False return compliant
def report(self): '''The report method examines the current configuration and determines whether or not it is correct. If the config is correct then the self.compliant, self.detailedresults and self.currstate properties are updated to reflect the system status. self.rulesuccess will be updated if the rule does not succeed. Perform a check to see if PROMPT has been set to 'no' or not :returns: bool @author bemalmbe @change: dwalker ''' try: self.detailedresults = "" compliant = True self.perms = [0, 0, 420] self.helper = Pkghelper(self.logger, self.environ) if self.helper.manager == "portage": self.filepath = "/etc/conf.d/rc" keyval = {"RC_INTERACTIVE": "no"} elif self.helper.manager == "zypper": self.filepath = "/etc/sysconfig/boot" keyval = {"PROMPT_FOR_CONFIRM": "no"} elif self.helper.manager == "apt-get": self.filepath = "/etc/default/grub" keyval = {"GRUB_DISABLE_RECOVERY": '"true"'} self.restart = "/usr/sbin/update-grub" elif self.helper.manager == "yum" or self.helper.manager == "dnf": self.filepath = "/etc/sysconfig/init" keyval = {"PROMPT": "no"} tmpPath = self.filepath + ".tmp" if not os.path.exists(self.filepath): if createFile(self.filepath, self.logger): self.created = True if not checkPerms(self.filepath, self.perms, self.logger): compliant = False self.detailedresults += "Permissions are not correct on " + \ self.filepath + "\n" self.editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.filepath, tmpPath, keyval, "present", "closedeq") if os.path.exists(self.filepath): if not self.editor.report(): self.detailedresults += "Configuration for " + \ self.filepath + " is incorrect via kveditor report\n" compliant = False self.compliant = compliant except (KeyboardInterrupt, SystemExit): raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def fixMain(self, command): '''Entries that are found with an empty password field (2nd field) should have the blank field replaced with an ! @author: dwalker :param command: ''' success = True if os.path.exists(self.shadow): if self.empty: for user in self.empty: try: retval = call(command + user, stdout=None, shell=True) if retval != 0: self.detailedresults += "not able to lock the \ following account: " + user + "\n" success = False except OSError: success = False self.detailedresults += traceback.format_exc() + "\n" self.detailedresults += " unable to run the account \ lock command\n" if self.ph: if self.ph.manager == "apt-get": retval = getUserGroupName("/etc/shadow") if retval[0] != "root" or retval[1] != "shadow": uid = pwd.getpwnam("root").pw_uid gid = grp.getgrnam("shadow").gr_gid setPerms("/etc/shadow", [uid, gid, 416], self.logger) else: if not checkPerms(self.shadow, [0, 0, 256], self.logger) \ and not checkPerms(self.shadow, [0, 0, 0], self.logger): if not setPerms(self.shadow, [0, 0, 256], self.logger): success = False else: if not checkPerms(self.shadow, [0, 0, 256], self.logger) and \ not checkPerms(self.shadow, [0, 0, 0], self.logger): if not setPerms(self.shadow, [0, 0, 256], self.logger): success = False return success else: self.detailedresults += "/etc/shadow file or /etc/master.passwd \ file not present, cannot perform fix\n" return False
def reportSSHFile(self, sshfile, directives): """ Report configuration options of config files :param: sshfile - filepath string :param: directives - dictionary of desired directives :return: compliant :rtype: bool """ compliant = True debug = "" directives = dict(directives) tpath = sshfile + ".tmp" if os.path.exists(sshfile): if re.search("Ubuntu", self.environ.getostype()): if sshfile == "/etc/ssh/sshd_config": del (directives["GSSAPIAuthentication"]) del (directives["KerberosAuthentication"]) elif sshfile == "/etc/ssh/ssh_config": del (directives["GSSAPIAuthentication"]) elif self.environ.getostype() == "Mac OS X" and self.mac_piv_auth_CI.getcurrvalue(): if sshfile == "/private/etc/ssh/sshd_config": directives["PasswordAuthentication"] = "no" self.server = directives editor = KVEditorStonix(self.statechglogger, self.logger, "conf", sshfile, tpath, directives, "present", "space") if not editor.report(): self.detailedresults += "Did not find the correct " + \ "contents in sshd_config\n" compliant = False # for ubuntu systems we want to make sure the following two # directives don't exist in the server file if re.search("Ubuntu", self.environ.getostype()): if sshfile == "/etc/ssh/sshd_config": directives = {"GSSAPIAuthentication": "", "KerberosAuthentication": ""} elif sshfile == "/etc/ssh/ssh_config": directives = {"GSSAPIAuthentication": ""} editor.setIntent("notpresent") editor.setData(directives) if not editor.report(): self.detailedresults += "didn't find the correct" + \ " contents in sshd_config\n" self.logger.log(LogPriority.DEBUG, debug) compliant = False if not checkPerms(sshfile, [0, 0, 0o644], self.logger): self.detailedresults += "Incorrect permissions for " + \ "file " + self.serverfile + "\n" compliant = False else: self.detailedresults += sshfile + " does not exist\n" compliant = False return compliant
def chkLogin(self): compliant = True if os.path.exists(self.loginfile): if not checkPerms(self.loginfile, [0, 0, 0o644], self.logger): compliant = False self.detailedresults += self.libuserfile + " does not have " + \ "the correct permissions. Expected 644, found " + \ str(getOctalPerms(self.libuserfile)) + ".\n" contents = readFile(self.loginfile, self.logger) iterator1 = 0 for line in contents: if re.search("^#", line) or re.match('^\s*$', line): iterator1 += 1 elif re.search('^default:\\\\$', line.strip()): found = True temp = contents[iterator1 + 1:] length2 = len(temp) - 1 iterator2 = 0 for line2 in temp: if re.search('^[^:][^:]*:\\\\$', line2): contents2 = temp[:iterator2] break elif iterator2 < length2: iterator2 += 1 elif iterator2 == length2: contents2 = temp[:iterator2] break else: iterator1 += 1 if contents2: for key in self.Fspecs: found = False for line in contents2: if re.search("^#", line) or re.match('^\s*$', line): continue elif re.search('^:' + key, line.strip()): if re.search('=', line): temp = line.split('=') if re.search(str(self.Fspecs[key]) + '(:\\\\|:|\\\\|\s)', temp[1]): found = True continue else: found = False break if not found: compliant = False return compliant else: self.detailedresults += self.loginfile + "does not exist. " + \ "Please note that the fix for this rule will not attempt " + \ "to create this file.\n" compliant = False debug = "chkLogin method is returning " + (compliant) + " compliance\n" self.logger.log(LogPriority.DEBUG, debug) return compliant
def report(self): try: self.detailedresults = "" self.ph = Pkghelper(self.logger, self.environ) self.data1 = { "ddns-update-style": "none;", "deny": ["declines;", "bootp;"] } self.data2 = [ "domain-name", "domain-name-servers", "nis-domain", "nis-servers", "ntp-servers", "routers", "time-offset" ] if self.ph.manager == "zypper": self.path = "/etc/dhcpd.conf" elif self.ph.manager == "yum" or self.ph.manager == "dnf": self.path = "/etc/dhcp/dhcpd.conf" elif self.ph.manager == "apt-get": self.path = "/etc/dhcp/dhcpd.conf" self.tmppath = self.path + ".tmp" compliant = True if os.path.exists(self.path): if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.detailedresults += "The permissions on " + \ self.path + " are incorrect\n" compliant = False self.editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.path, self.tmppath, self.data1, "present", "space") if not self.editor.report(): self.detailedresults += self.path + " doesn't contain " + \ "the correct contents\n" compliant = False contents = readFile(self.path, self.logger) for line in contents: if re.match('^#', line) or re.match(r'^\s*$', line): continue if re.search("^option", line): linesplit = line.split() if len(linesplit) >= 2: for item in self.data2: if re.search(item, linesplit[1]): compliant = False self.detailedresults += "Unwanted " + \ "option found in " + self.path + \ ": " + line self.compliant = compliant except (KeyboardInterrupt, SystemExit): raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def setaccountlockout(self, regex): """ configure the account lockout time in pam :param regex: string; regular expression :return: success :rtype: bool """ success = True pamfiles = [] if self.ph.manager in ("yum", "dnf"): pamfiles.append(self.pamauthfile) pamfiles.append(self.pampassfile) writecontents = self.auth + "\n" + self.acct + "\n" + \ self.password + "\n" + self.session else: pamfiles.append(self.pamauthfile) writecontents = self.auth for pamfile in pamfiles: if not os.path.exists(pamfile): self.detailedresults += pamfile + " doesn't exist.\n" + \ "Stonix will not attempt to create this file " + \ "and the fix for the this rule will not continue\n" return False # """Check permissions on pam file(s)""" for pamfile in pamfiles: if not checkPerms(pamfile, [0, 0, 0o644], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(pamfile, [0, 0, 0o644], self.logger, self.statechglogger, myid): success = False self.detailedresults += "Unable to set " + \ "correct permissions on " + pamfile + "\n" contents = readFile(pamfile, self.logger) found = False for line in contents: if re.search(regex, line.strip()): found = True if not found: tmpfile = pamfile + ".stonixtmp" if writeFile(tmpfile, writecontents, self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {'eventtype': 'conf', 'filepath': pamfile} self.statechglogger.recordchgevent(myid, event) self.statechglogger.recordfilechange(pamfile, tmpfile, myid) os.rename(tmpfile, pamfile) os.chown(pamfile, 0, 0) os.chmod(pamfile, 0o644) resetsecon(pamfile) else: self.detailedresults += "Unable to write to " + pamfile + "\n" success = False return success
def fix(self): try: if not self.ci.getcurrvalue(): return results = "" success = True # Clear out event history so only the latest fix is recorded self.iditerator = 0 eventlist = self.statechglogger.findrulechanges(self.rulenumber) for event in eventlist: self.statechglogger.deleteentry(event) if os.path.exists(self.path): if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.path, [0, 0, 0o644], self.logger, self.statechglogger, myid): success = False results += "Could not set permissions on " + \ self.path + "\n" if self.editor.fixables or self.editor.removeables: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor.setEventID(myid) if not self.editor.fix(): debug = "kveditor fix did not run successfully\n" self.logger.log(LogPriority.DEBUG, debug) success = False elif not self.editor.commit(): debug = "kveditor commit did not run successfully\n" self.logger.log(LogPriority.DEBUG, debug) success = False os.chown(self.path, 0, 0) os.chmod(self.path, 0o644) resetsecon(self.path) else: success = False results += "Could not find path to sshd_config\n" self.detailedresults = results self.rulesuccess = success except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception: self.rulesuccess = False success = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("fix", success, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.rulesuccess
def reportLinux1(self): '''Linux specific report method that ensures the items in fileContents exist in /etc/sysctl.conf. Sets self.compliant to True if all items exist in the file. Returns True if successful in updating the file :returns: bool ''' compliant = True if not os.path.exists(self.path): self.detailedresults += self.path + " does not exist\n" compliant = False else: lfc = {"net.ipv4.conf.all.secure_redirects": "0", "net.ipv4.conf.all.accept_redirects": "0", "net.ipv4.conf.all.rp_filter": "1", "net.ipv4.conf.all.log_martians": "1", "net.ipv4.conf.all.accept_source_route": "0", "net.ipv4.conf.default.accept_redirects": "0", "net.ipv4.conf.default.secure_redirects": "0", "net.ipv4.conf.default.rp_filter": "1", "net.ipv4.conf.default.accept_source_route": "0", "net.ipv4.tcp_syncookies": "1", "net.ipv4.icmp_echo_ignore_broadcasts": "1", "net.ipv4.tcp_max_syn_backlog": "4096"} editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.path, self.tmpPath, lfc, "present", "openeq") if not editor.report(): self.detailedresults += self.path + " is not configured " + \ "correctly for configuration item 1\n" compliant = False if not checkPerms(self.path, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions are incorrect on " + \ self.path + "\n" compliant = False for key in lfc: self.ch.executeCommand("/sbin/sysctl " + key) retcode = self.ch.getReturnCode() if retcode != 0: self.detailedresults += "Failed to get value of core dumps configuration with sysctl command\n" errmsg = self.ch.getErrorString() self.logger.log(LogPriority.DEBUG, errmsg) compliant = False else: output = self.ch.getOutputString() if output.strip() != key + " = " + lfc[key]: compliant = False self.detailedresults += "sysctl output has incorrect value: " + \ output + "\n" return compliant
def checklibuser(self): '''Private method to check the password hash algorithm settings in libuser.conf. @author: dwalker :returns: bool ''' compliant = True '''check if libuser is intalled''' if not self.ph.check("libuser"): '''if not, check if available''' if self.ph.checkAvailable("libuser"): self.detailedresults += "libuser available but not installed\n" return False else: '''not available, not a problem''' return True '''create a kveditor for file if it exists, if not, we do it in the setlibuser method inside the fix''' if os.path.exists(self.libuserfile): data = {"userdefaults": {"LU_SHADOWMAX": "", "LU_SHADOWMIN": "", "LU_SHADOWWARNING": "", "LU_UIDNUMBER": "", "LU_SHADOWINACTIVE": "", "LU_SHADOWEXPIRE": ""}} datatype = "tagconf" intent = "notpresent" tmppath = self.libuserfile + ".tmp" self.editor2 = KVEditorStonix(self.statechglogger, self.logger, datatype, self.libuserfile, tmppath, data, intent, "openeq") if not self.editor2.report(): debug = "/etc/libuser.conf doesn't contain the correct " + \ "contents\n" self.detailedresults += "/etc/libuser.conf doesn't " + \ "contain the correct contents\n" self.logger.log(LogPriority.DEBUG, debug) compliant = False if not checkPerms(self.libuserfile, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions are incorrect on " + \ self.libuserfile + "\n" compliant = False else: self.detailedresults += "Libuser installed but libuser " + \ "file doesn't exist\n" compliant = False return compliant
def reportMac(self): '''Mac specific report method1 that ensures the items in fileContents exist in /etc/sysctl.conf. Sets self.compliant to True if all items exist in the file. :returns: compliant :rtype: bool @author: dwalker @change: Breen Malmberg - 1/10/2017 - minor doc string adjustments; fixed permissions on file /etc/sysctl.conf (needs to be 0o600; was 0o644); try/except ''' compliant = True try: self.editor = None if not os.path.exists(self.path): self.detailedresults += self.path + " does not exist\n" compliant = False else: mfc = {"net.inet.ip.forwarding": "0", "net.inet.ip.redirect": "0"} kvtype = "conf" intent = "present" self.editor = KVEditorStonix(self.statechglogger, self.logger, kvtype, self.path, self.tmpPath, mfc, intent, "closedeq") if not self.editor.report(): self.detailedresults += self.path + " is not " + \ "configured correctly\n" compliant = False else: self.detailedresults += self.path + " is " + \ "configured correctly\n" if not checkPerms(self.path, [0, 0, 0o600], self.logger): self.detailedresults += "Permissions are incorrect on " + \ self.path + ": Expected 644, found " + \ str(getOctalPerms(self.path)) + "\n" compliant = False except Exception: raise return compliant
def report(self): '''The report method examines the current configuration and determines whether or not it is correct. If the config is correct then the self.compliant, self.detailedresults and self.currstate properties are updated to reflect the system status. self.rulesuccess will be updated if the rule does not succeed. :returns: self.compliant :rtype: bool @author bgonz12 ''' try: compliant = True self.detailedresults = "" if not os.path.exists(self.securettypath): compliant = False self.detailedresults += self.securettypath + " is missing\n" else: if not checkPerms(self.securettypath, [0, 0, 0o600], self.logger): compliant = False self.detailedresults += "Permissions incorrect on " + self.securettypath + "\n" contents = readFileString(self.securettypath, self.logger) if contents != "": compliant = False self.detailedresults += self.securettypath + " should be empty\n" else: self.isblank = True self.compliant = compliant except (OSError): self.detailedresults = traceback.format_exc() self.logger.log(LogPriority.DEBUG, self.detailedresults) except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception as err: self.rulesuccess = False self.detailedresults = self.detailedresults + "\n" + str(err) + \ " - " + str(traceback.format_exc()) self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def report(self): try: results = "" compliant = True path1 = "/private/etc/sshd_config" path2 = "/private/etc/ssh/sshd_config" if self.usesSip(): if os.path.exists(path2): self.path = path2 elif os.path.exists(path1): self.path = path1 else: compliant = False results += "Could not find path to sshd_config file\n" else: if os.path.exists(path1): self.path = path1 elif os.path.exists(path2): self.path = path2 else: compliant = False results += "Could not find path to sshd_config file\n" self.tmppath = self.path + ".tmp" if os.path.exists(self.path): self.editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.path, self.tmppath, self.ssh, "present", "space") if not self.editor.report(): compliant = False results += "Settings in " + self.path + " are not " + \ "correct\n" if not checkPerms(self.path, [0, 0, 0o644], self.logger): compliant = False results += self.path + " permissions are incorrect\n" self.detailedresults = results self.compliant = compliant except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def fixLogDef(self, specs): success = True debug = "" if not os.path.exists(self.logdeffile): if createFile(self.logdeffile, self.logger): self.logindefcreate = True setPerms(self.logdeffile, [0, 0, 0o644], self.logger) tmpfile = self.logdeffile + ".tmp" self.editor1 = KVEditorStonix(self.statechglogger, self.logger, "conf", self.logdeffile, tmpfile, specs, "present", "space") else: self.detailedresults += "Was not able to create " + \ self.logdeffile + " file\n" success = False if self.logindefcreate: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {"eventtype": "creation", "filepath": self.logdeffile} self.statechglogger.recordchgevent(myid, event) elif not checkPerms(self.logdeffile, [0, 0, 0o644], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.logdeffile, [0, 0, 0o644], self.logger, self.statechglogger, myid): debug += "permissions not correct on: " + \ self.logdeffile + "\n" success = False if self.editor1.fixables or self.editor1.removeables: if not self.logindefcreate: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor1.setEventID(myid) if not self.editor1.fix(): debug += "fixLogDef editor.fix did not complete successfully\n" success = False elif not self.editor1.commit(): debug += "fixLogDef editor.commit did not complete successfully\n" success = False os.chown(self.logdeffile, 0, 0) os.chmod(self.logdeffile, 0o644) resetsecon(self.logdeffile) if debug: self.logger.log(LogPriority.DEBUG, debug) return success
def checklibuser(self): """ Private method to check the password hash algorithm settings in libuser.conf @author: Derek Walker :return: compliant :rtype: bool """ compliant = True # """check if libuser is intalled""" if not self.ph.check("libuser"): # """if not, check if available""" if self.ph.checkAvailable("libuser"): self.detailedresults += "libuser available but not installed\n" return False else: # """not available, not a problem""" return True # """create a kveditor for file if it exists, if not, we do it in # the setlibuser method inside the fix""" if os.path.exists(self.libuserfile): data = {"defaults": {"crypt_style": "sha512"}} datatype = "tagconf" intent = "present" tmppath = self.libuserfile + ".stonixtmp" self.editor1 = KVEditorStonix(self.statechglogger, self.logger, datatype, self.libuserfile, tmppath, data, intent, "openeq") if not self.editor1.report(): debug = "/etc/libuser.conf doesn't contain the correct contents\n" self.detailedresults += "/etc/libuser.conf doesn't contain the correct contents\n" self.logger.log(LogPriority.DEBUG, debug) compliant = False if not checkPerms(self.libuserfile, [0, 0, 0o644], self.logger): self.detailedresults += "Permissions are incorrect on " + self.libuserfile + "\n" compliant = False else: self.detailedresults += "Libuser installed but libuser file doesn't exist\n" compliant = False return compliant
def report(self): '''DisableNobodyAccess.report() method to report on whether system is compliant or not. If the key-value pair ENABLE_NOBODY_KEYS=NO is present, the system is compliant, if not, system is not compliant @author: dwalker :param self: essential if you override this definition :returns: bool - False if the method died during execution ''' try: compliant = True keys = {"ENABLE_NOBODY_KEYS": "NO"} if os.path.exists(self.path): tmpPath = self.path + ".tmp" self.editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.path, tmpPath, keys, "present", "closedeq") if not self.editor.report(): compliant = False if not checkPerms(self.path, [0, 0, 292], self.logger): compliant = False else: self.createFile(self.path) self.created = True tmpPath = self.path + ".tmp" self.editor = KVEditorStonix(self.statechglogger, self.logger, "conf", self.path, tmpPath, keys, "present", "closedeq") self.editor.fixables = keys compliant = False self.compliant = compliant return compliant except (KeyboardInterrupt, SystemExit): # User initiated exit raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def setlogindefs(self): """ configure login.defs options :return: success :rtype: bool """ success = True if not checkPerms(self.logindefs, [0, 0, 0o644], self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.logindefs, [0, 0, 0o644], self.logger, self.statechglogger, myid): self.detailedresults += "Unable to set permissions on " + self.logindefs + " file\n" success = False if self.editor2: if self.editor2.fixables: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor2.setEventID(myid) if self.editor2.fix(): if self.editor2.commit(): debug = "/etc/login.defs file has been corrected\n" self.logger.log(LogPriority.DEBUG, debug) os.chown(self.logindefs, 0, 0) os.chmod(self.logindefs, 0o644) resetsecon(self.logindefs) else: debug = "Unable to correct the contents of /etc/login.defs\n" self.detailedresults += "Unable to correct the contents of /etc/login.defs\n" self.logger.log(LogPriority.DEBUG, debug) success = False else: self.detailedresults += "Unable to correct the contents of /etc/login.defs\n" debug = "Unable to correct the contents of /etc/login.defs\n" self.logger.log(LogPriority.DEBUG, debug) success = False return success
def report(self): try: self.path = "/etc/securetty" self.serialRE = r"^ttyS\d" self.compliant = True self.detailedresults = "" if re.search("red hat|centos|fedora", self.myos): perms = [0, 0, 0o600] else: perms = [0, 0, 0o644] self.perms = perms if os.path.exists(self.path): sttyText = readFile(self.path, self.logger) for line in sttyText: if re.search(self.serialRE, line): self.compliant = False self.detailedresults += self.path + " contains " + \ "uncommented serial ports.\n" break if not checkPerms(self.path, perms, self.logger): self.compliant = False self.detailedresults += self.path + " permissions " + \ "are incorrect.\n" else: debug = self.path + " does not exist. This is considered " + \ "secure, and should disable all serial ports.\n" self.logger.log(LogPriority.DEBUG, debug) except (KeyboardInterrupt, SystemExit): raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("report", self.compliant, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.compliant
def chkUserAdd(self): compliant = True debug = "" if not os.path.exists(self.useraddfile): self.detailedresults += self.useraddfile + " file does not exist\n" compliant = False else: if not checkPerms(self.useraddfile, [0, 0, 0o600], self.logger): compliant = False self.detailedresults += self.useraddfile + " does not have " + \ "the correct permissions. Expected 600, found " + \ str(getOctalPerms(self.useraddfile)) + ".\n" contents = readFile(self.useraddfile, self.logger) found = False valcorrect = True for line in contents: if re.search("^\#", line) or re.match('^\s*$', line): continue if re.search('^INACTIVE', line.strip()) and re.search('=', line): found = True temp = line.split('=') if int(temp[1].strip()) <= -1 or int(temp[1].strip()) > 35: valcorrect = False break if not found: compliant = False self.detailedresults += "INACTIVE key was not found in " + \ self.useraddfile + "\n" if found and not valcorrect: compliant = False self.detailedresults += "INACTIVE key was found in " + \ self.useraddfile + ", but value is incorrect\n" debug += "chkUserAdd method is returning " + str(compliant) + \ " compliance\n" if debug: self.logger.log(LogPriority.DEBUG, debug) return compliant
def fix(self): '''The fix method will apply the required settings to the system. self.rulesuccess will be updated if the rule does not succeed. Search for the /etc/sysconfig/init configuration file and set the PROMPT setting to PROMPT=no @author bemalmbe @change: dwalker 4/8/2014 implementing KVEditorStonix ''' try: if not self.ci.getcurrvalue(): return self.detailedresults = "" # clear out event history so only the latest fix is recorded self.iditerator = 0 eventlist = self.statechglogger.findrulechanges(self.rulenumber) for event in eventlist: self.statechglogger.deleteentry(event) if os.path.exists(self.filepath): if not checkPerms(self.filepath, self.perms, self.logger): self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(self.filepath, self.perms, self.logger, self.statechglogger, myid): self.rulesuccess = False if self.editor.fixables: if not self.created: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) self.editor.setEventID(myid) if self.editor.fix(): self.detailedresults += "kveditor fix ran successfully\n" if self.editor.commit(): self.detailedresults += "kveditor commit ran " + \ "successfully\n" else: self.detailedresults += "kveditor commit did not " + \ "run successfully\n" self.rulesuccess = False else: self.detailedresults += "kveditor fix did not run " + \ "successfully\n" self.rulesuccess = False os.chown(self.filepath, self.perms[0], self.perms[1]) os.chmod(self.filepath, self.perms[2]) resetsecon(self.filepath) if self.restart: self.ch.executeCommand(self.restart) if self.ch.getReturnCode() != 0: self.detailedresults += "Unable to restart Grub with " + \ "new changes\n" self.rulesuccess = False except (KeyboardInterrupt, SystemExit): raise except Exception: self.rulesuccess = False self.detailedresults += "\n" + traceback.format_exc() self.logdispatch.log(LogPriority.ERROR, self.detailedresults) self.formatDetailedResults("fix", self.rulesuccess, self.detailedresults) self.logdispatch.log(LogPriority.INFO, self.detailedresults) return self.rulesuccess
def fix_security_limits(self): '''ensure the limits.conf file contains the configuration setting * hard core 0 :returns: succcess :rtype: bool @author: ??? ''' success = True path1 = "/etc/security/limits.conf" lookfor1 = "(^\*)\s+hard\s+core\s+0?" created = False if not os.path.exists(path1): if not createFile(path1, self.logger): success = False self.detailedresults += "Unable to create " + path1 + " file\n" else: created = True self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {"eventtype": "creation", "filepath": "path1"} self.statechglogger.recordchgevent(myid, event) if os.path.exists(path1): if not checkPerms(path1, [0, 0, 0o644], self.logger): if not created: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(path1, [0, 0, 0o644], self.logger, self.statechglogger, myid): success = False self.detailedresults += "Unable to correct permissions on " + path1 + "\n" contents = readFile(path1, self.logger) found = False tempstring = "" if contents: for line in contents: if re.search(lookfor1, line.strip()): found = True else: tempstring += line else: found = False if not found: tempstring += "* hard core 0\n" tempfile = path1 + ".stonixtmp" if not writeFile(tempfile, tempstring, self.logger): success = False self.detailedresults += "Unable to write contents to " + path1 + "\n" else: if not created: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {"eventtype": "conf", "filepath": path1} self.statechglogger.recordchgevent(myid, event) self.statechglogger.recordfilechange( path1, tempfile, myid) os.rename(tempfile, path1) setPerms(path1, [0, 0, 0o644], self.logger) resetsecon(path1) return success
def fix_sysctl(self): '''set the systemd configuration setting fs.suid_dumpable to 0 :returns: success :rtype: bool @author: ??? ''' success = True # manually writing key and value to /etc/sysctl.conf sysctl = "/etc/sysctl.conf" created = False if not os.path.exists(sysctl): if createFile(sysctl, self.logger): created = True setPerms(sysctl, [0, 0, 0o644], self.logger) self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) event = {"eventtype": "creation", "filepath": sysctl} self.statechglogger.recordchgevent(myid, event) else: success = False debug = "Unable to create " + sysctl + "\n" self.logger.log(LogPriority.DEBUG, debug) if os.path.exists(sysctl): if not checkPerms(sysctl, [0, 0, 0o644], self.logger): if not created: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) if not setPerms(sysctl, [0, 0, 0o644], self.logger, self.statechglogger, myid): success = False tmpfile = sysctl + ".tmp" editor = KVEditorStonix(self.statechglogger, self.logger, "conf", sysctl, tmpfile, {"fs.suid_dumpable": "0"}, "present", "openeq") if not editor.report(): if editor.fixables: # If we did not create the file, set an event ID for the # KVEditor's undo event if not created: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) editor.setEventID(myid) if not editor.fix(): success = False debug = "Unable to complete kveditor fix method" + \ "for /etc/sysctl.conf file\n" self.logger.log(LogPriority.DEBUG, debug) elif not editor.commit(): success = False debug = "Unable to complete kveditor commit " + \ "method for /etc/sysctl.conf file\n" self.logger.log(LogPriority.DEBUG, debug) if not checkPerms(sysctl, [0, 0, 0o644], self.logger): if not setPerms(sysctl, [0, 0, 0o644], self.logger): self.detailedresults += "Could not set permissions on " + \ self.path + "\n" success = False resetsecon(sysctl) # using sysctl -w command self.logger.log(LogPriority.DEBUG, "Configuring /etc/sysctl fs.suid_dumpable directive") self.ch.executeCommand("/sbin/sysctl -w fs.suid_dumpable=0") retcode = self.ch.getReturnCode() if retcode != 0: success = False self.detailedresults += "Failed to set core dumps variable suid_dumpable to 0\n" errmsg = self.ch.getErrorString() self.logger.log(LogPriority.DEBUG, errmsg) else: self.logger.log(LogPriority.DEBUG, "Re-reading sysctl configuration from files") self.ch.executeCommand("/sbin/sysctl -q -e -p") retcode2 = self.ch.getReturnCode() if retcode2 != 0: success = False self.detailedresults += "Failed to load new sysctl configuration from config file\n" errmsg2 = self.ch.getErrorString() self.logger.log(LogPriority.DEBUG, errmsg2) else: self.iditerator += 1 myid = iterate(self.iditerator, self.rulenumber) command = "/sbin/sysctl -w fs.suid_dumpable=1" event = {"eventtype": "commandstring", "command": command} self.statechglogger.recordchgevent(myid, event) return success