class zzzTestRuleSTIGConfigureLoginWindowPolicy(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = STIGConfigureLoginWindowPolicy(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) self.identifier = "mil.disa.STIG.loginwindow.alacarte" if search("10\.10.*", self.environ.getosver()): self.rule.profile = "/Users/vagrant/stonix/src/stonix_resources/files/" + \ "U_Apple_OS_X_10-10_Workstation_V1R2_STIG_Login_Window_Policy.mobileconfig" elif search("10\.11\.*", self.environ.getosver()): self.rule.profile = "/Users/vagrant/stonix/src/stonix_resources/files/" + \ "U_Apple_OS_X_10-11_V1R1_STIG_Login_Window_Policy.mobileconfig" else: self.rule.profile = "/Users/vagrant/stonix/src/stonix_resources/files/" + \ "U_Apple_macOS_10-12_V1R1_STIG_Login_Window_Policy.mobileconfig" def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): success = True self.detailedresults = "" cmd = ["/usr/bin/profiles", "-P"] if not self.ch.executeCommand(cmd): success = False self.detailedresults += "Unable to run profiles command\n" else: output = self.ch.getOutput() if output: for line in output: if search("mil\.disa\.STIG\.loginwindow\.alacarte$", line.strip()): cmd = [ "/usr/bin/profiles", "-R", "-p", self.identifier ] if not self.ch.executeCommand(cmd): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleConfigureGatekeeper(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = ConfigureGatekeeper(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): success = True cmd = ["/usr/bin/profiles", "-L"] #change this to actual gatkeeper profile number profilenum = "C873806E-E634-4E58-B960-62817F398E11" if self.ch.executeCommand(cmd): output = self.ch.getOutput() if output: for line in output: if re.search(profilenum, line): cmd = ["/usr/bin/profiles", "-r", profilenum] if not self.ch.executeCommand(cmd): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): ''' check on whether report was correct @param self: essential if you override this definition @param pCompliance: the self.iscompliant value of rule @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): ''' check on whether fix was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): ''' check on whether undo was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleDisableIPV6(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = DisableIPV6(self.config, self.environ, self.logdispatch, self.statechglogger) self.logger = self.logdispatch self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) self.checkUndo = True def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): '''Configure system for the unit test :param self: essential if you override this definition :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' success = True if self.environ.getosfamily() == "linux": success = self.setLinuxConditions() elif self.environ.getosfamily() == "darwin": success = self.setMacConditions() return success def setLinuxConditions(self): success = True self.ph = Pkghelper(self.logger, self.environ) if not self.messupNetconfigFile(): success = False if not self.messupSysctl(): success = False if not self.messupModprobeFiles(): success = False if not self.messupInterfaceFile(): success = False if self.ph.manager == "apt-get": if not self.messupSSHDFile(): success = False return success def setMacConditions(self): success = True debug = "" networksetup = "/usr/sbin/networksetup" listnetworkservices = networksetup + " -listallnetworkservices" ipv6status = "^IPv6:\s+On" getinfo = networksetup + " -getinfo" self.ch.executeCommand(listnetworkservices) retcode = self.ch.getReturnCode() if retcode != 0: success = False debug = "Failed to get list of network services" self.logger.log(LogPriority.DEBUG, debug) else: networkservices = self.ch.getOutput() for ns in networkservices: # ignore non-network service output lines if re.search("denotes that", ns, re.IGNORECASE): continue else: self.ch.executeCommand(networksetup + ' -setv6automatic ' + '"' + ns + '"') retcode = self.ch.getReturnCode() if retcode != 0: success = False debug = "Failed to get information for network service: " + ns self.logger.log(LogPriority.DEBUG, debug) return success def messupNetconfigFile(self): success = True # stig portion, check netconfig file for correct contents if self.ph.manager == "apt-get": nfspkg = "nfs-common" else: nfspkg = "nfs-utils.x86_64" if self.ph.check(nfspkg): if not self.ph.remove(nfspkg): success = False debug = "Unable to remove nfs package for preconditions" self.logger.log(LogPriority.DEBUG, debug) if os.path.exists("/etc/netconfig"): item1 = "udp6 tpi_clts v inet6 udp - -" item2 = "tcp6 tpi_cots_ord v inet6 tcp - -" item1found, item2found, fixFile = False, False, False writestring = "" contents = readFile("/etc/netconfig", self.logger) for line in contents: writestring += line line = re.sub("\s+", " ", line.strip()) if re.search(item1, line): item1found = True if re.search(item2, line): item2found = True if not item1found: writestring += item1 fixFile = True if not item2found: writestring += item2 fixFile = True if fixFile: if not writeFile("/etc/netconfig", writestring, self.logger): success = False debug = "Unable tomess up /etc/netconfig file for preconditions" self.logger.log(LogPriority.DEBUG, debug) return success def messupSysctl(self): success = True sysctlcmd = "" sysctl = "/etc/sysctl.conf" directives = [ "net.ipv6.conf.all.disable_ipv6=0", "net.ipv6.conf.default.disable_ipv6=0" ] filedirectives = { "net.ipv6.conf.all.disable_ipv6": "0", "net.ipv6.conf.default.disable_ipv6": "0" } tmpfile = sysctl + ".tmp" if os.path.exists(sysctl): editor = KVEditorStonix(self.statechglogger, self.logger, "conf", sysctl, tmpfile, filedirectives, "present", "openeq") if not editor.report(): if not editor.fix(): success = False debug = "Unable to mess up " + sysctl + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) elif not editor.commit(): success = False debug = "Unable to mess up " + sysctl + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) sysctllocs = ["/sbin/sysctl", "/usr/sbin/sysctl"] for loc in sysctllocs: if os.path.exists(loc): sysctlcmd = loc if sysctlcmd: for d in directives: setbadopt = sysctlcmd + " -w " + d self.ch.executeCommand(setbadopt) retcode = self.ch.getReturnCode() if retcode != 0: success = False debug = "Failed to write configuration change: " + d + "\n" self.logger.log(LogPriority.DEBUG, debug) else: debug = "sysctl command not found on system\n" self.logger.log(LogPriority.DEBUG, debug) success = False return success def messupModprobeFiles(self): success = True modprobes = { "options": "ipv6 disable=1", "install": "ipv6 /bin/true", "helloworld": "" } if os.path.exists("/etc/modprobe.d/"): modprobefiles = glob.glob("/etc/modprobe.d/*") for modfile in modprobefiles: tmpfile = modfile + ".tmp" editor = KVEditorStonix(self.statechglogger, self.logger, "conf", modfile, tmpfile, modprobes, "notpresent", "space") if not editor.report(): if not editor.fix(): success = False debug = "Unable to mess up " + modfile + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) elif not editor.commit(): success = False debug = "Unable to mess up " + modfile + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) return success def messupInterfaceFile(self): success = True interface = {"IPV6INIT": '"yes"', "NETWORKING_IPV6": '"yes"'} # Check for existence of interface and network files to be configured if self.ph.manager == "yum": ifacefile = "/etc/sysconfig/network-scripts/" if not os.path.exists(ifacefile): ifacefile = "" netwrkfile = "/etc/sysconfig/network" if not os.path.exists(netwrkfile): netwrkfile = "" elif self.ph.manager == "zypper": ifacefile = "/etc/sysconfig/network/" if not os.path.exists(ifacefile): ifacefile = "" if ifacefile: dirs = glob.glob(ifacefile + "*") for loc in dirs: contents = [] if re.search('^' + ifacefile + 'ifcfg', loc): tmpfile = loc + ".tmp" editor = KVEditorStonix(self.statechglogger, self.logger, "conf", loc, tmpfile, interface, "present", "closedeq") if not editor.report(): if not editor.fix(): success = False debug = "Unable to mess up " + loc + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) elif not editor.commit(): success = False debug = "Unable to mess up " + loc + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) return success def messupSSHDFile(self): success = True sshfile = "/etc/ssh/sshd_config" if os.path.exists(sshfile): tmpfile = sshfile + ".tmp" data = {"AddressFamily": "inet"} editor = KVEditorStonix(self.statechglogger, self.logger, "conf", sshfile, tmpfile, data, "notpresent", "space") if not editor.report(): if not editor.fix(): success = False debug = "Unable to mess up " + sshfile + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) elif not editor.commit(): success = False debug = "Unable to mess up " + sshfile + " file for preconditions" self.logger.log(LogPriority.DEBUG, debug) return success def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \ str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleForceIdleLogout(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = ForceIdleLogout(self.config, self.environ, self.logdispatch, self.statechglogger) self.logger = self.logdispatch self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.rule.filci.updatecurrvalue(True) self.checkUndo = True self.cmdhelper = CommandHelper(self.logger) self.ph = Pkghelper(self.logger, self.environ) self.gnomesettingpath = "/etc/dconf/db/local.d/00-autologout" self.gnomelockpath = "/etc/dconf/db/local.d/locks/autologout" self.undotimeout = "" self.undoforcelogout = "" self.kdesddm = False myos = self.environ.getostype().lower() if re.search("red hat", myos) or re.search("centos", myos): self.gconf = "GConf2" else: self.gconf = "gconf2" self.timeoutci = self.rule.timeoutci.getcurrvalue() def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): '''Configure system for the unit test :param self: essential if you override this definition :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' success = True if self.environ.osfamily == 'linux': try: self.seconds = self.timeoutci * 60 except (TypeError): debug = "FORCEIDLELOGOUTTIMEOUT value is not " + \ "valid!\n" self.logger.log(LogPriority.DEBUG, debug) return False self.kdesddm = self.ph.check("sddm") self.gnomesettingpath = "/etc/dconf/db/local.d/00-autologout" desktopmgr = False desktopmgrs = [ "gdm", "gdm3", "kdm", "kde-workspace", "sddm", "patterns-kde-kde_yast" ] if self.ph.check("gdm") or self.ph.check("gdm3"): desktopmgr = True if self.ph.check("kdm") or self.ph.check("kde-workspace")or \ self.ph.check("sddm") or self.ph.check("patterns-kde-kde_yast"): desktopmgr = True if not desktopmgr: for mgr in desktopmgrs: if self.ph.checkAvailable(mgr): if self.ph.install(mgr): desktopmgr = True if not desktopmgr: success = False debug = "Unable to install a desktop manager for testing\n" self.logger.log(LogPriority.DEBUG, debug) success = self.setgnome() success = self.setkde() elif self.environ.getosfamily() == 'darwin': if not self.setosx(): success = False return success def setgnome(self): ''' @author: dwalker @return: bool - success ''' debug = "" if self.environ.geteuid() != 0: debug = "Unable to set gnome conditions in unit " + \ "test because user is not root." success = True if os.path.exists('/etc/dconf/db/local.d'): if os.path.exists(self.gnomesettingpath): if not os.remove(self.gnomesettingpath): success = False debug = "Unable to remove " + self.gnomesettingpath + \ " for unit test preconditions\n" self.logger.log(LogPriority.DEBUG, debug) if self.ph.check(self.gconf): get = "/usr/bin/gconftool-2 --direct --config-source " + \ "xml:readwrite:/etc/gconf/gconf.xml.mandatory --get " set = "/usr/bin/gconftool-2 --direct --config-source " + \ "xml:readwrite:/etc/gconf/gconf.xml.mandatory --set " unset = "/usr/bin/gconftool-2 --direct --config-source " + \ "xml/readwrite:/etc/gconf/gconf.xml.mandatory --unset " idletimecmd = get + "/desktop/gnome/session/max_idle_time" if self.cmdhelper.executeCommand(idletimecmd): output = self.cmdhelper.getOutput() if output: try: if int(output[0].strip()) == self.seconds: timeout = int(self.seconds) + 5 idletimecmd = set + "--type integer /desktop/gnome/session/max_idle_time " + \ str(timeout) if not self.cmdhelper.executeCommand(idletimecmd): success = False debug = "Unable to set incorrect timeout value for " + \ "unit test preconditions\n" self.logger.log(LogPriority.DEBUG, debug) except (IndexError): debug = "No output to display timeout value\n" self.logger.log(LogPriority.DEBUG, debug) else: success = False debug = "Unable to obtain the timeout value\n" self.logger.log(LogPriority.DEBUG, debug) idleactcmd = get + "/desktop/gnome/session/max_idle_action" if self.cmdhelper.executeCommand(idleactcmd): output = self.cmdhelper.getOutput() if output: if re.search("forced-logout", output[0]): idleact = unset + "/desktop/gnome/session/max_idle_action" if not self.cmdhelper.executeCommand(idleact): success = False debug = "Unable to unset max_idle_action for " + \ "unit test preconditions\n" self.logger.log(LogPriority.DEBUG, debug) return success def setkde(self): ''' @author: dwalker @return: bool - success ''' success = True debug = "" if self.kdesddm: self.kdecheck = ".config/kdeglobals" self.rcpath = ".config/kscreenlockerrc" self.kdeprops = {"ScreenSaver": {"Timeout": str(self.seconds)}} else: self.kdecheck = ".kde" self.rcpath = ".kde/share/config/kscreensaverrc" self.kdeprops = { "ScreenSaver": { "AutoLogout": "true", "AutoLogoutTimeout": str(self.seconds) } } contents = readFile("/etc/passwd", self.logger) for line in contents: username = "" homepath = "" temp = line.split(":") try: username = temp[0] homepath = temp[5] except (IndexError): continue kdeparent = os.path.join(homepath, self.kdecheck) kdefile = os.path.join(homepath, self.rcpath) if not os.path.exists(kdeparent): continue elif os.path.exists(kdefile): if self.searchFile(kdefile): if not self.messFile(kdefile): success = False debug = "Unable to set incorrect values for kde " + \ "for user " + username + " in " + \ "unit test preconditions\n" self.logger.log(LogPriority.DEBUG, debug) return success def searchFile(self, filehandle): '''temporary method to separate the code to find directives from the rest of the code. Will put back all in one method eventually @author: dwalker @return: bool @param filehandle: string ''' self.editor = "" kvt = "tagconf" intent = "present" tpath = filehandle + ".tmp" conftype = "closedeq" self.editor = KVEditorStonix(self.statechglogger, self.logger, kvt, filehandle, tpath, self.kdeprops, intent, conftype) if not self.editor.report(): return False else: return True def messFile(self, filehandle): success = True self.editor = "" garbagevalue = "" while True: garbagevalue = randint(0, 200) if garbagevalue != self.timeoutci: break kvt = "tagconf" intent = "present" tpath = filehandle + ".tmp" conftype = "closedeq" if self.kdesddm: self.kdecheck = ".config/kdeglobals" self.rcpath = ".config/kscreenlockerrc" self.kdeprops = {"ScreenSaver": {"Timeout": str(garbagevalue)}} else: self.kdecheck = ".kde" self.rcpath = ".kde/share/config/kscreensaverrc" self.kdeprops = { "ScreenSaver": { "AutoLogout": "true", "AutoLogoutTimeout": str(garbagevalue) } } self.editor = KVEditorStonix(self.statechglogger, self.logger, kvt, filehandle, tpath, self.kdeprops, intent, conftype) self.editor.report() if not self.editor.fix(): success = False elif not self.editor.commit(): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success
class MacOSUser(ManageUser): """ Class to manage users on Mac OS. @method findUniqueUid @method setUserShell @method setUserComment @method setUserUid @method setUserPriGid @method setUserHomeDir @method addUserToGroup @method rmUserFromGroup @method setUserPassword @method setUserLoginKeychainPassword @method createHomeDirectory @method rmUser @method rmUserHome @author: Roy Nielsen """ def __init__(self, userName="", userShell="/bin/bash", userComment="", userUid=1000, userPriGid=20, userHomeDir="/tmp", logger=False): super(MacOSUser, self).__init__(userName, userShell, userComment, userUid, userPriGid, userHomeDir, logger) self.module_version = '20160225.125554.540679' self.dscl = "/usr/bin/dscl" self.cmdh = CommandHelper(self.logger) #---------------------------------------------------------------------- def createStandardUser(self, userName, password): """ Creates a user that has the "next" uid in line to be used, then puts in in a group of the same id. Uses /bin/bash as the standard shell. The userComment is left empty. Primary use is managing a user during test automation, when requiring a "user" context. It does not set a login keychain password as that is created on first login to the GUI. @author: Roy Nielsen """ self.createBasicUser(userName) newUserID = self.findUniqueUid() newUserGID = newUserID self.setUserUid(userName, newUserID) self.setUserPriGid(userName, newUserID) self.setUserHomeDir(userName) self.setUserShell(userName, "/bin/bash") self.setUserPassword(userName, password) ##### # Don't need to set the user login keychain password as it should be # created on first login. #---------------------------------------------------------------------- def setDscl(self, directory=".", action="", object="", property="", value=""): """ Using dscl to set a value in a directory... @author: Roy Nielsen """ success = False reterr = "" if directory and action and object and property and value: cmd = [self.dscl, directory, action, object, property, value] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise DsclError("Error trying to set a value with dscl (" + \ str(reterr).strip() + ")") return success def getDscl(self, directory="", action="", dirobj="", property=""): """ Using dscl to retrieve a value from the directory @author: Roy Nielsen """ success = False reterr = "" retval = "" ##### # FIRST VALIDATE INPUT!! if isinstance(directory, basestring) and re.match("^[/\.][A-Za-z0-9/]*", directory): success = True else: success = False if isinstance(action, basestring) and re.match("^[-]*[a-z]+", action) and success: success = True else: success = False if isinstance(dirobj, basestring) and re.match("^[A-Za-z0=9/]+", dirobj) and success: success = True else: success = False if isinstance(property, basestring) and re.match("^[A-Za-z0-9]+", property) and success: success = True else: success = False ##### # Now do the directory lookup. if success: cmd = [self.dscl, directory, action, object, property] self.cmdh.executeCommand(cmd) retval = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if reterr: raise DsclError("Error trying to get a value with dscl (" + \ str(reterr).strip() + ")") return ("\n").join(retval) def findUniqueUid(self): """ We need to make sure to find an unused uid (unique ID) for the user, $ dscl . -list /Users UniqueID will list all the existing users, an unused number above 500 is good. @author: Roy Nielsen """ success = False maxUserID = 0 newUserID = 0 userList = self.getDscl(".", "-list", "/Users", "UniqueID") ##### # Sort the list, add one to the highest value and return that # value for user in str(userList).split("\n"): if int(user.split()[1]) > maxUserID: maxUserID = int(user.split()[1]) newUserID = str(int(maxUserID + 1)) return newUserID #---------------------------------------------------------------------- def uidTaken(self, uid): """ See if the UID requested has been taken. Only approve uid's over 1k $ dscl . -list /Users UniqueID @author: Roy Nielsen """ uidList = [] success = False userList = self.getDscl(".", "-list", "/Users", "UniqueID") ##### # Sort the list, add one to the highest value and return that # value for user in str(userList).split("\n"): uidList.append(str(user.split()[1])) if str(uid) in uidList: success = True return success #---------------------------------------------------------------------- def createBasicUser(self, userName=""): """ Create a username with just a moniker. Allow the system to take care of the rest. Only allow usernames with letters and numbers. On the MacOS platform, all other steps must also be done. @author: Roy Nielsen """ success = False reterr = "" if isinstance(userName, basestring)\ and re.match("^[A-Za-z][A-Za-z0-9]*$", userName): cmd = [self.dscl, ".", "-create", "/Users/" + str(userName)] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise DsclError("Error trying to set a value with dscl (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def setUserShell(self, user="", shell=""): """ dscl . -create /Users/luser UserShell /bin/bash @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and self.isSaneUserShell(shell): isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "UserShell", str(shell)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserComment(self, user="", comment=""): """ dscl . -create /Users/luser RealName "Real A. Name" @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and comment: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "RealName", str(comment)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserUid(self, user="", uid=""): """ dscl . -create /Users/luser UniqueID "503" @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and uid: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "UniqueID", str(uid)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserPriGid(self, user="", priGid=""): """ dscl . -create /Users/luser PrimaryGroupID 20 @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and priGid: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "PrimaryGroupID", str(priGid)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserHomeDir(self, user="", userHome=""): """ Create a "local" home directory dscl . -create /Users/luser NFSHomeDirectory /Users/luser better yet: createhomedir -l -u <username> @author: Roy Nielsen """ success = False ##### # Creating a non-standard userHome is not currently permitted #if self.saneUserName(user) and self.saneUserHomeDir(userHome): if self.isSaneUserName(user): isSetDSCL = self.setDscl(".", "-create", "/Users/" + str(user), "NFSHomeDirectory", str("/Users/" + str(user))) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def createHomeDirectory(self, user=""): """ createhomedir -c -u luser This should use the system "User Template" for standard system user settings. @author: Roy Nielsen """ success = False reterr = "" if user: cmd = ["/usr/sbin/createhomedir", "-c", " -u", + str(user)] self.cmdh.executeCommand(cmd) self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise CreateHomeDirError("Error trying to create user home (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def addUserToGroup(self, user="", group=""): """ dscl . -append /Groups/admin GroupMembership luser @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and self.isSaneGroupName(group): isSetDSCL = self.setDscl(".", "-append", "/Groups/" + str(group), "GroupMembership", str(user)) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def rmUserFromGroup(self, user="", group=""): """ """ success = False if self.isSaneUserName(user) and self.isSaneGroupName(group): isSetDSCL = self.setDscl(".", "-delete", "/Groups/" + str(group), "GroupMembership", str(user)) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def setUserPassword(self, user="", password=""): """ dscl . -passwd /Users/luser password @author: Roy Nielsen """ success = False if self.isSaneUserName(user) and isinstance(password, basestring): isSetDSCL = self.setDscl("."", -passwd", "/Users/" + str(user), password) if not isSetDSCL: success = False else: success = True return success #---------------------------------------------------------------------- def setUserLoginKeychainPassword(self, user="", password=""): """ Use the "security" command to set the login keychain. If it has not been created, create the login keychain. Needs research.. Not sure if a sudo'd admin can use the security command to change another user's keychain password... possibly: security set-keychain-password -o oldpassword -p newpassword file.keychain where file.keychain is the default login.keychain of another user? @author: Roy Nielsen """ pass """ self.sec = "/usr/bin/security" success = False keychainpath = "" if self.isSaneUserName(user) and isinstance(password, basestring): pass ##### # Input validation ##### # Check if login keychain exists ##### # if it does not exist, create it if not os.path.exists(keychainpath): cmd = ["Create Keychain Command Here"] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: self.logger.log(lp.INFO, "Unsuccessful attempt to create the " + \ "keychain...(" + str(reterr) + ")") ##### # else set the login keychain password pass """ #---------------------------------------------------------------------- def rmUser(self, user=""): """ dscl . delete /Users/<user> @author: Roy Nielsen """ success = False if self.isSaneUserName(user): cmd = [self.dscl, ".", "-delete", "/Users/" + str(user)] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise Exception("Error trying to remove a user (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def rmUserHome(self, user=""): """ Remove the user home... right now only default location, but should look up the user home in the directory service and remove that specifically. @author: Roy Nielsen """ success = False if self.isSaneUserName(user): ##### # # ***** WARNING WILL ROBINSON ***** # # Please refactor to do a lookup of the user in the directory # service, and use the home directory specified there.. # try: shutil.rmtree("/Users/" + str(user)) except IOError or OSError, err: self.logger.log(lp.INFO, "Exception trying to remove user home...") self.logger.log(lp.INFO, "Exception: " + str(err)) raise err else: success = True return success
class zzzTestRuleConfigurePasswordPolicy(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = ConfigurePasswordPolicy(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): '''@author: dwalker @note: This unit test will install two incorrect profiles on purpose to force system non-compliancy ''' success = True goodprofiles = {} pwprofile = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]))) + \ "/src/stonix_resources/files/stonix4macPasscodeProfileFor" + \ "OSXElCapitan10.11.mobileconfig" secprofile = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]))) + \ "/src/stonix_resources/files/stonix4macSecurity&Privacy" + \ "ForOSXElcapitan10.11.mobileconfig" pwprofiledict = { "com.apple.mobiledevice.passwordpolicy": { "allowSimple": ["1", "bool"], "forcePIN": ["1", "bool"], "maxFailedAttempts": ["5", "int", "less"], "maxPINAgeInDays": ["180", "int", "more"], "minComplexChars": ["1", "int", "more"], "minLength": ["8", "int", "more"], "minutesUntilFailedLoginReset": ["15", "int", "more"], "pinHistory": ["5", "int", "more"], "requireAlphanumeric": ["1", "bool"] } } spprofiledict = { "com.apple.screensaver": "", "com.apple.loginwindow": "", "com.apple.systempolicy.managed": "", "com.apple.SubmitDiagInfo": "", "com.apple.preference.security": "", "com.apple.MCX": "", "com.apple.applicationaccess": "", "com.apple.systempolicy.control": "" } self.rule.pwprofile = pwprofile self.rule.secprofile = secprofile goodprofiles[pwprofile] = pwprofiledict goodprofiles[secprofile] = spprofiledict cmd = ["/usr/sbin/system_profiler", "SPConfigurationProfileDataType"] if self.ch.executeCommand(cmd): output = self.ch.getOutput() if output: for item, values in list(goodprofiles.items()): self.editor = KVEditorStonix(self.statechglogger, self.logdispatch, "profiles", "", "", values, "", "", output) if self.editor.report(): cmd = ["/usr/bin/profiles", "-R", "-F", item] if not self.ch.executeCommand(cmd): success = False else: cmd = [ "/usr/bin/profiles", "-I", "-F,", item + "fake" ] if not self.ch.executeCommand(cmd): success = False else: success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleEnableKernelAuditing(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = EnableKernelAuditing(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) def tearDown(self): # restore backups of original files, made before testing # if self.environ.getosfamily() == 'darwin': # auditcontrolbak = '/etc/security/audit_control.stonixbak' # audituserbak = '/etc/security/audit_user.stonixbak' # if os.path.exists(auditcontrolbak): # os.rename(auditcontrolbak, '/etc/security/audit_control') # if os.path.exists(audituserbak): # os.rename(audituserbak, '/etc/security/audit_user') # else: # auditdbaks =['/etc/audit/auditd.conf.stonixbak', '/etc/auditd.conf.stonixbak'] # auditrulesbaks = ['/etc/audit/audit.rules.stonixbak', '/etc/audit/rules.d/audit.rules.stonixbak'] # for bak in auditdbaks: # if os.path.exists(bak): # os.rename(bak, bak[:-10]) # for bak in auditrulesbaks: # if os.path.exists(bak): # os.rename(bak, bak[:-10]) pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): ''' Configure system for the unit test @param self: essential if you override this definition @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' success = True # # # make backups of any original files, before testing # if self.environ.getosfamily() == 'darwin': # if os.path.exists('/etc/security/audit_control'): # os.rename('/etc/security/audit_control', '/etc/security/audit_control.stonixbak') # if os.path.exists('/etc/security/audit_user'): # os.rename('/etc/security/audit_user', '/etc/security/audit_user.stonixbak') # else: # auditdpaths = ['/etc/audit/auditd.conf', '/etc/auditd.conf'] # for path in auditdpaths: # if os.path.exists(path): # os.rename(path, path + '.stonixbak') # if os.path.exists('/etc/audisp/audispd.conf'): # os.rename('/etc/audisp/audispd.conf', '/etc/audisp/audispd.conf.stonixbak') # auditruleslocs = ['/etc/audit/audit.rules', '/etc/audit/rules.d/audit.rules'] # for loc in auditruleslocs: # if os.path.exists(loc): # os.rename(loc, loc + '.stonixbak') return success def test_freqci_in_range(self): ''' test if the frequency ci value is within range @author: Breen Malmberg ''' allowable_freq_range = range(1,100) self.assertTrue(self.rule.freqci.getcurrvalue() in allowable_freq_range) def test_flushtype_valid(self): ''' test if the flush type ci value is a valid flush type @author: Breen Malmberg ''' allowable_flush_types = ['data', 'incremental', 'sync'] self.assertTrue(self.rule.flushtypeci.getcurrvalue() in allowable_flush_types) def test_get_system_arch(self): ''' test the command to get the system arch @author: Breen Malmberg ''' found = False self.ch.executeCommand('/usr/bin/uname -m') self.assertEqual(0, self.ch.getReturnCode()) outputlines = self.ch.getOutput() self.assertFalse(outputlines == '') for line in outputlines: if re.search('^x86\_64', line): found = True for line in outputlines: if re.search('^x86', line): found = True self.assertEqual(found, True) def test_get_suid_files(self): ''' test the command to find suid files @author: Breen Malmberg ''' self.ch.executeCommand('/usr/bin/find / -xdev -type f -perm -4000 -o -type f -perm -2000') self.assertEqual(0, self.ch.getReturnCode()) def test_release_file_exists(self): ''' does at least one of the release file paths that the code relies on exist? linux-only @author: Breen Malmberg ''' if self.environ.getosfamily() == 'darwin': return True found = False releasefilelocs = ['/etc/os-release', '/etc/redhat-release'] for loc in releasefilelocs: if os.path.exists(loc): found = True self.assertEqual(found, True) def test_grub_cfg_file_exists(self): ''' does at least one of the grub config file paths that the code relies on exist? linux-only @author: Breen Malmberg ''' if self.environ.getosfamily() == 'darwin': return True found = False grubcfglocs = ['/boot/grub/grub.conf', '/etc/default/grub'] for loc in grubcfglocs: if os.path.exists(loc): found = True self.assertEqual(found, True) def checkReportForRule(self, pCompliance, pRuleSuccess): ''' check on whether report was correct @param self: essential if you override this definition @param pCompliance: the self.iscompliant value of rule @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \ str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): ''' check on whether fix was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): ''' check on whether undo was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success
class MacOSUser(ManageUser): '''Class to manage users on Mac OS. @method findUniqueUid @method setUserShell @method setUserComment @method setUserUid @method setUserPriGid @method setUserHomeDir @method addUserToGroup @method rmUserFromGroup @method setUserPassword @method setUserLoginKeychainPassword @method createHomeDirectory @method rmUser @method rmUserHome @author: Roy Nielsen ''' def __init__(self, userName="", userShell="/bin/bash", userComment="", userUid=1000, userPriGid=20, userHomeDir="/tmp", logger=False): super(MacOSUser, self).__init__(userName, userShell, userComment, userUid, userPriGid, userHomeDir, logger) self.module_version = '20160225.125554.540679' self.dscl = "/usr/bin/dscl" self.cmdh = CommandHelper(self.logger) #---------------------------------------------------------------------- def createStandardUser(self, userName, password): '''Creates a user that has the "next" uid in line to be used, then puts in in a group of the same id. Uses /bin/bash as the standard shell. The userComment is left empty. Primary use is managing a user during test automation, when requiring a "user" context. It does not set a login keychain password as that is created on first login to the GUI. @author: Roy Nielsen :param userName: :param password: ''' self.createBasicUser(userName) newUserID = self.findUniqueUid() newUserGID = newUserID self.setUserUid(userName, newUserID) self.setUserPriGid(userName, newUserID) self.setUserHomeDir(userName) self.setUserShell(userName, "/bin/bash") self.setUserPassword(userName, password) ##### # Don't need to set the user login keychain password as it should be # created on first login. #---------------------------------------------------------------------- def setDscl(self, directory=".", action="", object="", property="", value=""): '''Using dscl to set a value in a directory... @author: Roy Nielsen :param directory: (Default value = ".") :param action: (Default value = "") :param object: (Default value = "") :param property: (Default value = "") :param value: (Default value = "") ''' success = False reterr = "" if directory and action and object and property and value: cmd = [self.dscl, directory, action, object, property, value] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise DsclError("Error trying to set a value with dscl (" + \ str(reterr).strip() + ")") return success def getDscl(self, directory="", action="", dirobj="", property=""): '''Using dscl to retrieve a value from the directory @author: Roy Nielsen :param directory: (Default value = "") :param action: (Default value = "") :param dirobj: (Default value = "") :param property: (Default value = "") ''' success = False reterr = "" retval = "" ##### # FIRST VALIDATE INPUT!! if isinstance(directory, str) and re.match("^[/\.][A-Za-z0-9/]*", directory): success = True else: success = False if isinstance(action, str) and re.match("^[-]*[a-z]+", action) and success: success = True else: success = False if isinstance(dirobj, str) and re.match("^[A-Za-z0=9/]+", dirobj) and success: success = True else: success = False if isinstance(property, str) and re.match("^[A-Za-z0-9]+", property) and success: success = True else: success = False ##### # Now do the directory lookup. if success: cmd = [self.dscl, directory, action, object, property] self.cmdh.executeCommand(cmd) retval = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if reterr: raise DsclError("Error trying to get a value with dscl (" + \ str(reterr).strip() + ")") return ("\n").join(retval) def findUniqueUid(self): '''We need to make sure to find an unused uid (unique ID) for the user, $ dscl . -list /Users UniqueID will list all the existing users, an unused number above 500 is good. @author: Roy Nielsen ''' success = False maxUserID = 0 newUserID = 0 userList = self.getDscl(".", "-list", "/Users", "UniqueID") ##### # Sort the list, add one to the highest value and return that # value for user in str(userList).split("\n"): if int(user.split()[1]) > maxUserID: maxUserID = int(user.split()[1]) newUserID = str(int(maxUserID + 1)) return newUserID #---------------------------------------------------------------------- def uidTaken(self, uid): '''See if the UID requested has been taken. Only approve uid's over 1k $ dscl . -list /Users UniqueID @author: Roy Nielsen :param uid: ''' uidList = [] success = False userList = self.getDscl(".", "-list", "/Users", "UniqueID") ##### # Sort the list, add one to the highest value and return that # value for user in str(userList).split("\n"): uidList.append(str(user.split()[1])) if str(uid) in uidList: success = True return success #---------------------------------------------------------------------- def createBasicUser(self, userName=""): '''Create a username with just a moniker. Allow the system to take care of the rest. Only allow usernames with letters and numbers. On the MacOS platform, all other steps must also be done. @author: Roy Nielsen :param userName: (Default value = "") ''' success = False reterr = "" if isinstance(userName, str)\ and re.match("^[A-Za-z][A-Za-z0-9]*$", userName): cmd = [self.dscl, ".", "-create", "/Users/" + str(userName)] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise DsclError("Error trying to set a value with dscl (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def setUserShell(self, user="", shell=""): '''dscl . -create /Users/luser UserShell /bin/bash @author: Roy Nielsen :param user: (Default value = "") :param shell: (Default value = "") ''' success = False if self.isSaneUserName(user) and self.isSaneUserShell(shell): isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "UserShell", str(shell)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserComment(self, user="", comment=""): '''dscl . -create /Users/luser RealName "Real A. Name" @author: Roy Nielsen :param user: (Default value = "") :param comment: (Default value = "") ''' success = False if self.isSaneUserName(user) and comment: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "RealName", str(comment)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserUid(self, user="", uid=""): '''dscl . -create /Users/luser UniqueID "503" @author: Roy Nielsen :param user: (Default value = "") :param uid: (Default value = "") ''' success = False if self.isSaneUserName(user) and uid: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "UniqueID", str(uid)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserPriGid(self, user="", priGid=""): '''dscl . -create /Users/luser PrimaryGroupID 20 @author: Roy Nielsen :param user: (Default value = "") :param priGid: (Default value = "") ''' success = False if self.isSaneUserName(user) and priGid: isSetDSL = self.setDscl(".", "-create", "/Users/" + str(user), "PrimaryGroupID", str(priGid)) if isSetDSL: success = True return success #---------------------------------------------------------------------- def setUserHomeDir(self, user="", userHome=""): '''Create a "local" home directory dscl . -create /Users/luser NFSHomeDirectory /Users/luser better yet: createhomedir -l -u <username> @author: Roy Nielsen :param user: (Default value = "") :param userHome: (Default value = "") ''' success = False ##### # Creating a non-standard userHome is not currently permitted #if self.saneUserName(user) and self.saneUserHomeDir(userHome): if self.isSaneUserName(user): isSetDSCL = self.setDscl(".", "-create", "/Users/" + str(user), "NFSHomeDirectory", str("/Users/" + str(user))) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def createHomeDirectory(self, user=""): '''createhomedir -c -u luser This should use the system "User Template" for standard system user settings. @author: Roy Nielsen :param user: (Default value = "") ''' success = False reterr = "" if user: cmd = ["/usr/sbin/createhomedir", "-c", " -u", +str(user)] self.cmdh.executeCommand(cmd) self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise CreateHomeDirError("Error trying to create user home (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def addUserToGroup(self, user="", group=""): '''dscl . -append /Groups/admin GroupMembership luser @author: Roy Nielsen :param user: (Default value = "") :param group: (Default value = "") ''' success = False if self.isSaneUserName(user) and self.isSaneGroupName(group): isSetDSCL = self.setDscl(".", "-append", "/Groups/" + str(group), "GroupMembership", str(user)) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def rmUserFromGroup(self, user="", group=""): ''' :param user: (Default value = "") :param group: (Default value = "") ''' success = False if self.isSaneUserName(user) and self.isSaneGroupName(group): isSetDSCL = self.setDscl(".", "-delete", "/Groups/" + str(group), "GroupMembership", str(user)) if isSetDSCL: success = True return success #---------------------------------------------------------------------- def setUserPassword(self, user="", password=""): '''dscl . -passwd /Users/luser password @author: Roy Nielsen :param user: (Default value = "") :param password: (Default value = "") ''' success = False if self.isSaneUserName(user) and isinstance(password, str): isSetDSCL = self.setDscl("." ", -passwd", "/Users/" + str(user), password) if not isSetDSCL: success = False else: success = True return success #---------------------------------------------------------------------- def setUserLoginKeychainPassword(self, user="", password=""): '''Use the "security" command to set the login keychain. If it has not been created, create the login keychain. Needs research.. Not sure if a sudo'd admin can use the security command to change another user's keychain password... possibly: security set-keychain-password -o oldpassword -p newpassword file.keychain where file.keychain is the default login.keychain of another user? @author: Roy Nielsen :param user: (Default value = "") :param password: (Default value = "") ''' pass """ self.sec = "/usr/bin/security" success = False keychainpath = "" if self.isSaneUserName(user) and isinstance(password, str): pass ##### # Input validation ##### # Check if login keychain exists ##### # if it does not exist, create it if not os.path.exists(keychainpath): cmd = ["Create Keychain Command Here"] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: self.logger.log(lp.INFO, "Unsuccessful attempt to create the " + \ "keychain...(" + str(reterr) + ")") ##### # else set the login keychain password pass """ #---------------------------------------------------------------------- def rmUser(self, user=""): '''dscl . delete /Users/<user> @author: Roy Nielsen :param user: (Default value = "") ''' success = False if self.isSaneUserName(user): cmd = [self.dscl, ".", "-delete", "/Users/" + str(user)] self.cmdh.executeCommand(cmd) output = self.cmdh.getOutput() reterr = self.cmdh.getErrorString() if not reterr: success = True else: raise Exception("Error trying to remove a user (" + \ str(reterr).strip() + ")") return success #---------------------------------------------------------------------- def rmUserHome(self, user=""): '''Remove the user home... right now only default location, but should look up the user home in the directory service and remove that specifically. @author: Roy Nielsen :param user: (Default value = "") ''' success = False if self.isSaneUserName(user): ##### # # ***** WARNING WILL ROBINSON ***** # # Please refactor to do a lookup of the user in the directory # service, and use the home directory specified there.. # try: shutil.rmtree("/Users/" + str(user)) except IOError or OSError as err: self.logger.log(lp.INFO, "Exception trying to remove user home...") self.logger.log(lp.INFO, "Exception: " + str(err)) raise err else: success = True return success #---------------------------------------------------------------------- def validateUser(self, userName=False, userShell=False, userComment=False, userUid=False, userPriGid=False, userHomeDir=False): '''Future functionality... validate that the passed in parameters to the class instanciation match. @author: :param userName: (Default value = False) :param userShell: (Default value = False) :param userComment: (Default value = False) :param userUid: (Default value = False) :param userPriGid: (Default value = False) :param userHomeDir: (Default value = False) ''' sane = False ##### # Look up all user attributes and check that they are accurate. # Only check the "SANE" parameters passed in. if self.isSaneUserName(userName): self.userName = userName sane = True else: raise BadUserInfoError("Need a valid user name...") if self.isSaneUserShell(userShell) and sane: self.userShell = userShell elif not userShell: pass else: sane = False if self.isSaneUserComment(userComment) and sane: self.userComment = userComment elif not userComment: pass else: sane = False if self.isSaneUserUid(str(userUid)) and sane: self.userUid = self.userUid elif not userUid: pass else: sane = False if self.isSaneUserPriGid(str(userPriGid)) and sane: self.userUid = userUid elif not userPriGid: pass else: sane = False if self.isSaneUserHomeDir(userHomeDir) and sane: self.userHomeDir = userHomeDir elif not userHomeDir: pass else: sane = False return sane #---------------------------------------------------------------------- def getUser(self, userName=""): ''' :param userName: (Default value = "") ''' userInfo = False if self.isSaneUserName(userName): output = self.getDscl(".", "read", "/Users/" + str(userName), "RecordName") try: userInfo = output.split()[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userInfo #---------------------------------------------------------------------- def getUserShell(self, userName=""): ''' :param userName: (Default value = "") ''' userShell = False if self.isSaneUserName(userName): output = self.getDscl(".", "read", "/Users/" + str(userName), "UserShell") try: userShell = output.split()[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userShell #---------------------------------------------------------------------- def getUserComment(self, userName=""): ''' :param userName: (Default value = "") ''' userComment = False if self.isSaneUserName(userName): ##### # Need to process the output to get the right information due to a # spurrious "\n" in the output output = self.getDscl(".", "read", "/Users/" + str(userName), "RealName") try: userComment = output[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userComment #---------------------------------------------------------------------- def getUserUid(self, userName=""): ''' :param userName: (Default value = "") ''' userUid = False if self.isSaneUserName(userName): output = self.getDscl(".", "read", "/Users/" + str(userName), "UniqueID") ##### # Process to get out the right information.... try: userUid = output.split()[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userUid #---------------------------------------------------------------------- def getUserPriGid(self, userName=""): ''' :param userName: (Default value = "") ''' userPriGid = False if self.isSaneUserName(userName): output = self.getDscl(".", "read", "/Users/" + str(userName), "PrimaryGroupID") ##### # Process to get out the right information.... try: userPriGid = output.split()[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userPriGid #---------------------------------------------------------------------- def getUserHomeDir(self, userName=""): ''' :param userName: (Default value = "") ''' userHomeDir = False if self.isSaneUserName(userName): output = self.getDscl(".", "read", "/Users/" + str(userName), "NFSHomeDirectory") ##### # Process to get out the right information.... try: userHomeDir = output.split()[1] except (KeyError, IndexError) as err: self.logger.log(lp.INFO, "Error attempting to find user" + \ str(userName) + " in the " + \ "directory service.") else: raise BadUserInfoError("Need a valid user name...") return userHomeDir #---------------------------------------------------------------------- def isUserInstalled(self, user=""): '''Check if the user "user" is installed @author Roy Nielsen :param user: (Default value = "") ''' success = False if self.isSaneUserName(user): cmd = [self.dscl, ".", "-read", "/Users/" + str(user)] self.runWith.setCommand(cmd) self.runWith.communicate() retval, reterr, retcode = self.runWith.getNlogReturns() if not reterr: success = True return success #---------------------------------------------------------------------- def isUserInGroup(self, userName="", groupName=""): '''Check if this user is in this group @author: Roy Nielsen :param userName: (Default value = "") :param groupName: (Default value = "") ''' success = False if self.isSaneUserName(userName) and self.isSaneGroupName(groupName): output = self.getDscl(".", "read", "/Groups/" + groupName, "users") users = output.split()[:-1] if userName in users: success = True return success #---------------------------------------------------------------------- def fixUserHome(self, userName=""): '''Get the user information from the local directory and fix the user ownership and group of the user's home directory to reflect what is in the local directory service. @author: Roy Nielsen :param userName: (Default value = "") ''' success = False if self.isSaneUserName(userName): ##### # Acquire the user data based on the username first. try: userUid = self.getUserUid(userName) userPriGid = self.getUserPriGid(userName) userHomeDir = self.getUserHomeDir(userName) except BadUserInfoError as err: self.logger.log(lp.INFO, "Exception trying to find: \"" + \ str(userName) + "\" user information") self.logger.log(lp.INFO, "err: " + str(err)) else: success = True if success: try: for root, dirs, files in os.walk(userHomeDir): for d in dirs: os.chown(os.path.join(root, d), userUid, userPriGid) for f in files: os.chown(os.path.join(root, d, f), userUid, userPriGid) except: success = False self.logger.log(lp.INFO, "Exception attempting to chown...") raise err else: success = True return success
class zzzTestRuleDisableCamera(RuleTest): def setUp(self): ''' @change: Breen Malmberg - 06102015 - updated self.cmd and paths to work with updated unit test functionality ''' RuleTest.setUp(self) self.rule = DisableCamera(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) self.identifier = "041AD784-F0E2-40F5-9433-08ED6B105DDA" self.rule.camprofile = "/Users/vagrant/stonix/src/stonix_resources/" + \ "files/stonix4macCameraDisablement.mobileconfig" self.rule.ci.updatecurrvalue(True) def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): ''' Configure system for the unit test @param self: essential if you override this definition @return: boolean - If successful True; If failure False @author: ekkehard j. koch @change: Breen Malmberg - 06102015 - changed this method to reflect the new functionality of DisableCamera.py ''' success = True self.detailedresults = "" cmd = ["/usr/bin/profiles", "-P"] if not self.ch.executeCommand(cmd): success = False self.detailedresults += "Unable to run profiles command\n" else: output = self.ch.getOutput() if output: for line in output: if search(escape(self.identifier), line.strip()): cmd = ["/usr/bin/profiles", "-R", "-p", self.identifier] if not self.ch.executeCommand(cmd): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): ''' check on whether report was correct @param self: essential if you override this definition @param pCompliance: the self.iscompliant value of rule @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \ str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): ''' check on whether fix was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): ''' check on whether undo was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleDisableCamera(RuleTest): def setUp(self): '''@change: Breen Malmberg - 06102015 - updated self.cmd and paths to work with updated unit test functionality ''' RuleTest.setUp(self) self.rule = DisableCamera(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) self.identifier = "041AD784-F0E2-40F5-9433-08ED6B105DDA" self.rule.camprofile = "/Users/vagrant/stonix/src/stonix_resources/" + \ "files/stonix4macCameraDisablement.mobileconfig" self.rule.ci.updatecurrvalue(True) def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): '''Configure system for the unit test :param self: essential if you override this definition :returns: boolean - If successful True; If failure False @author: ekkehard j. koch @change: Breen Malmberg - 06102015 - changed this method to reflect the new functionality of DisableCamera.py ''' success = True self.detailedresults = "" cmd = ["/usr/bin/profiles", "-P"] if not self.ch.executeCommand(cmd): success = False self.detailedresults += "Unable to run profiles command\n" else: output = self.ch.getOutput() if output: for line in output: if search(escape(self.identifier), line.strip()): cmd = [ "/usr/bin/profiles", "-R", "-p", self.identifier ] if not self.ch.executeCommand(cmd): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \ str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleSTIGConfigureApplicationRestrictionsPolicy(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = STIGConfigureApplicationRestrictionsPolicy(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) self.identifier = "mil.disa.STIG.Application_Restrictions.alacarte" self.rule.profile = "/Users/vagrant/stonix/src/stonix_resources/files/" + \ "U_Apple_OS_X_10-11_V1R1_STIG_Application_Restrictions_Policy.mobileconfig" def tearDown(self): pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): success = True self.detailedresults = "" cmd = ["/usr/bin/profiles", "-P"] if not self.ch.executeCommand(cmd): success = False self.detailedresults += "Unable to run profiles command\n" else: output = self.ch.getOutput() if output: for line in output: if search("mil\.disa\.STIG\.Application_Restrictions\.alacarte$", line.strip()): cmd = ["/usr/bin/profiles", "-R", "-p", self.identifier] if not self.ch.executeCommand(cmd): success = False return success def checkReportForRule(self, pCompliance, pRuleSuccess): ''' check on whether report was correct @param self: essential if you override this definition @param pCompliance: the self.iscompliant value of rule @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): ''' check on whether fix was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): ''' check on whether undo was correct @param self: essential if you override this definition @param pRuleSuccess: did report run successfully @return: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + str(pRuleSuccess) + ".") success = True return success
class zzzTestRuleEnableKernelAuditing(RuleTest): def setUp(self): RuleTest.setUp(self) self.rule = EnableKernelAuditing(self.config, self.environ, self.logdispatch, self.statechglogger) self.rulename = self.rule.rulename self.rulenumber = self.rule.rulenumber self.ch = CommandHelper(self.logdispatch) def tearDown(self): # restore backups of original files, made before testing # if self.environ.getosfamily() == 'darwin': # auditcontrolbak = '/etc/security/audit_control.stonixbak' # audituserbak = '/etc/security/audit_user.stonixbak' # if os.path.exists(auditcontrolbak): # os.rename(auditcontrolbak, '/etc/security/audit_control') # if os.path.exists(audituserbak): # os.rename(audituserbak, '/etc/security/audit_user') # else: # auditdbaks =['/etc/audit/auditd.conf.stonixbak', '/etc/auditd.conf.stonixbak'] # auditrulesbaks = ['/etc/audit/audit.rules.stonixbak', '/etc/audit/rules.d/audit.rules.stonixbak'] # for bak in auditdbaks: # if os.path.exists(bak): # os.rename(bak, bak[:-10]) # for bak in auditrulesbaks: # if os.path.exists(bak): # os.rename(bak, bak[:-10]) pass def runTest(self): self.simpleRuleTest() def setConditionsForRule(self): '''Configure system for the unit test :param self: essential if you override this definition :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' success = True # # # make backups of any original files, before testing # if self.environ.getosfamily() == 'darwin': # if os.path.exists('/etc/security/audit_control'): # os.rename('/etc/security/audit_control', '/etc/security/audit_control.stonixbak') # if os.path.exists('/etc/security/audit_user'): # os.rename('/etc/security/audit_user', '/etc/security/audit_user.stonixbak') # else: # auditdpaths = ['/etc/audit/auditd.conf', '/etc/auditd.conf'] # for path in auditdpaths: # if os.path.exists(path): # os.rename(path, path + '.stonixbak') # if os.path.exists('/etc/audisp/audispd.conf'): # os.rename('/etc/audisp/audispd.conf', '/etc/audisp/audispd.conf.stonixbak') # auditruleslocs = ['/etc/audit/audit.rules', '/etc/audit/rules.d/audit.rules'] # for loc in auditruleslocs: # if os.path.exists(loc): # os.rename(loc, loc + '.stonixbak') return success def test_freqci_in_range(self): '''test if the frequency ci value is within range @author: Breen Malmberg ''' allowable_freq_range = list(range(1, 100)) self.assertTrue( self.rule.freqci.getcurrvalue() in allowable_freq_range) def test_flushtype_valid(self): '''test if the flush type ci value is a valid flush type @author: Breen Malmberg ''' allowable_flush_types = ['data', 'incremental', 'sync'] self.assertTrue( self.rule.flushtypeci.getcurrvalue() in allowable_flush_types) def test_get_system_arch(self): '''test the command to get the system arch @author: Breen Malmberg ''' found = False self.ch.executeCommand('/usr/bin/uname -m') self.assertEqual(0, self.ch.getReturnCode()) outputlines = self.ch.getOutput() self.assertFalse(outputlines == '') for line in outputlines: if re.search('^x86\_64', line): found = True for line in outputlines: if re.search('^x86', line): found = True self.assertEqual(found, True) def test_get_suid_files(self): '''test the command to find suid files @author: Breen Malmberg ''' self.ch.executeCommand( '/usr/bin/find / -xdev -type f -perm -4000 -o -type f -perm -2000') self.assertEqual(0, self.ch.getReturnCode()) def test_release_file_exists(self): '''does at least one of the release file paths that the code relies on exist? linux-only @author: Breen Malmberg ''' if self.environ.getosfamily() == 'darwin': return True found = False releasefilelocs = ['/etc/os-release', '/etc/redhat-release'] for loc in releasefilelocs: if os.path.exists(loc): found = True self.assertEqual(found, True) def test_grub_cfg_file_exists(self): '''does at least one of the grub config file paths that the code relies on exist? linux-only @author: Breen Malmberg ''' if self.environ.getosfamily() == 'darwin': return True found = False grubcfglocs = ['/boot/grub/grub.conf', '/etc/default/grub'] for loc in grubcfglocs: if os.path.exists(loc): found = True self.assertEqual(found, True) def checkReportForRule(self, pCompliance, pRuleSuccess): '''check on whether report was correct :param self: essential if you override this definition :param pCompliance: the self.iscompliant value of rule :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pCompliance = " + \ str(pCompliance) + ".") self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkFixForRule(self, pRuleSuccess): '''check on whether fix was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success def checkUndoForRule(self, pRuleSuccess): '''check on whether undo was correct :param self: essential if you override this definition :param pRuleSuccess: did report run successfully :returns: boolean - If successful True; If failure False @author: ekkehard j. koch ''' self.logdispatch.log(LogPriority.DEBUG, "pRuleSuccess = " + \ str(pRuleSuccess) + ".") success = True return success