Ejemplo n.º 1
0
class RemoveSoftware(Rule):
    """This class removes any unnecessary software installed on the system"""
    def __init__(self, config, environ, logger, statechglogger):
        """
        Constructor
        """

        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 91
        self.rulename = "RemoveSoftware"
        self.mandatory = True
        self.formatDetailedResults("initialize")
        self.sethelptext()
        self.rootrequired = True
        self.guidance = ["NSA 2.3.5.6"]
        self.applicable = {'type': 'white', 'family': ['linux', 'freebsd']}

        # Configuration item instantiation
        datatype1 = "bool"
        key1 = "REMOVESOFTWARE"
        instructions1 = "To disable this rule set the value of REMOVESOFTWARE TO False."
        default1 = False
        self.ci = self.initCi(datatype1, key1, instructions1, default1)

        datatype2 = "list"
        key2 = "PACKAGES"
        instructions2 = "Enter the package(s) that you wish to remove.  By " + \
            "default we already list packages that we recommend for removal."
        default2 = [
            "squid", "telnet-server", "rsh-server", "rsh", "rsh-client",
            "talk", "talk-server", "talkd", "libpam-ccreds", "pam_ccreds",
            "tftp-server", "tftp", "tftpd", "udhcpd", "dhcpd", "dhcp",
            "dhcp-server", "yast2-dhcp-server", "vsftpd", "httpd", "dovecot",
            "dovecot-imapd", "dovecot-pop3d", "snmpd", "net-snmpd", "net-snmp",
            "ipsec-tools", "irda-utils", "slapd", "openldap-servers",
            "openldap2", "bind9", "bind9.i386", "bind", "dnsutils",
            "bind-utils", "redhat-access-insights", "insights-client"
        ]

        self.pkgci = self.initCi(datatype2, key2, instructions2, default2)

    def report(self):
        """
        report whether any of the packages listed in the self.pkgci ci are installed
        return False if any are installed
        return True if none of them are installed

        :returns: self.compliant
        :rtype: bool
        """

        self.detailedresults = ""
        self.compliant = True
        self.ph = Pkghelper(self.logger, self.environ)
        packages = self.pkgci.getcurrvalue()
        self.remove_packages = []

        try:

            if packages:
                for pkg in packages:
                    if self.ph.check(pkg):
                        self.remove_packages.append(pkg)
                        self.detailedresults += pkg + " is installed\n"
                        self.compliant = False

        except Exception:
            self.compliant = False
            self.detailedresults += 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 fix(self):
        """
        remove all software packages listed in the self.pkgci list

        :returns: self.rulesuccess
        :rtype: bool
        """

        self.rulesuccess = True
        self.detailedresults = ""
        self.iditerator = 0
        enabled = self.ci.getcurrvalue()

        try:

            if not enabled:
                self.formatDetailedResults("fix", self.rulesuccess,
                                           self.detailedresults)
                return self.rulesuccess
            elif not self.remove_packages:
                self.formatDetailedResults("fix", self.rulesuccess,
                                           self.detailedresults)
                return self.rulesuccess

            # Clear out event history so only the latest fix is recorded
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            for event in eventlist:
                self.statechglogger.deleteentry(event)

            for pkg in self.remove_packages:
                try:
                    if self.ph.remove(pkg):
                        self.iditerator += 1
                        self.detailedresults += "\nRemoved package: " + str(
                            pkg)
                        myid = iterate(self.iditerator, self.rulenumber)
                        event = {
                            "eventtype": "pkghelper",
                            "pkgname": pkg,
                            "startstate": "installed",
                            "endstate": "removed"
                        }
                        self.statechglogger.recordchgevent(myid, event)
                    else:
                        self.rulesuccess = False
                        self.detailedresults += "\nFailed to remove package: " + str(
                            pkg)
                except Exception:
                    continue

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.rulesuccess = False
            self.detailedresults += 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
Ejemplo n.º 2
0
    def undo(self):
        """
        Undo changes made by this rule. Some rules may not be undone.
        self.rulesuccess will be updated if the rule does not succeed.

        @author D. Kennel & D. Walker
        """
        # pass
        if not self.environ.geteuid() == 0:
            self.detailedresults = "Root access required to revert changes."
            self.formatDetailedResults("undo", None, self.detailedresults)
        try:
            # This must be implemented later once the parameter option or observable
            # pattern for taking control of self.detailedresults refresh is implemented
            # see artf30937 : self.detailedresults through application flow for details
            self.detailedresults = ""
            undosuccessful = True
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            if not eventlist:
                self.formatDetailedResults("undo", None, self.detailedresults)
                self.logdispatch.log(LogPriority.INFO, self.detailedresults)
                return undosuccessful
            #eventlist.reverse()
            for entry in eventlist:
                try:
                    event = self.statechglogger.getchgevent(entry)
                    if event["eventtype"] == "perm":
                        perms = event["startstate"]
                        os.chmod(event["filepath"], perms[2])
                        os.chown(event["filepath"], perms[0], perms[1])

                    elif event["eventtype"] == "conf":
                        self.statechglogger.revertfilechanges(
                            event["filepath"], entry)

                    elif event["eventtype"] == "comm" or \
                         event["eventtype"] == "commandstring":
                        ch = CommandHelper(self.logdispatch)
                        command = event["command"]
                        ch.executeCommand(command)
                        if ch.getReturnCode() != 0:
                            self.detailedresults = "Couldn't run the " + \
                                "command to undo\n"
                            self.logdispatch.log(LogPriority.DEBUG,
                                                 self.detailedresults)

                    elif event["eventtype"] == "creation":
                        try:
                            os.remove(event["filepath"])
                        except OSError as oser:
                            if oser.errno == 21:
                                try:
                                    os.rmdir(event["filepath"])
                                except OSError as oserr:
                                    if oserr.errno == 39:
                                        self.logdispatch.log(
                                            LogPriority.DEBUG,
                                            "Cannot remove file path: " +
                                            str(event["filepath"]) +
                                            " because it is a non-empty directory."
                                        )
                            elif oser.errno == 2:
                                self.logdispatch.log(
                                    LogPriority.DEBUG,
                                    "Cannot remove file path: " +
                                    str(event["filepath"]) +
                                    " because it does not exist.")

                    elif event["eventtype"] == "deletion":
                        self.statechglogger.revertfiledelete(event["filepath"])

                    elif event["eventtype"] == "pkghelper":
                        ph = Pkghelper(self.logdispatch, self.environ)
                        if event["startstate"] == "installed":
                            ph.install(event["pkgname"])
                        elif event["startstate"] == "removed":
                            ph.remove(event["pkgname"])
                        else:
                            self.detailedresults = 'Invalid startstate for ' \
                                + 'eventtype "pkghelper". startstate should ' \
                                + 'either be "installed" or "removed"\n'
                            self.logdispatch.log(LogPriority.ERROR,
                                                 self.detailedresults)

                    elif event["eventtype"] == "servicehelper":
                        sh = ServiceHelper(self.environ, self.logdispatch)
                        if event["startstate"] == "enabled":
                            sh.enableservice(event["servicename"])
                        elif event["startstate"] == "disabled":
                            sh.disableservice(event["servicename"])
                        else:
                            self.detailedresults = 'Invalid startstate for ' \
                                + 'eventtype "servicehelper". startstate ' + \
                                'should either be "enabled" or "disabled"\n'
                            self.logdispatch.log(LogPriority.ERROR,
                                                 self.detailedresults)
                except (IndexError, KeyError):
                    self.detailedresults = "EventID " + entry + " not found"
                    self.logdispatch.log(LogPriority.DEBUG,
                                         self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            undosuccessful = False
            self.detailedresults = traceback.format_exc()
            self.logdispatch.log(
                LogPriority.ERROR,
                [self.rulename + ".undo", self.detailedresults])
        self.formatDetailedResults("undo", undosuccessful,
                                   self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return undosuccessful
Ejemplo n.º 3
0
class DisableWeakAuthentication(Rule):
    '''This rule will remove rsh(server and client) if installed, remove
    pam_rhosts entry from any pam file,


    '''
    def __init__(self, config, environ, logger, statechglogger):
        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 30
        self.rulename = "DisableWeakAuthentication"
        self.mandatory = True
        self.formatDetailedResults("initialize")
        self.guidance = ["NSA 3.2.3.1"]
        self.applicable = {
            'type': 'white',
            'family': ['linux', 'solaris', 'freebsd']
        }

        # Configuration item instantiation
        datatype = 'bool'
        key = 'DISABLEWEAKAUTHENTICATION'
        instructions = "To prevent the disabling of services using weak " + \
                       "authentication set DISABLEWEAKAUTHENTICATION to False."
        default = True
        self.ci = self.initCi(datatype, key, instructions, default)

        self.rsh = ["rshell", "rsh-client", "rsh-server", "rsh", "SUNWrcmdc"]
        self.pams = [
            "/etc/pam.conf", "/etc/pam_ldap.conf", "/etc/pam.conf-winbind"
        ]
        self.incorrects = []
        self.iditerator = 0
        self.sethelptext()

    def report(self):
        '''DisableWeakAuthentication.report() Public method to report on the
        presence of certain r-command packages and contents in pam files.
        @author: dwalker


        :returns: bool - False if the method died during execution

        '''
        self.detailedresults = ""
        try:
            self.helper = Pkghelper(self.logger, self.environ)
            compliant = True
            for item in self.rsh:
                if self.helper.check(item):
                    compliant = False
                    self.detailedresults += item + " is still installed\n"
                    break
            for item in self.pams:
                found = False
                if os.path.exists(item):
                    contents = readFile(item, self.logger)
                    if contents:
                        for line in contents:
                            if re.match('^#', line) or \
                               re.match(r'^\s*$', line):
                                continue
                            elif re.search("pam_rhosts", line):
                                found = True
                                compliant = False
                                self.detailedresults += "pam_rhosts line " + \
                                    "found in " + item + "\n"
                                break
                        if found:
                            self.incorrects.append(item)
                        if not checkPerms(item, [0, 0, 420], self.logger):
                            compliant = False
                            self.detailedresults += "Permissions for " + \
                                item + " are incorrect\n"
            if os.path.exists("/etc/pam.d/"):
                fileItems = glob.glob("/etc/pam.d/*")
                for item in fileItems:
                    found = False
                    if os.path.islink(item) or os.path.isdir(item):
                        continue
                    contents = readFile(item, self.logger)
                    if not contents:
                        continue
                    for line in contents:
                        if re.match('^#', line) or re.match(r'^\s*$', line):
                            continue
                        elif re.search("pam_rhosts", line):
                            found = True
                            compliant = False
                            self.detailedresults += "pam_rhosts line " + \
                                "found in " + item + "\n"
                            break
                    if found:
                        self.incorrects.append(item)
                for item in fileItems:
                    if os.path.islink(item) or os.path.isdir(item):
                        continue
                    if not checkPerms(item, [0, 0, 420], self.logger):
                        compliant = False
                        self.detailedresults += "Permissions for " + \
                            item + " are incorrect\n"
                        break
            if self.incorrects:
                debug = "The following files need to be corrected: " + \
                    str(self.incorrects) + "\n\n"
                self.logger.log(LogPriority.DEBUG, debug)
            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 fix(self):
        '''DisableWeakAuthentication.fix() Public method to fix any issues
        that were found in the report method.
        @author: dwalker


        :returns: bool - False if the method died during execution

        '''
        try:
            self.detailedresults = ""
            if not self.ci.getcurrvalue():
                return
            success = True
            for item in self.rsh:
                if self.helper.check(item):
                    if not self.helper.remove(item):
                        success = False
            if self.incorrects:
                for item in self.incorrects:
                    tempstring = ""
                    contents = readFile(item, self.logger)
                    if not contents:
                        continue
                    for line in contents:
                        if re.match('^#', line) or re.match(r'^\s*$', line):
                            tempstring += line
                        elif re.search("pam_rhosts", line):
                            continue
                        else:
                            tempstring += line
                    if not checkPerms(item, [0, 0, 420], self.logger):
                        if not setPerms(item, [0, 0, 420], self.logger):
                            success = False
                    tmpfile = item + ".tmp"
                    if writeFile(tmpfile, tempstring, self.logger):
                        os.rename(tmpfile, item)
                        os.chown(item, 0, 0)
                        os.chmod(item, 420)
                        resetsecon(item)
                    else:
                        success = False
            for item in self.pams:
                if os.path.exists(item):
                    if not checkPerms(item, [0, 0, 420], self.logger):
                        if not setPerms(item, [0, 0, 420], self.logger):
                            success = False
            if os.path.exists("/etc/pam.d/"):
                fileItems = glob.glob("/etc/pam.d/*")
                for item in fileItems:
                    if not checkPerms(item, [0, 0, 420], self.logger):
                        if not setPerms(item, [0, 0, 420], self.logger):
                            success = False
            return success
        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 undo(self):
        '''There is no undo method for this rule since we don't ever want rsh
        installed or for the r services to be enabled.  Overrides the undo
        inside the rule.py class


        '''
        try:
            info = "no undo available"
            self.logger.log(LogPriority.INFO, info)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
            return False
Ejemplo n.º 4
0
class DisableGUILogon(Rule):

    def __init__(self, config, environ, logger, statechglogger):
        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 105
        self.rulename = "DisableGUILogon"
        self.formatDetailedResults("initialize")
        self.mandatory = False
        self.applicable = {'type': 'white',
                           'family': ['linux']}

        # Configuration item instantiation
        datatype = "bool"
        key = "DISABLEX"
        instructions = "To enable this item, set the value of DISABLEX " + \
            "to True. When enabled, this rule will disable the automatic " + \
            "GUI login, and the system will instead boot to the console " + \
            "(runlevel 3). This will not remove any GUI components, and the " + \
            "GUI can still be started using the \"startx\" command."
        default = False
        self.ci1 = self.initCi(datatype, key, instructions, default)

        datatype = "bool"
        key = "LOCKDOWNX"
        instructions = "To enable this item, set the value of LOCKDOWNX " + \
            "to True. When enabled, this item will help secure X Windows by " + \
            "disabling the X Font Server (xfs) service and disabling X " + \
            "Window System Listening. This item should be enabled if X " + \
            "Windows is disabled but will be occasionally started via " + \
            "startx, unless there is a mission-critical need for xfs or " + \
            "a remote display."
        default = False
        self.ci2 = self.initCi(datatype, key, instructions, default)

        datatype = "bool"
        key = "REMOVEX"
        instructions = "To enable this item, set the value of REMOVEX " + \
            "to True. When enabled, this item will COMPLETELY remove X " + \
            "Windows from the system, and on most platforms will disable " + \
            "any currently running display manager. It is therefore " + \
            "recommended that this rule be run from a console session " + \
            "rather than from the GUI.\nREMOVEX cannot be undone."
        default = False
        self.ci3 = self.initCi(datatype, key, instructions, default)

        self.guidance = ["NSA 3.6.1.1", "NSA 3.6.1.2", "NSA 3.6.1.3",
                         "CCE 4462-8", "CCE 4422-2", "CCE 4448-7",
                         "CCE 4074-1"]
        self.iditerator = 0
        self.ph = Pkghelper(self.logger, self.environ)
        self.ch = CommandHelper(self.logger)
        self.sh = ServiceHelper(self.environ, self.logger)
        self.myos = self.environ.getostype().lower()
        self.sethelptext()

    def report(self):
        '''@author: Eric Ball

        :param self: essential if you override this definition
        :returns: bool - True if system is compliant, False if it isn't

        '''
        try:
            compliant = True
            results = ""

            if os.path.exists("/bin/systemctl"):
                self.initver = "systemd"
                compliant, results = self.reportSystemd()
            elif re.search("debian", self.myos):
                self.initver = "debian"
                compliant, results = self.reportDebian()
            elif re.search("ubuntu", self.myos):
                self.initver = "ubuntu"
                compliant, results = self.reportUbuntu()
            else:
                self.initver = "inittab"
                compliant, results = self.reportInittab()

            # NSA guidance specifies disabling of X Font Server (xfs),
            # however, this guidance seems to be obsolete as of RHEL 6,
            # and does not apply to the Debian family.
            if self.sh.auditService("xfs", _="_"):
                compliant = False
                results += "xfs is currently enabled\n"

            xremoved = True
            self.xservSecure = True
            if re.search("debian|ubuntu", self.myos):
                if self.ph.check("xserver-xorg-core"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            elif re.search("opensuse", self.myos):
                if self.ph.check("xorg-x11-server"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            else:
                if self.ph.check("xorg-x11-server-Xorg"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            # Removing X will take xserverrc with it. If X is not present, we
            # do not need to check for xserverrc
            if not xremoved:
                self.serverrc = "/etc/X11/xinit/xserverrc"
                self.xservSecure = False
                if os.path.exists(self.serverrc):
                    serverrcText = readFile(self.serverrc, self.logger)
                    if re.search("opensuse", self.myos):
                        for line in serverrcText:
                            reSearch = r'exec (/usr/bin/)?X \$dspnum.*\$args'
                            if re.search(reSearch, line):
                                self.xservSecure = True
                                break
                    else:
                        for line in serverrcText:
                            reSearch = r'^exec (/usr/bin/)?X (:0 )?-nolisten tcp ("$@"|.?\$@)'
                            if re.search(reSearch, line):
                                self.xservSecure = True
                                break
                    if not self.xservSecure:
                        compliant = False
                        results += self.serverrc + " does not contain proper " \
                            + "settings to disable X Window System " + \
                            "Listening/remote display\n"
                else:
                    compliant = False
                    results += self.serverrc + " does not exist; X Window " + \
                        "System Listening/remote display has not " + \
                        "been disabled\n"

            self.detailedresults = results
            self.compliant = compliant
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.rulesuccess = False
            self.detailedresults = "\n" + traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
        self.formatDetailedResults("report", self.compliant,
                                   self.detailedresults)
        self.logger.log(LogPriority.INFO, self.detailedresults)
        return self.compliant

    def reportInittab(self):
        compliant = False
        results = ""
        inittab = "/etc/inittab"
        if os.path.exists(inittab):
            initData = readFile(inittab, self.logger)
            for line in initData:
                if line.strip() == "id:3:initdefault:":
                    compliant = True
                    break
        else:
            self.logger.log(LogPriority.ERROR, inittab + " not found, init " +
                            "system unknown")
        if not compliant:
            results = "inittab not set to runlevel 3; GUI logon is enabled\n"
        return compliant, results

    def reportSystemd(self):
        compliant = True
        results = ""
        cmd = ["/bin/systemctl", "get-default"]
        self.ch.executeCommand(cmd)
        defaultTarget = self.ch.getOutputString()
        if not re.search("multi-user.target", defaultTarget):
            compliant = False
            results = "systemd default target is not multi-user.target; " + \
                      "GUI logon is enabled\n"
        return compliant, results

    def reportDebian(self):
        compliant = True
        results = ""
        dmlist = ["gdm", "gdm3", "lightdm", "xdm", "kdm"]
        for dm in dmlist:
            if self.sh.auditService(dm, _="_"):
                compliant = False
                results = dm + \
                    " is still in init folders; GUI logon is enabled\n"
        return compliant, results

    def reportUbuntu(self):
        compliant = True
        results = ""
        ldmover = "/etc/init/lightdm.override"
        grub = "/etc/default/grub"
        if os.path.exists(ldmover):
            lightdmText = readFile(ldmover, self.logger)
            if not re.search("manual", lightdmText[0], re.IGNORECASE):
                compliant = False
                results += ldmover + ' exists, but does not contain text ' + \
                                    '"manual". GUI logon is still enabled\n'
        else:
            compliant = False
            results += ldmover + " does not exist; GUI logon is enabled\n"
        if os.path.exists(grub):
            tmppath = grub + ".tmp"
            data = {"GRUB_CMDLINE_LINUX_DEFAULT": '"quiet"'}
            editor = KVEditorStonix(self.statechglogger, self.logger, "conf",
                                    grub, tmppath, data, "present", "closedeq")
            if not editor.report():
                compliant = False
                results += grub + " does not contain the correct values: " + \
                    str(data)
        else:
            compliant = False
            results += "Cannot find file " + grub
        if not compliant:
            results += "/etc/init does not contain proper override file " + \
                      "for lightdm; GUI logon is enabled\n"
        return compliant, results

    def fix(self):
        '''@author: Eric Ball

        :param self: essential if you override this definition
        :returns: bool - True if fix is successful, False if it isn't

        '''
        try:
            if not self.ci1.getcurrvalue() and not self.ci2.getcurrvalue() \
               and not self.ci3.getcurrvalue():
                return
            success = True
            self.detailedresults = ""
            # Delete past state change records from previous fix
            self.iditerator = 0
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            for event in eventlist:
                self.statechglogger.deleteentry(event)

            # If we are doing DISABLEX or REMOVEX, we want to boot to
            # non-graphical multi-user mode.
            if self.ci1.getcurrvalue() or self.ci3.getcurrvalue():
                success &= self.fixBootMode()

            # Since LOCKDOWNX depends on having X installed, and REMOVEX
            # completely removes X from the system, LOCKDOWNX fix will only be
            # executed if REMOVEX is not.
            if self.ci3.getcurrvalue():
                success &= self.fixRemoveX()
            elif self.ci2.getcurrvalue():
                success &= self.fixLockdownX()

            self.rulesuccess = success
        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("fix", self.rulesuccess,
                                   self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return self.rulesuccess

    def fixBootMode(self):
        success = True
        if self.initver == "systemd":
            cmd = ["/bin/systemctl", "set-default",
                   "multi-user.target"]
            if not self.ch.executeCommand(cmd):
                success = False
                self.detailedresults += '"systemctl set-default ' \
                    + 'multi-user.target" did not succeed\n'
            else:
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                commandstring = "/bin/systemctl set-default " + \
                                "graphical.target"
                event = {"eventtype": "commandstring",
                         "command": commandstring}
                self.statechglogger.recordchgevent(myid, event)

        elif self.initver == "debian":
            dmlist = ["gdm", "gdm3", "lightdm", "xdm", "kdm"]
            for dm in dmlist:
                cmd = ["update-rc.d", "-f", dm, "disable"]
                if not self.ch.executeCommand(cmd):
                    self.detailedresults += "Failed to disable desktop " + \
                        "manager " + dm
                else:
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    event = {"eventtype": "servicehelper",
                             "servicename": dm,
                             "startstate": "enabled",
                             "endstate": "disabled"}
                    self.statechglogger.recordchgevent(myid, event)

        elif self.initver == "ubuntu":
            ldmover = "/etc/init/lightdm.override"
            tmpfile = ldmover + ".tmp"
            created = False
            if not os.path.exists(ldmover):
                createFile(ldmover, self.logger)
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "creation", "filepath": ldmover}
                self.statechglogger.recordchgevent(myid, event)
                created = True
            writeFile(tmpfile, "manual\n", self.logger)
            if not created:
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "conf", "filepath": ldmover}
                self.statechglogger.recordchgevent(myid, event)
                self.statechglogger.recordfilechange(ldmover, tmpfile, myid)
            os.rename(tmpfile, ldmover)
            resetsecon(ldmover)

            grub = "/etc/default/grub"
            if not os.path.exists(grub):
                createFile(grub, self.logger)
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "creation", "filepath": grub}
                self.statechglogger.recordchgevent(myid, event)
            tmppath = grub + ".tmp"
            data = {"GRUB_CMDLINE_LINUX_DEFAULT": '"quiet"'}
            editor = KVEditorStonix(self.statechglogger, self.logger,
                                    "conf", grub, tmppath, data,
                                    "present", "closedeq")
            editor.report()
            if editor.fixables:
                if editor.fix():
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    editor.setEventID(myid)
                    debug = "kveditor fix ran successfully\n"
                    self.logger.log(LogPriority.DEBUG, debug)
                    if editor.commit():
                        debug = "kveditor commit ran successfully\n"
                        self.logger.log(LogPriority.DEBUG, debug)
                    else:
                        error = "kveditor commit did not run " + \
                                "successfully\n"
                        self.logger.log(LogPriority.ERROR, error)
                        success = False
                else:
                    error = "kveditor fix did not run successfully\n"
                    self.logger.log(LogPriority.ERROR, error)
                    success = False
            cmd = "update-grub"
            self.ch.executeCommand(cmd)

        else:
            inittab = "/etc/inittab"
            tmpfile = inittab + ".tmp"
            if os.path.exists(inittab):
                initText = open(inittab, "r").read()
                initre = r"id:\d:initdefault:"
                if re.search(initre, initText):
                    initText = re.sub(initre, "id:3:initdefault:",
                                      initText)
                    writeFile(tmpfile, initText, self.logger)
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    event = {"eventtype": "conf", "filepath": inittab}
                    self.statechglogger.recordchgevent(myid, event)
                    self.statechglogger.recordfilechange(inittab,
                                                         tmpfile, myid)
                    os.rename(tmpfile, inittab)
                    resetsecon(inittab)
                else:
                    initText += "\nid:3:initdefault:\n"
                    writeFile(tmpfile, initText, self.logger)
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    event = {"eventtype": "conf", "filepath": inittab}
                    self.statechglogger.recordchgevent(myid, event)
                    self.statechglogger.recordfilechange(inittab,
                                                         tmpfile, myid)
                    os.rename(tmpfile, inittab)
                    resetsecon(inittab)
            else:
                self.detailedresults += inittab + " not found, no other " + \
                    "init system found. If you are using a supported " + \
                    "Linux OS, please report this as a bug\n"
        return success

    def fixRemoveX(self):
        success = True
        # Due to automatic removal of dependent packages, the full
        # removal of X and related packages cannot be undone
        if re.search("opensuse", self.myos):
            cmd = ["zypper", "-n", "rm", "-u", "xorg-x11*", "kde*",
                   "xinit*"]
            self.ch.executeCommand(cmd)
        elif re.search("debian|ubuntu", self.myos):
            xpkgs = ["unity.*", "xserver-xorg-video-ati",
                     "xserver-xorg-input-synaptics",
                     "xserver-xorg-input-wacom", "xserver-xorg-core",
                     "xserver-xorg", "lightdm.*", "libx11-data"]
            for xpkg in xpkgs:
                self.ph.remove(xpkg)
        elif re.search("fedora", self.myos):
            # Fedora does not use the same group packages as other
            # RHEL-based OSs. Removing this package will remove the X
            # Windows system, just less efficiently than using a group
            self.ph.remove("xorg-x11-server-Xorg")
            self.ph.remove("xorg-x11-xinit*")
        else:
            cmd = ["yum", "groups", "mark", "convert"]
            self.ch.executeCommand(cmd)
            self.ph.remove("xorg-x11-xinit")
            self.ph.remove("xorg-x11-server-Xorg")
            cmd2 = ["yum", "groupremove", "-y", "X Window System"]
            if not self.ch.executeCommand(cmd2):
                success = False
                self.detailedresults += '"yum groupremove -y X Window System" command failed\n'
        return success

    def fixLockdownX(self):
        success = True
        if self.sh.disableService("xfs", _="_"):
            self.iditerator += 1
            myid = iterate(self.iditerator, self.rulenumber)
            event = {"eventtype":   "servicehelper",
                     "servicename": "xfs",
                     "startstate":  "enabled",
                     "endstate":    "disabled"}
            self.statechglogger.recordchgevent(myid, event)
        else:
            success = False
            self.detailedresults += "STONIX was unable to disable the " + \
                "xfs service\n"

        if not self.xservSecure:
            serverrcString = "exec X :0 -nolisten tcp $@"
            if not os.path.exists(self.serverrc):
                createFile(self.serverrc, self.logger)
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "creation",
                         "filepath": self.serverrc}
                self.statechglogger.recordchgevent(myid, event)
                writeFile(self.serverrc, serverrcString, self.logger)
            else:
                open(self.serverrc, "a").write(serverrcString)
        return success
Ejemplo n.º 5
0
    def undo(self):
        """
        Undo changes made by this rule. Some rules may not be undone.
        self.rulesuccess will be updated if the rule does not succeed.

        @author D. Kennel & D. Walker
        """
        # pass
        if not self.environ.geteuid() == 0:
            self.detailedresults = "Root access required to revert changes."
            self.formatDetailedResults("undo", None, self.detailedresults)
        try:
# This must be implemented later once the parameter option or observable
# pattern for taking control of self.detailedresults refresh is implemented
# see artf30937 : self.detailedresults through application flow for details
            self.detailedresults = ""
            undosuccessful = True
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            if not eventlist:
                self.formatDetailedResults("undo", None, self.detailedresults)
                self.logdispatch.log(LogPriority.INFO, self.detailedresults)
                return undosuccessful
            #eventlist.reverse()
            for entry in eventlist:
                try:
                    event = self.statechglogger.getchgevent(entry)
                    if event["eventtype"] == "perm":
                        perms = event["startstate"]
                        os.chmod(event["filepath"], perms[2])
                        os.chown(event["filepath"], perms[0], perms[1])

                    elif event["eventtype"] == "conf":
                        self.statechglogger.revertfilechanges(event["filepath"],
                                                              entry)

                    elif event["eventtype"] == "comm" or \
                         event["eventtype"] == "commandstring":
                        ch = CommandHelper(self.logdispatch)
                        command = event["command"]
                        ch.executeCommand(command)
                        if ch.getReturnCode() != 0:
                            self.detailedresults = "Couldn't run the " + \
                                "command to undo\n"
                            self.logdispatch.log(LogPriority.DEBUG,
                                                 self.detailedresults)

                    elif event["eventtype"] == "creation":
                        try:
                            os.remove(event["filepath"])
                        except OSError as oser:
                            if oser.errno == 21:
                                try:
                                    os.rmdir(event["filepath"])
                                except OSError as oserr:
                                    if oserr.errno == 39:
                                        self.logdispatch.log(LogPriority.DEBUG, "Cannot remove file path: " + str(event["filepath"]) + " because it is a non-empty directory.")
                            elif oser.errno == 2:
                                self.logdispatch.log(LogPriority.DEBUG, "Cannot remove file path: " + str(event["filepath"]) + " because it does not exist.")

                    elif event["eventtype"] == "deletion":
                        self.statechglogger.revertfiledelete(event["filepath"])

                    elif event["eventtype"] == "pkghelper":
                        ph = Pkghelper(self.logdispatch, self.environ)
                        if event["startstate"] == "installed":
                            ph.install(event["pkgname"])
                        elif event["startstate"] == "removed":
                            ph.remove(event["pkgname"])
                        else:
                            self.detailedresults = 'Invalid startstate for ' \
                                + 'eventtype "pkghelper". startstate should ' \
                                + 'either be "installed" or "removed"\n'
                            self.logdispatch.log(LogPriority.ERROR,
                                                 self.detailedresults)

                    elif event["eventtype"] == "servicehelper":
                        sh = ServiceHelper(self.environ, self.logdispatch)
                        if event["startstate"] == "enabled":
                            sh.enableservice(event["servicename"])
                        elif event["startstate"] == "disabled":
                            sh.disableservice(event["servicename"])
                        else:
                            self.detailedresults = 'Invalid startstate for ' \
                                + 'eventtype "servicehelper". startstate ' + \
                                'should either be "enabled" or "disabled"\n'
                            self.logdispatch.log(LogPriority.ERROR,
                                                 self.detailedresults)
                except(IndexError, KeyError):
                    self.detailedresults = "EventID " + entry + " not found"
                    self.logdispatch.log(LogPriority.DEBUG,
                                         self.detailedresults)
        except(KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            undosuccessful = False
            self.detailedresults = traceback.format_exc()
            self.logdispatch.log(LogPriority.ERROR, [self.rulename + ".undo",
                                                     self.detailedresults])
        self.formatDetailedResults("undo", undosuccessful,
                                   self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return undosuccessful
Ejemplo n.º 6
0
class DisableUbuntuDataCollection(Rule):
    def __init__(self, config, environ, logger, statechglogger):
        '''

        :param config:
        :param environ:
        :param logger:
        :param statechglogger:

        '''

        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.environ = environ
        self.rulenumber = 311
        self.rulename = "DisableUbuntuDataCollection"
        self.mandatory = True
        self.rootrequired = True
        self.formatDetailedResults("initialize")
        self.guidance = []
        self.applicable = {'type': 'white', 'os': {'Ubuntu': ['16.04', '+']}}
        self.sethelptext()

        datatype = "bool"
        key = "DISABLEUBUNTUDATACOLLECTION"
        instructions = """To prevent the diabling of data collection from this system, set the value of DISABLEUBUNTUDATACOLLECTION to False."""
        default = True
        self.enabledCI = self.initCi(datatype, key, instructions, default)

    def report(self):
        '''Check for the existence of any of a number of data-collection
        and reporting utilities on the system
        report compliance status as not compliant if any exist
        report compliance status as compliant if none exist


        :returns: self.compliant

        :rtype: bool
@author: Breen Malmberg

        '''

        self.detailedresults = ""
        self.ph = Pkghelper(self.logger, self.environ)
        self.compliant = True

        self.pkgslist = ["popularity-contest", "apport", "ubuntu-report"]
        self.removepkgs = []

        try:

            for pkg in self.pkgslist:
                if self.ph.check(pkg):
                    self.compliant = False
                    self.detailedresults += "\nData collection utility: " + str(
                        pkg) + " is still installed"
                    self.removepkgs.append(pkg)

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.compliant = 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 fix(self):
        '''Remove any data-collection and reporting utilities from the system
        report success status as True if all are removed
        report success status as False if any remain


        :returns: self.rulesuccess

        :rtype: bool
@author: Breen Malmberg

        '''

        self.detailedresults = ""
        self.rulesuccess = True
        self.iditerator = 0

        try:

            if self.enabledCI.getcurrvalue():

                eventlist = self.statechglogger.findrulechanges(
                    self.rulenumber)
                for event in eventlist:
                    self.statechglogger.deleteentry(event)

                for pkg in self.removepkgs:

                    if not self.ph.remove(pkg):
                        self.detailedresults += "\nUnable to remove package: " + str(
                            pkg)
                        self.rulesuccess = False
                    else:
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        comm = self.ph.getRemove() + pkg
                        event = {"eventtype": "commandstring", "command": comm}
                        self.statechglogger.recordchgevent(myid, event)
                        self.logger.log(LogPriority.DEBUG,
                                        "Removing package: " + str(pkg))

            else:
                self.logger.log(LogPriority.DEBUG,
                                "Rule was NOT enabled. Nothing was done.")

        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
Ejemplo n.º 7
0
class SecureMDNS(Rule):
    '''The Avahi daemon implements the DNS Service Discovery and Multicast DNS
    protocols, which provide service and host discovery on a network. It allows
    a system to automatically identify resources on the network, such as
    printers or web servers. This capability is also known as mDNSresponder
    and is a major part of Zeroconf networking. By default, it is enabled.
    This rule makes a number of configuration changes to the avahi service
    in order to secure it.
    @change: 04/16/2014 ekkehard ci and self.setkvdefaultscurrenthost updates


    '''
    def __init__(self, config, environ, logger, statechglogger):
        '''
        Constructor
        '''
        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 135
        self.rulename = 'SecureMDNS'
        self.formatDetailedResults("initialize")
        self.mandatory = True
        self.sethelptext()
        self.rootrequired = True
        self.compliant = False
        self.rulesuccess = True
        self.guidance = [
            'NSA(3.7.2)', 'CCE 4136-8', 'CCE 4409-9', 'CCE 4426-3',
            'CCE 4193-9', 'CCE 4444-6', 'CCE 4352-1', 'CCE 4433-9',
            'CCE 4451-1', 'CCE 4341-4', 'CCE 4358-8', 'CCE-RHEL7-CCE-TBD 2.5.2'
        ]
        self.applicable = {
            'type': 'white',
            'family': ['linux', 'solaris', 'freebsd'],
            'os': {
                'Mac OS X': ['10.15', 'r', '10.15.10']
            }
        }

        # set up command helper object
        self.ch = CommandHelper(self.logger)

        # init helper classes
        self.sh = ServiceHelper(self.environ, self.logger)
        self.serviceTarget = ""

        if self.environ.getostype() == "Mac OS X":
            self.ismac = True
            self.hasSIP = False
            self.plb = "/usr/libexec/PlistBuddy"
            osxversion = str(self.environ.getosver())
            versplit = osxversion.split(".")
            if len(versplit) > 2:
                minorVersion = int(versplit[1])
                releaseVersion = int(versplit[2])
            elif len(versplit) == 2:
                minorVersion = int(versplit[1])
                releaseVersion = 0
            else:
                self.logger.log(LogPriority.ERROR,
                                "Unexpected version string length")
                raise Exception
            if minorVersion == 10 and releaseVersion < 4:
                self.service = "/System/Library/LaunchDaemons/com.apple." + \
                    "discoveryd.plist"
                self.servicename = "com.apple.networking.discoveryd"
                self.parameter = "--no-multicast"
                self.pbr = self.plb + " -c Print " + self.service + \
                    " | grep 'no-multicast'"
                self.pbf = self.plb + ' -c "Add :ProgramArguments: string ' + \
                    self.parameter + '" ' + self.service
            elif minorVersion > 10:
                self.hasSIP = True
                self.service = "/System/Library/LaunchDaemons/" + \
                    "com.apple.mDNSResponder.plist"
                self.servicename = "com.apple.mDNSResponder.reloaded"
                self.parameter = "NoMulticastAdvertisements"
                self.preferences = "/Library/Preferences/" + \
                    "com.apple.mDNSResponder.plist"
                self.pbr = self.plb + " -c Print " + self.preferences + \
                    " | grep 'NoMulticastAdvertisements'"
                self.pbf = "defaults write " + self.preferences + " " + \
                    self.parameter + " -bool YES"
            else:
                self.service = "/System/Library/LaunchDaemons/" + \
                    "com.apple.mDNSResponder.plist"
                if minorVersion >= 10:
                    self.servicename = "com.apple.mDNSResponder.reloaded"
                else:
                    self.servicename = "com.apple.mDNSResponder"
                self.parameter = "-NoMulticastAdvertisements"
                self.pbr = self.plb + " -c Print " + self.service + \
                    " | grep 'NoMulticastAdvertisements'"
                self.pbf = self.plb + ' -c "Add :ProgramArguments: string ' + \
                    self.parameter + '" ' + self.service
        else:
            self.ismac = False
            # init CIs
            datatype = 'bool'
            mdnskey = 'SECUREMDNS'
            avahikey = 'DISABLEAVAHI'
            mdnsinstructions = 'To configure the Avahi server daemon ' + \
                'securely set the value of SECUREMDNS to True and the ' + \
                'value of DISABLEAVAHI to False.'
            avahiinstructions = 'To completely disable the Avahi server ' + \
                'daemon rather than configure it, set the value of ' + \
                'DISABLEAVAHI to True and the value of SECUREMDNS to False.'
            mdnsdefault = False
            avahidefault = True
            self.SecureMDNS = self.initCi(datatype, mdnskey, mdnsinstructions,
                                          mdnsdefault)
            self.DisableAvahi = self.initCi(datatype, avahikey,
                                            avahiinstructions, avahidefault)

            self.configparser = configparser.SafeConfigParser()

            self.confavahidict = {
                'use-ipv6': {
                    'section': 'server',
                    'val': 'no'
                },
                'check-response-ttl': {
                    'section': 'server',
                    'val': 'yes'
                },
                'disallow-other-stacks': {
                    'section': 'server',
                    'val': 'yes'
                },
                'disable-publishing': {
                    'section': 'publish',
                    'val': 'yes'
                },
                'disable-user-service-publishing': {
                    'section': 'publish',
                    'val': 'yes'
                },
                'publish-addresses': {
                    'section': 'publish',
                    'val': 'no'
                },
                'publish-hinfo': {
                    'section': 'publish',
                    'val': 'no'
                },
                'publish-workstation': {
                    'section': 'publish',
                    'val': 'no'
                },
                'publish-domain': {
                    'section': 'publish',
                    'val': 'no'
                }
            }
            self.confoptions = {
                'server': {
                    'use-ipv6': 'no',
                    'check-response-ttl': 'yes',
                    'disallow-other-stacks': 'yes'
                },
                'publish': {
                    'disable-publishing': 'yes',
                    'disable-user-service-publishing': 'yes',
                    'publish-addresses': 'no',
                    'publish-hinfo': 'no',
                    'publish-workstation': 'no',
                    'publish-domain': 'no'
                }
            }
        self.iditerator = 0

    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.detailed results and self.currstate properties are
        updated to reflect the system status. self.rulesuccess will be updated
        if the rule does not succeed.


        :returns: bool
        @author: Breen Malmberg
        @change: dwalker - added conditional call to reportmac()
        @change: Breen Malmberg - 12/05/2017 - removed unnecessary argument
                "serviceTarget" in linux-only call to servicehelper; removed
                assignment of unused local variable serviceTarget to self.servicename
                since servicename is not assigned in the linux code logic path (which
                was resulting in variable referenced before assignment error)

        '''

        try:

            # defaults
            compliant = True
            self.detailedresults = ''
            self.rulesuccess = True

            # if system is a mac, run reportmac
            if self.ismac:
                compliant = self.reportmac()

            # if not mac os x, then run this portion
            else:
                self.editor = None
                # set up package helper object only if not mac os x
                self.pkghelper = Pkghelper(self.logger, self.environ)

                # if the disableavahi CI is set, we want to make sure it is
                # completely disabled
                if self.DisableAvahi.getcurrvalue():
                    self.package = "avahi-daemon"
                    # if avahi-daemon is still running, it is not disabled
                    if self.sh.auditService('avahi-daemon'):
                        compliant = False
                        self.detailedresults += 'DisableAvahi has been ' + \
                            'set to True, but avahi-daemon service is ' + \
                            'currently running.\n'
                    self.numdependencies = 0
                    if self.pkghelper.determineMgr() == 'yum' or \
                       self.pkghelper.determineMgr() == 'dnf':
                        self.package = "avahi"
                        # The following KVEditor for /etc/sysconfig/network is
                        # used to meet the zeroconf requirement in
                        # CCE-RHEL7-CCE-TBD 2.5.2
                        path = "/etc/sysconfig/network"
                        self.path = path
                        if os.path.exists(path):
                            tmppath = path + ".tmp"
                            data = {"NOZEROCONF": "yes"}
                            self.editor = KVEditorStonix(
                                self.statechglogger, self.logger, "conf", path,
                                tmppath, data, "present", "closedeq")
                            if not self.editor.report():
                                self.compliant = False
                                self.detailedresults += path + " does not " + \
                                    "have the correct settings.\n"
                        else:
                            self.compliant = False
                            self.detailedresults += path + " does not exist.\n"

                        self.numdependencies = \
                            self.parseNumDependencies(self.package)
                        if self.numdependencies <= 3:
                            if self.pkghelper.check(self.package):
                                compliant = False
                                self.detailedresults += 'DisableAvahi is ' + \
                                    'set to True, but Avahi is currently ' + \
                                    'installed.\n'
                        else:
                            self.detailedresults += 'Avahi has too many ' + \
                                'dependent packages. Will not attempt to ' + \
                                'remove it.\n'

                    elif self.pkghelper.determineMgr() == "zypper":
                        self.package = "avahi"
                    elif self.pkghelper.check(self.package):
                        compliant = False
                        self.detailedresults += 'DisableAvahi is ' + \
                            'set to True, but Avahi is currently ' + \
                            'installed.\n'

                # otherwise if the securemdns CI is set, we want to make sure
                # it is securely configured
                if self.SecureMDNS.getcurrvalue():

                    # if the config file is found, proceed
                    if os.path.exists('/etc/avahi/avahi-daemon.conf'):

                        kvtype = "tagconf"
                        intent = "present"
                        filepath = '/etc/avahi/avahi-daemon.conf'
                        tmpfilepath = '/etc/avahi/avahi-daemon.conf.stonixtmp'
                        conftype = "closedeq"
                        self.avahiconfeditor = KVEditorStonix(
                            self.statechglogger, self.logger, kvtype, filepath,
                            tmpfilepath, self.confoptions, intent, conftype)
                        self.avahiconfeditor.report()
                        if self.avahiconfeditor.fixables:
                            compliant = False
                            self.detailedresults += "\nThe following configuration options are missing or incorrect in " + str(
                                filepath) + ":\n" + "\n".join(
                                    self.avahiconfeditor.fixables)

                    # if config file not found, check if avahi is installed
                    else:

                        # if not installed, we can't configure anything
                        if not self.pkghelper.check('avahi'):
                            self.detailedresults += 'Avahi Daemon not ' + \
                                'installed. Cannot configure it.\n'
                            compliant = True
                            self.logger.log(LogPriority.DEBUG,
                                            self.detailedresults)

                        # if it is installed, then the config file is missing
                        else:
                            compliant = False
                            self.detailedresults += 'Avahi is installed ' + \
                                'but could not find config file in ' + \
                                'expected location.\n'
                            self.logger.log(LogPriority.DEBUG,
                                            self.detailedresults)

            self.compliant = compliant

        except (IOError):
            self.detailedresults += '\n' + traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
        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 reportmac(self):
        '''check for configuration items needed for mac os x


        :returns: bool
        @author: Breen Malmberg
        @change: dwalker - implemented kveditor defaults

        '''
        try:
            self.detailedresults = ""
            # See if parameter is set
            self.ch.executeCommand(self.pbr)
            resultOutput = self.ch.getOutput()
            if len(resultOutput) >= 1:
                if (resultOutput[0] == ""):
                    commandsuccess = False
                    self.detailedresults += "Parameter: " + str(self.parameter) + \
                        " for service " + self.servicename + " is not set.\n"
                else:
                    commandsuccess = True
                    debug = "Parameter: " + str(self.parameter) + \
                        " for service " + self.servicename + \
                        " is set correctly."
                    self.logger.log(LogPriority.DEBUG, debug)
            else:
                commandsuccess = False
                self.detailedresults += "Parameter: " + str(self.parameter) + \
                    " for service " + self.servicename + " is not set.\n"
            # see if service is running
            if not re.match("^10.11", self.environ.getosver()):
                servicesuccess = self.sh.auditService(
                    self.service, serviceTarget=self.servicename)
            else:
                servicesuccess = self.sh.auditService(
                    self.service, serviceTarget=self.servicename)
            if servicesuccess:
                debug = "Service: " + str(self.service) + ", " + \
                    self.servicename + " audit successful."
                self.logger.log(LogPriority.DEBUG, debug)
            else:
                self.detailedresults += "Service: " + str(self.service) + \
                    ", " + self.servicename + " audit failed.\n"

            if servicesuccess and commandsuccess:
                return True
            else:
                return False
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.compliant = False
            raise
        return self.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.
        
        @author: Breen Malmberg
        @change: dwalker - added statechglogger findrulechanges and deleteentry
        @changed: Breen Malmberg - 12/05/2017 - removed unnecessary servicetarget


        '''

        try:

            self.rulesuccess = True
            self.iditerator = 0
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            for event in eventlist:
                self.statechglogger.deleteentry(event)
            self.detailedresults = ""

            # if this system is a mac, run fixmac()
            if self.ismac:
                self.rulesuccess = self.fixmac()

            # if not mac os x, run this portion
            else:
                # if DisableAvahi CI is enabled, disable the avahi service
                # and remove the package
                if self.DisableAvahi.getcurrvalue():
                    avahi = self.package
                    avahid = 'avahi-daemon'
                    if self.sh.auditService(avahid):
                        debug = "Disabling " + avahid + " service"
                        self.logger.log(LogPriority.DEBUG, debug)
                        self.sh.disableService(avahid)
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        event = {
                            "eventtype": "servicehelper",
                            "servicename": avahid,
                            "startstate": "enabled",
                            "endstate": "disabled"
                        }
                        self.statechglogger.recordchgevent(myid, event)
                    if self.environ.getosfamily() == 'linux' and \
                       self.pkghelper.check(avahi):
                        if self.numdependencies <= 3:
                            self.pkghelper.remove(avahi)
                            self.iditerator += 1
                            myid = iterate(self.iditerator, self.rulenumber)
                            event = {
                                "eventtype": "pkghelper",
                                "pkgname": avahi,
                                "startstate": "installed",
                                "endstate": "removed"
                            }
                            self.statechglogger.recordchgevent(myid, event)
                        else:
                            debug += 'Avahi package has too many dependent ' \
                                + 'packages. Will not attempt to remove.\n'
                            self.logger.log(LogPriority.DEBUG, debug)

                    if self.pkghelper.determineMgr() == 'yum' or \
                       self.pkghelper.determineMgr() == 'dnf':
                        path = self.path
                        if not os.path.exists(path):
                            if createFile(path, self.logger):
                                self.iditerator += 1
                                myid = iterate(self.iditerator,
                                               self.rulenumber)
                                event = {
                                    "eventtype": "creation",
                                    "filepath": path
                                }
                                self.statechglogger.recordchgevent(myid, event)
                            else:
                                self.rulesuccess = False
                                self.detailedresults += "Failed to create " + \
                                    "file: " + path + ".\n"
                        if self.editor is None:
                            tmppath = path + ".tmp"
                            data = {"NOZEROCONF": "yes"}
                            self.editor = KVEditorStonix(
                                self.statechglogger, self.logger, "conf", path,
                                tmppath, data, "present", "closedeq")
                        if not self.editor.report():
                            if self.editor.fix():
                                self.iditerator += 1
                                myid = iterate(self.iditerator,
                                               self.rulenumber)
                                self.editor.setEventID(myid)
                                if not self.editor.commit():
                                    self.rulesuccess = False
                                    self.detailedresults += "Could not " + \
                                        "commit changes to " + path + ".\n"
                            else:
                                self.rulesuccess = False
                                self.detailedresults += "Could not fix " + \
                                    "file " + path + ".\n"

                # if SecureMDNS CI is enabled, configure avahi-daemon.conf
                if self.SecureMDNS.getcurrvalue():
                    # if config file is present, proceed
                    avahiconf = '/etc/avahi/avahi-daemon.conf'
                    if os.path.exists(avahiconf):
                        if self.avahiconfeditor.fixables:
                            self.iditerator += 1
                            myid = iterate(self.iditerator, self.rulenumber)
                            self.avahiconfeditor.setEventID(myid)
                            if not self.avahiconfeditor.fix():
                                self.rulesuccess = False
                                debug = "KVEditor fix for " + avahiconf + \
                                    "failed"
                                self.logger.log(LogPriority.DEBUG, debug)
                            elif not self.avahiconfeditor.commit():
                                self.rulesuccess = False
                                debug = "KVEditor commit for " + avahiconf + \
                                    "failed"
                                self.logger.log(LogPriority.DEBUG, debug)

                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        setPerms(avahiconf, [0, 0, 0o644], self.logger,
                                 self.statechglogger, myid)
                        resetsecon(avahiconf)

                    # if config file is not present and avahi not installed,
                    # then we can't configure it
                    else:
                        if not self.pkghelper.check(avahi):
                            debug = 'Avahi Daemon not installed. ' + \
                                'Cannot configure it.'
                            self.logger.log(LogPriority.DEBUG, debug)
                        else:
                            self.detailedresults += 'Avahi daemon ' + \
                                'installed, but could not locate the ' + \
                                'configuration file for it.\n'
                            self.rulesuccess = False

        except IOError:
            self.detailedresults += '\n' + traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        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("fix", self.rulesuccess,
                                   self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return self.rulesuccess

    def fixmac(self):
        '''apply fixes needed for mac os x
        
        @author: Breen Malmberg
        @change: dwalker - implemented kveditor instead of direct editing


        '''
        try:
            self.detailedresults = ""
            success = True
            # See if parameter is set
            self.ch.executeCommand(self.pbr)
            resultOutput = self.ch.getOutput()
            if len(resultOutput) >= 1:
                if (resultOutput[0] == ""):
                    fixit = True
                else:
                    fixit = False
            else:
                fixit = True
            # Add parameter
            if fixit:
                # Due to weaknesses in using PlistBuddy and defaults to delete
                # from plists, as well as shortcomings in STONIX's state change
                # logging, we will record this change as a file deletion.
                # If the rule's undo is run on OS X, it will restore the
                # previous version of this file.
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                if self.hasSIP:
                    self.statechglogger.recordfiledelete(
                        self.preferences, myid)
                else:
                    self.statechglogger.recordfiledelete(self.service, myid)
                self.ch.executeCommand(self.pbf)
                resultOutput = self.ch.getOutput()
                errorcode = self.ch.getReturnCode()
                if errorcode == 0:
                    debug = self.parameter + " was set successfully!"
                    self.logger.log(LogPriority.DEBUG, debug)
                else:
                    self.detailedresults += self.parameter + \
                        " was not set successfully!\n"
                    self.statechglogger.deleteentry(myid)
                    success = False
            else:
                debug = self.parameter + " was already set!"
                self.logger.log(LogPriority.DEBUG, debug)
            # Reload Service
            if success:
                success = self.sh.reloadService(self.service,
                                                serviceTarget=self.servicename)
                if success:
                    debug = "Service: " + str(self.service) + ", " + \
                        self.servicename + " was reloaded successfully."
                    self.logger.log(LogPriority.DEBUG, debug)
                else:
                    debug = "Service: " + str(self.service) + ", " + \
                        self.servicename + " reload failed!"
                    self.logger.log(LogPriority.DEBUG, debug)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            success = False
            raise
        return success

    def parseNumDependencies(self, pkgname):
        '''parse output of yum command to determine number of dependent packages
        to the given pkgname

        :param pkgname: 
        :returns: int
        @author: Breen Malmberg

        '''
        numdeps = 0
        flag = 0

        try:

            if self.pkghelper.determineMgr() == 'zypper':
                command = ['zypper', 'info', '--requires', pkgname]
                self.ch.executeCommand(command)
                output = self.ch.getOutput()
                for line in output:
                    if flag:
                        numdeps += 1
                    if re.search('Requires:', line):
                        flag = 1

            elif self.pkghelper.determineMgr() == 'yum':
                command = ['yum', '--assumeno', 'remove', pkgname]
                self.ch.wait = False
                self.ch.executeCommand(command)
                output = self.ch.getOutput()
                for line in output:
                    if re.search('Dependent packages\)', line):
                        sline = line.split('(+')
                        if len(sline) < 2:
                            return numdeps
                        cline = [
                            int(s) for s in sline[1].split() if s.isdigit()
                        ]
                        numdeps = int(cline[0])

            elif self.pkghelper.determineMgr() == 'dnf':
                command = ['dnf', '--assumeno', 'remove', pkgname]
                self.ch.wait = False
                self.ch.executeCommand(command)
                output = self.ch.getOutput()
                for line in output:
                    if re.search('Dependent packages\)', line):
                        sline = line.split('(+')
                        if len(sline) < 2:
                            return numdeps
                        cline = [
                            int(s) for s in sline[1].split() if s.isdigit()
                        ]
                        numdeps = int(cline[0])

            elif self.pkghelper.determineMgr() == 'apt-get':
                command = ['apt-cache', 'depends', pkgname]
                self.ch.executeCommand(command)
                output = self.ch.getOutput()
                for line in output:
                    if re.search('Depends:', line):
                        numdeps += 1
            else:
                self.detailedresults += 'Unable to detect package manager\n'
                return numdeps

        except (IOError, OSError):
            self.detailedresults += 'Specified package: ' + str(pkgname) + \
                ' not found.\n'
            return numdeps
        except Exception:
            raise
        return numdeps
Ejemplo n.º 8
0
class DisableRemoveableStorage(Rule):
    '''Disable removeable storage. This rule is optional, and disables USB, thunderbolt and firewire
    storage devices from accessing, or being accessed, by the system.


    '''
    def __init__(self, config, environ, logger, statechglogger):
        '''

        @param config:
        @param environ:
        @param logger:
        @param statechglogger:
        '''
        Rule.__init__(self, config, environ, logger, statechglogger)

        self.logger = logger
        self.rulenumber = 29
        self.rulename = 'DisableRemoveableStorage'
        self.mandatory = False
        self.formatDetailedResults("initialize")
        self.guidance = ['NSA 2.2.2.2, CIS, NSA(2.2.2.2), cce-4006-3,4173-1']
        self.applicable = {
            'type': 'white',
            'family': ['linux', 'solaris', 'freebsd'],
            'os': {
                'Mac OS X': ['10.15', 'r', '10.15.10']
            },
            'fisma': 'high'
        }

        # configuration item instantiation
        datatype = "bool"
        key = "DISABLEREMOVEABLESTORAGE"
        instructions = "To disable removeable storage devices on this system, set the value of DISABLEREMOVEABLESTORAGE to True"
        default = False
        self.storageci = self.initCi(datatype, key, instructions, default)

        #global variables
        self.grubfiles = [
            "/boot/grub2/grub.cfg", "/boot/grub/grub.cfg",
            "/boot/grub/grub.conf"
        ]
        self.pcmcialist = ['pcmcia-cs', 'kernel-pcmcia-cs', 'pcmciautils']
        self.pkgremovedlist = []
        self.iditerator = 0
        self.created = False
        self.daemonpath = os.path.abspath(
            os.path.join(os.path.dirname(
                sys.argv[0]))) + "/stonix_resources/disablestorage.py"
        self.sethelptext()
        self.grubperms = ""
        self.ph = Pkghelper(self.logger, self.environ)
        self.ch = CommandHelper(self.logger)

    def report(self):
        '''report the current rule-compliance status of this system. update
        self.rulesuccess if method does not succeed. self.compliant if
        rule succeeds and reports true.


        :returns: self.compliant

        :rtype: bool

@author: Breen Malmberg

@change: dwalker - implementing kveditor and completely revamped rule
    logic. added event deletion at the beginning of the fix
@change: dwalker 8/13/2014 changed name of rule to
    DisableRemoveableStorage and rule now supports disabling other
    ports such thunderbolt and firewire

        '''

        try:
            # defaults
            self.detailedresults = ""
            if self.environ.getostype() == "Mac OS X":
                compliant = self.reportMac()
            else:
                compliant = self.reportLinux()
            self.compliant = compliant
        except OSError:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
        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 reportLinux(self):
        '''sub method for linux portion of compliance reporting
        @author: dwalker


        :returns: compliant

        :rtype: boolean

        '''
        compliant = True
        lsmodcmd = ""

        # determine location of lsmod binary
        if os.path.exists("/sbin/lsmod"):
            lsmodcmd = "/sbin/lsmod"
        elif os.path.exists("/usr/bin/lsmod"):
            lsmodcmd = "/usr/bin/lsmod"

        usbmods = ["usb_storage", "usb-storage"]
        # run lsmod command and look for any of the items from
        # usbmods list in the output.  If item exists in output
        # then that usb module is not disabled.  This is for
        # reporting only.  There is no fix using lsmod command.
        if lsmodcmd:
            for usb in usbmods:
                cmd = [lsmodcmd, "|", "grep", usb]
                self.ch.executeCommand(cmd)
                if self.ch.getReturnCode() == "0":
                    compliant = False
                    self.detailedresults += "lsmod command shows usb not disabled\n"
                    break

        # check compliance of grub file(s) if files exist
        if re.search("Red Hat", self.environ.getostype()) and \
                re.search("^6", self.environ.getosver()):
            self.grubperms = [0, 0, 0o600]
        elif self.ph.manager is "apt-get":
            self.grubperms = [0, 0, 0o400]
        else:
            self.grubperms = [0, 0, 0o644]
        for grub in self.grubfiles:
            if os.path.exists(grub):
                if self.grubperms:
                    if not checkPerms(grub, self.grubperms, self.logger):
                        compliant = False
                        self.detailedresults += "Permissions " + \
                                                "incorrect on " + grub + " file\n"
                contents = readFile(grub, self.logger)
                if contents:
                    for line in contents:
                        if re.search("^kernel", line.strip()) \
                                or re.search("^linux", line.strip()) \
                                or re.search("^linux16", line.strip()) \
                                or re.search("^set default_kernelopts", line.strip()):
                            if not re.search("\s+nousb\s*", line):
                                debug = grub + " file doesn't " + \
                                        "contain nousb kernel option\n"
                                self.detailedresults += grub + " file doesn't " + \
                                                        "contain nousb kernel option\n"
                                self.logger.log(LogPriority.DEBUG, debug)
                                compliant = False
                            if not re.search(
                                    "\s+usbcore\.authorized_default=0\s*",
                                    line):
                                debug = grub + " file doesn't " + \
                                        "contain usbcore.authorized_default=0 " + \
                                        "kernel option\n"
                                self.detailedresults += grub + " file doesn't " + \
                                                        "contain usbcore.authorized_default=0 " + \
                                                        "kernel option\n"
                                self.logger.log(LogPriority.DEBUG, debug)
                                compliant = False
        # check for existence of certain usb packages, non-compliant
        # if any exist
        for item in self.pcmcialist:
            if self.ph.check(item):
                self.detailedresults += item + " is installed " + \
                                        "and shouldn't be\n"
                compliant = False

        # check modprobe files inside modprobe.d directory for
        # contents inside self.blacklist variable
        removeables = []
        found1 = True
        # self.blacklist dictionary contains the directives
        # and the value we're looking for (key) and contains
        # a default value of False for each one.  Upon finding
        # each directive and value pair e.g. blacklist usb_storage
        # the dictionary is updated with a True value.  This keeps
        # track of the directives we didnt find or that had
        # incorrect values
        self.blacklist = {
            "blacklist usb_storage": False,
            "install usbcore /bin/true": False,
            "install usb-storage /bin/true": False,
            "blacklist uas": False,
            "blacklist firewire-ohci": False,
            "blacklist firewire-sbp2": False
        }
        #check if /etc/modprobe.d directory exists
        if os.path.exists("/etc/modprobe.d"):
            #extract all files inside modprobe.d
            dirs = glob.glob("/etc/modprobe.d/*")
            # since file name doesn't matter
            # i.e. all files are read and treated the same in
            # modprobe.d, if directives are found in any of
            # the files inside this directory, where they don't
            # have to be in the same file, the system is compliant
            for directory in dirs:
                if os.path.isdir(directory):
                    continue
                contents = readFile(directory, self.logger)
                for item in self.blacklist:
                    for line in contents:
                        if re.search("^" + item, line.strip()):
                            self.blacklist[item] = True
            # if we don't find all directives in any of the files in
            # modprobe.d, we will now check /etc/modprobe.conf as
            # they are all equivalent. We will still keep track of
            # whether we already found one directive in one of the
            # files in modprobe.d
            for item in self.blacklist:
                if not self.blacklist[item]:
                    found1 = False
        else:
            found1 = False

        # either not all directives inside self.blacklist were found
        # or /etc/modprobe.d didn't exist.  Now we check /etc/modprobe.conf
        # for any remaining unfound directives.
        if not found1:
            if os.path.exists("/etc/modprobe.conf"):
                contents = readFile("/etc/modprobe.conf")
                if contents:
                    for item in self.blacklist:
                        for line in contents:
                            if re.search("^" + item, line.strip()):
                                self.blacklist[item] = True
            for item in self.blacklist:
                if not self.blacklist[item]:
                    debug = "modprobe.conf nor blacklist " + \
                            "files contain " + item + "\n"
                    self.logger.log(LogPriority.DEBUG, debug)
                    compliant = False
        # any directives that were found we remove from self.blacklist
        # We must add to a variable called removeables first then
        # iterate through removeables and remove each item self.blacklist
        for item in self.blacklist:
            if self.blacklist[item]:
                removeables.append(item)
        for item in removeables:
            del (self.blacklist[item])

        # check the contents of the udev file for a certain desired line
        self.udevfile = "/etc/udev/rules.d/10-local.rules"
        found2 = False
        if os.path.exists(self.udevfile):
            if not checkPerms(self.udevfile, [0, 0, 0o644], self.logger):
                self.detailedresults += "Permissions not correct " + \
                                        "on " + self.udevfile + "\n"
                compliant = False
            contents = readFile(self.udevfile, self.logger)
            for line in contents:
                if re.search(
                        "ACTION\=\=\"add\"\, SUBSYSTEMS\=\=\"usb\"\, RUN\+\=\"/bin/sh \-c \'for host in /sys/bus/usb/devices/usb\*\; do echo 0 \> \$host/authorized\_default\; done\'\"",
                        line.strip()):
                    found2 = True
            if not found2:
                self.detailedresults += "Udev rule not found to disable usb at boot\n"
                debug = "Udev rule not found to disable usb at boot\n"
                self.logger.log(LogPriority.DEBUG, debug)
                compliant = False
        else:
            self.detailedresults += "Udev file doesn't exist to disable usb at boot\n"
            debug = "Udev file doesn't exist to disable usb at boot\n"
            self.logger.log(LogPriority.DEBUG, debug)
            compliant = False
        return compliant

    def reportMac(self):
        '''
        :returns: compliant
        :rtype: bool
        '''

        self.detailedresults = ""
        compliant = True
        self.setvars()
        if not self.usbprofile:
            self.detailedresults += "Could not locate the appropriate usb disablement profile for your system.\n"
            compliant = False
            self.formatDetailedResults("report", compliant,
                                       self.detailedresults)
            self.logdispatch.log(LogPriority.INFO, self.detailedresults)
            return compliant
        self.usbdict = {
            "com.apple.systemuiserver": {
                "harddisk-external": {
                    "val": ["deny", "eject"],
                    "type": "",
                    "accept": "",
                    "result": False
                }
            }
        }
        self.usbeditor = KVEditorStonix(self.statechglogger, self.logger,
                                        "profiles", self.usbprofile, "",
                                        self.usbdict, "", "")
        if not self.usbeditor.report():
            if self.usbeditor.badvalues:
                self.detailedresults += self.usbeditor.badvalues + "\n"
            self.detailedresults += "USB Disablement profile either not installed or values are incorrect\n"
            compliant = False
        return compliant

    def setvars(self):
        self.usbprofile = ""
        baseconfigpath = "/Applications/stonix4mac.app/Contents/Resources/stonix.app/Contents/MacOS/stonix_resources/files/"
        self.usbprofile = baseconfigpath + "stonix4macDisableUSB.mobileconfig"

        # the following path and dictionaries are for testing on local vm's
        # without installing stonix package each time.  DO NOT DELETE
        # basetestpath = "/Users/username/stonix/src/stonix_resources/files/"
        # self.usbprofile = basetestpath + "stonix4macDisableUSB.mobileconfig"
        if not os.path.exists(self.usbprofile):
            self.logger.log(
                LogPriority.DEBUG,
                "Could not locate appropriate usb disablement profile\n")
            self.usbprofile = ""

    def fix(self):
        '''attempt to perform necessary operations to bring the system into
        compliance with this rule.
        
        @author Breen Malmberg
        @change: dwalker - implemented event deletion at the beginning of fix,
            also implemented a check for the ci value to see if fix should
            even be run.


        '''

        try:
            success = True
            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 not self.storageci.getcurrvalue():
                self.detailedresults += "Rule not enabled so nothing was done\n"
                self.logger.log(LogPriority.DEBUG,
                                'Rule was not enabled, so nothing was done')
                return
            if self.environ.getostype() == "Mac OS X":
                success = self.fixMac()
            else:
                success = self.fixLinux()
            self.rulesuccess = success
        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 fixMac(self):
        '''This method will attempt to disable certain storage ports by moving
        certain kernel extensions.  If the check box is checked we will
        move the kernel (if present) associated with that storage port/device
        into a folder designated for those disabled extensions.  If the
        check box is unchecked, we will assume the user doesn't want this
        disabled and if the kernel is no longer where it should be, we will
        check the disabled extensions folder to see if it was previously
        disabled.  If it's in that folder, we will move it back.
        @author: Breen Malmberg


        :returns: bool
        @change: dwalker 8/19/2014

        '''
        success = True
        if not self.usbprofile:
            return False
        if not self.usbeditor.report():
            if self.usbeditor.fix():
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                self.usbeditor.setEventID(myid)
                if not self.usbeditor.commit():
                    success = False
                    self.detailedresults += "Unable to install " + self.usbprofile + " profile\n"
                    self.logdispatch.log(LogPriority.DEBUG,
                                         "Kveditor commit failed")
            else:
                success = False
                self.detailedresults += "Unable to install " + self.passprofile + "profile\n"
                self.logdispatch.log(LogPriority.DEBUG, "Kveditor fix failed")
        else:
            success = False
            self.detailedresults += "Password CI was not enabled.\n"
        return success

    def fixLinux(self):
        '''sub method for linux portion of compliance fixing
        @author: dwalker


        :returns: success

        :rtype: boolean

        '''
        success = True
        created1, created2 = False, False
        changed = False
        tempstring = ""
        grubfilefound = False

        for grub in self.grubfiles:
            if os.path.exists(grub):
                grubfilefound = True
                if self.grubperms:
                    if not checkPerms(grub, self.grubperms, self.logger):
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        if not setPerms(grub, self.grubperms, self.logger,
                                        self.statechglogger, myid):
                            success = False
                contents = readFile(grub, self.logger)
                kernellinefound = False
                if contents:
                    for line in contents:
                        if re.search("^kernel", line.strip()) or re.search("^linux", line.strip()) \
                                or re.search("^linux16", line.strip()):
                            kernellinefound = True
                            if not re.search("\s+nousb\s*", line):
                                changed = True
                                tempstring += line.strip() + " nousb"
                            if not re.search(
                                    "\s+usbcore\.authorized_default=0\s+",
                                    line):
                                changed = True
                                tempstring += line.strip(
                                ) + " usbcore.authorized_default=0"
                            tempstring += "\n"
                        elif re.search("^set default_kernelopts",
                                       line.strip()):
                            # Fedora 31 has changed it's kernel option line format
                            kernellinefound = True
                            kernelline = line.strip()
                            if not re.search("\s+nousb\s*", kernelline):
                                changed = True
                                kernelline = re.sub("\"$", " nousb\"",
                                                    kernelline)
                            if not re.search(
                                    "\s+usbcore\.authorized_default=0\s+",
                                    kernelline):
                                changed = True
                                kernelline = re.sub(
                                    "\"$", " usbcore.authorized_default=0\"",
                                    kernelline)
                            tempstring += kernelline + "\n"
                        else:
                            tempstring += line
                if not kernellinefound:
                    changed = False
                    self.detailedresults += "The grub file doesn't contain kernel line\n" + \
                                            "Unable to fully implement fixes in this rule\n"
                    success = False
                if changed:
                    tmpfile = grub + ".tmp"
                    if writeFile(tmpfile, tempstring, self.logger):
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        event = {"eventtype": "conf", "filepath": grub}
                        self.statechglogger.recordchgevent(myid, event)
                        self.statechglogger.recordfilechange(
                            grub, tmpfile, myid)
                        os.rename(tmpfile, grub)
                        if not setPerms(grub, self.grubperms, self.logger):
                            success = False
                            self.detailedresults += "Unable to set permissions on " + \
                                                    grub + " file\n"
                    else:
                        success = False
        if not grubfilefound:
            self.detailedresults += "No grub configuration file found\n" + \
                                    "Unable to fully fix system for this rule\n"
            success = False
        blacklistf = "/etc/modprobe.d/stonix-blacklist.conf"
        tempstring = ""
        # Check if self.blacklist still contains values, if it
        # does, then we didn't find all the blacklist values
        # in report
        if self.blacklist:
            # didn't find one or more directives in the files
            # inside modprobe.d so we now check an alternate file
            # we create stonixblacklist file if it doesn't
            # exist and put remaining unfound blacklist
            # items there
            if not os.path.exists(blacklistf):
                created1 = True
                createFile(blacklistf, self.logger)
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "creation", "filepath": blacklistf}
                self.statechglogger.recordchgevent(myid, event)
            # file was already present and we need contents already
            # inside file to remain in newly written file
            if not created1:
                contents = readFile(blacklistf, self.logger)
                for item in contents:
                    tempstring += item
            for item in self.blacklist:
                tempstring += item + "\n"
            tmpfile = blacklistf + ".tmp"
            if writeFile(tmpfile, tempstring, self.logger):
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                event = {"eventtype": "conf", "filepath": blacklistf}
                self.statechglogger.recordchgevent(myid, event)
                self.statechglogger.recordfilechange(blacklistf, tmpfile, myid)
                os.rename(tmpfile, blacklistf)
                os.chown(blacklistf, 0, 0)
                os.chmod(blacklistf, 420)
                resetsecon(blacklistf)
            if not checkPerms(blacklistf, [0, 0, 420], self.logger):
                self.iditerator += 1
                myid = iterate(self.iditerator, self.rulenumber)
                if not setPerms(blacklistf, [0, 0, 420], self.logger,
                                self.statechglogger, myid):
                    success = False
            if self.ph.manager == "apt-get":
                cmd = ["/usr/sbin/update-initramfs", "-u"]
                if not self.ch.executeCommand(cmd):
                    success = False
                    self.detailedresults += "Unable to run update-initramfs command\n"
        for item in self.pcmcialist:
            if self.ph.check(item):
                self.ph.remove(item)
                self.pkgremovedlist.append(item)
        if not os.path.exists(self.udevfile):
            if not createFile(self.udevfile, self.logger):
                self.detailedresults += "Unable to create " + \
                                        self.udevfile + " file\n"
                success = False
            else:
                created2 = True
        if os.path.exists(self.udevfile):
            if not checkPerms(self.udevfile, [0, 0, 0o644], self.logger):
                if created2:
                    if not setPerms(self.udevfile, [0, 0, 0o644], self.logger):
                        success = False
                        self.detailedresults += "Unable to set " + \
                                                "permissions on " + self.udevfile + "\n"
                else:
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    if not setPerms(self.udevfile, [0, 0, 0o644], self.logger,
                                    self.statechglogger, myid):
                        success = False
                        self.detailedresults += "Unable to set " + \
                                                "permissions on " + self.udevfile + "\n"
            found = False
            contents = readFile(self.udevfile, self.logger)
            tempstring = ""
            for line in contents:
                if re.search(
                        "ACTION==\"add\"\, SUBSYSTEMS==\"usb\"\, RUN+=\"/bin/sh -c \'for host in /sys/bus/usb/devices/usb\*\; do echo 0 > \$host/authorized_default; done\'\"",
                        line.strip()):
                    found = True
                tempstring += line
            if not found:
                tempstring += "ACTION==\"add\", SUBSYSTEMS==\"usb\", RUN+=\"/bin/sh -c \'for host in /sys/bus/usb/devices/usb*; do echo 0 > $host/authorized_default; done\'\""
                tmpfile = self.udevfile + ".tmp"
                if writeFile(tmpfile, tempstring, self.logger):
                    if not created2:
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        event = {
                            "eventtype": "conf",
                            "filepath": self.udevfile
                        }
                        self.statechglogger.recordchgevent(myid, event)
                        self.statechglogger.recordfilechange(
                            self.udevfile, tmpfile, myid)
                    os.rename(tmpfile, self.udevfile)
                    os.chown(self.udevfile, 0, 0)
                    os.chmod(self.udevfile, 0o644)
                    resetsecon(self.udevfile)
                else:
                    success = False
                    self.detailedresults += "Unable to write changes " + \
                                            "to " + self.udevfile + "\n"
        return success
Ejemplo n.º 9
0
class RemoveSUIDGames(Rule):
    def __init__(self, config, enviro, logger, statechglogger):
        Rule.__init__(self, config, enviro, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 244
        self.rulename = "RemoveSUIDGames"
        self.formatDetailedResults("initialize")
        self.mandatory = True
        self.sethelptext()
        self.applicable = {'type': 'white', 'family': 'linux'}

        # Configuration item instantiation
        datatype = "bool"
        key = "REMOVESUIDGAMES"
        instructions = "To disable this rule, set the value of " + \
                       "REMOVESUIDGAMES to false."
        default = True
        self.ci = self.initCi(datatype, key, instructions, default)

        self.guidance = ["LANL 15.7"]
        self.iditerator = 0
        self.ph = Pkghelper(self.logger, self.environ)

        self.gamelist = [
            'atlantik', 'bomber', 'bovo', 'gnuchess', 'kapman', 'kasteroids',
            'katomic', 'kbackgammon', 'kbattleship', 'kblackbox', 'kblocks',
            'kbounce', 'kbreakout', 'kdiamond', 'kenolaba', 'kfouleggs',
            'kfourinline', 'kgoldrunner', 'killbots', 'kiriki', 'kjumpingcube',
            'klickety', 'klines', 'kmahjongg', 'kmines', 'knetwalk', 'kolf',
            'kollision', 'konquest', 'kpat', 'kpoker', 'kreversi', 'ksame',
            'kshisen', 'ksirk', 'ksirkskineditor', 'ksirtet', 'ksmiletris',
            'ksnake', 'kspaceduel', 'ksquares', 'ksudoku', 'ktron',
            'ktuberling', 'kubrick', 'kwin4', 'kwin4proc', 'lskat',
            'lskatproc', 'gnome-games', 'kdegames', 'gnome-taquin'
        ]

    def report(self):
        try:
            compliant = True
            self.gamesfound = []
            self.gamedirsfound = []

            for game in self.gamelist:
                if self.ph.check(game):
                    self.gamesfound.append(game)
                    compliant = False
                    self.detailedresults += game + " installed on system\n"
                if os.path.exists("/usr/bin/" + game):
                    self.gamedirsfound.append("/usr/bin/" + game)
                    compliant = False
                    self.detailedresults += "/usr/bin/" + game + "path exists\n"
            if (os.path.exists("/usr/games")):
                usrgames = os.listdir("/usr/games")
                if len(usrgames) > 0:
                    compliant = False
                    self.detailedresults += "/usr/games directory is not empty\n"
            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 fix(self):
        try:
            if not self.ci.getcurrvalue():
                return
            success = True
            debug = ""
            self.iditerator = 0
            eventlist = self.statechglogger.findrulechanges(self.rulenumber)
            for event in eventlist:
                self.statechglogger.deleteentry(event)

            for game in self.gamesfound:
                # pkgName = self.ph.getPackageFromFile(game)
                # if pkgName is not None and str(pkgName) is not "":
                if self.ph.remove(game):
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)
                    event = {
                        "eventtype": "pkghelper",
                        "pkgname": game,
                        "startstate": "installed",
                        "endstate": "removed"
                    }
                    self.statechglogger.recordchgevent(myid, event)
                else:
                    success = False
                    self.detailedresults += "Unable to remove " + game + "\n"
            for game in self.gamedirsfound:
                #did not put state change event recording here due to python
                #not sending valid return code back for success or failure
                #with os.remove command therefore not knowing if successful
                #to record event
                if os.path.exists(game):
                    os.remove(game)
            if os.path.exists("/usr/games/"):
                if not self.__cleandir("/usr/games/"):
                    success = False
                    self.detailedresults += "Unable to remove all games from /usr/games\n"

            self.rulesuccess = success
        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("fix", self.rulesuccess,
                                   self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return self.rulesuccess

    def __cleandir(self, directory, depth=0):
        '''Recursively finds the package name for each file in a directory,
        and all child directories, and uninstalls the package. Ignores links.
        This is best-effort; no error checking is done for the uninstall
        requests.

        @param directory: Name of the directory to search
        @return: False if a package name is not found for any file, True
                 otherwise.
        @author: Eric Ball
        '''
        success = True
        dirlist = os.listdir(directory)
        for path in dirlist:
            path = directory + path
            if os.path.isfile(path):
                pkgName = self.ph.getPackageFromFile(path)
                if pkgName is not None:
                    if self.ph.remove(pkgName):
                        self.iditerator += 1
                        myid = iterate(self.iditerator, self.rulenumber)
                        event = {
                            "eventtype": "pkghelper",
                            "pkgname": pkgName,
                            "startstate": "installed",
                            "endstate": "removed"
                        }
                        self.statechglogger.recordchgevent(myid, event)
                    else:
                        debug = "Could not remove package " + pkgName
                        self.logger.log(LogPriority.DEBUG, debug)
                        success = False
                else:
                    debug = "Could not find package name for " + path
                    self.logger.log(LogPriority.DEBUG, debug)
                    success = False
            elif os.path.isdir(path):
                if depth < 6:
                    success &= self.__cleandir(path, depth + 1)
        dirlist = os.listdir(directory)
        if dirlist:
            # There is a possibility that removing some packages will result in
            # other packages being installed. We will attempt to remove these
            # additional packages, but limit this to avoid infinite loops.
            if depth < 6:
                success &= self.__cleandir(directory, depth + 1)
        return success
Ejemplo n.º 10
0
class SecureSNMP(Rule):
    '''classdocs'''

    def __init__(self, config, environ, logger, statechglogger):
        '''
        Constructor
        '''

        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.statechglogger = statechglogger
        self.rulenumber = 144
        self.rulename = 'SecureSNMP'
        self.formatDetailedResults("initialize")
        self.mandatory = True
        self.sethelptext()
        self.rootrequired = True
        self.guidance = ['NSA 3.20', 'CCE 4540-1']
        self.applicable = {'type': 'white',
                           'family': ['linux', 'solaris', 'freebsd'],
                           'os': {'Mac OS X': ['10.15', 'r', '10.15.10']}}
        datatype = 'bool'
        key = 'DISABLESNMP'
        instructions = "If there is a mission-critical need for hosts at" + \
                       "this site to be remotely monitored by a SNMP " + \
                       "tool, then prevent the disabling and removal " + \
                       "of SNMP by setting the value of DisableSNMP " + \
                       "to False."
        default = True
        self.disablesnmp = self.initCi(datatype, key, instructions, default)

        datatype2 = 'bool'
        key2 = 'CONFIGURESNMP'
        instructions2 = "To configure SNMP on this system, make sure " + \
                        "you have the value for DisableSNMP set to " + \
                        "False, and set the value of ConfigureSNMP to True."
        default2 = True
        self.configuresnmp = self.initCi(datatype2, key2, instructions2,
                                         default2)

        self.snmpdconflocations = ['/etc/snmp/conf/snmpd.conf',
                                   '/etc/snmp/conf/snmp.conf',
                                   '/etc/snmp/snmpd.conf',
                                   '/etc/snmp/snmp.conf']
        self.snmpv3directives = {'defContext': 'none',
                                 'defVersion': '3',
                                 'defAuthType': 'SHA',
                                 'defSecurityLevel': 'authNoPriv'}
# add any other possible snmp configuration file paths from the environment
# variable SNMPCONFPATH
# .get does not throw keyerror but instead returns None if env doesn't exist
        snmpconfpathstring = os.environ.get('SNMPCONFPATH')

        if snmpconfpathstring:
            snmpconfpathlist = snmpconfpathstring.split()
            for path in snmpconfpathlist:
                path = str(path).strip()
                self.snmpdconflocations.append(path)

    def report(self):
        '''Determine which report method(s) to run and run them


        :returns: bool
        @author bemalmbe

        '''

        # defaults
        self.detailedresults = ""

        try:

            if self.environ.getostype() == 'Mac OS X':
                self.compliant = self.reportmac()
                self.formatDetailedResults("report", self.compliant,
                                           self.detailedresults)
                self.logdispatch.log(LogPriority.INFO, self.detailedresults)
                return self.compliant
            compliant = True
            self.svchelper = ServiceHelper(self.environ, self.logger)
            self.pkghelper = Pkghelper(self.logger, self.environ)

            if self.disablesnmp.getcurrvalue():
                if not self.reportDisableSNMP():
                    compliant = False

            if self.configuresnmp.getcurrvalue():
                if not self.reportConfigureSNMP():
                    compliant = False

            self.compliant = compliant

        except AttributeError:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            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 reportmac(self):
        '''@author: Breen Malmberg'''

        configured = True

        try:

            self.cmdhelper = CommandHelper(self.logger)
            filepath = '/System/Library/LaunchDaemons/org.net-snmp.snmpd.plist'
            if not os.path.exists(filepath):
                configured = False
                self.detailedresults += '\nrequired plist configuration file not found: ' + filepath
            cmd = '/usr/bin/defaults read ' + filepath + ' Disabled'
            self.cmdhelper.executeCommand(cmd)
            output = self.cmdhelper.getOutputString()
            errout = self.cmdhelper.getErrorString()
            if errout:
                configured = False
                self.detailedresults += '\nunable to execute defaults read command, or \"Disabled\" key does not exist'
            else:
                if not re.search('^1', output):
                    configured = False
                    self.detailedresults += '\nsnmpd is not yet disabled'

        except Exception:
            raise
        return configured

    def reportDisableSNMP(self):
        '''Determine whether SNMP service is disabled and uninstalled


        :returns: bool
        @author bemalmbe

        '''

        # defaults
        secure = False
        svcenabled = False
        pkginstalled = False

        try:

            svcenabled = self.svchelper.auditService('snmpd', _="_")

            pkginstalled = self.pkghelper.check('net-snmpd')

            if not svcenabled and not pkginstalled:
                secure = True

            return secure

        except AttributeError:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
            return False

    def reportConfigureSNMP(self):
        '''Determine whether the SNMP service is securely configured


        :returns: bool
        @author bemalmbe

        '''

        # defaults
        kvintent = 'present'
        kvconftype = 'conf'
        kvtype = 'space'
        secure = True

        # check to make sure perms on conf files are 640
        # check to make sure ownership of conf files is root:root
        # check to make sure conf files are not using weak or default community
        # string and that they are not using anything other than version 3
        # security model as per NSA guidance

        try:

            if self.reportDisableSNMP():
                return True

            for location in self.snmpdconflocations:
                if os.path.exists(location):
                    perms = getOctalPerms(location)
                    if perms != 640:
                        secure = False

                    kvpath = location
                    kvtmppath = location + '.stonixtmp'

                    self.kvosnmp = KVEditorStonix(self.statechglogger,
                                                  self.logger, kvtype, kvpath,
                                                  kvtmppath,
                                                  self.snmpv3directives,
                                                  kvintent, kvconftype)

                    kvosnmpretval = self.kvosnmp.report()
                    if not kvosnmpretval:
                        secure = False

                    f = open(location, 'r')
                    contentlines = f.readlines()
                    f.close()

                    for line in contentlines:
                        if re.search('^group', line):
                            line = line.split()
                            if line[2] in ['v1', 'v2', 'v2c']:
                                secure = False
                                self.detailedresults += '''You are currently using an outdated security model for your SNMP configuration. Please update to model 3.'''

                    for line in contentlines:
                        if re.search('^com2sec', line):
                            line = line.split()
                            if line[3] in ['public', 'community']:
                                secure = False
                                self.detailedresults += '''You are currently using a default or weak community string.'''

                    for line in contentlines:
                        if re.search('^access', line):
                            line = line.split()
                            if line[3] in ['any', 'v1', 'v2', 'v2c']:
                                secure = False
                                self.detailedresults += '''You are currently using an outdated security model for your SNMP configuration. Please update to model 3.'''

                            if line[4] == 'noauth':
                                secure = False
                                self.detailedresults += '''You are currently not requiring authentication for SNMP. This is an unsecure practice. Please change to authNoPriv or authPriv.'''

            return secure

        except (IndexError, OSError):
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.ERROR, self.detailedresults)
            return False

    def fix(self):
        '''Determine which fix method(s) to run and run them
        
        @author bemalmbe


        '''

        self.detailedresults = ""
        self.rulesuccess = True

        try:

            if self.environ.getostype() == 'Mac OS X':
                if self.disablesnmp.getcurrvalue() or self.configuresnmp.getcurrvalue():
                    self.rulesuccess = self.fixmac()
                    self.formatDetailedResults("fix", self.rulesuccess,
                                               self.detailedresults)
                    self.logdispatch.log(LogPriority.INFO, self.detailedresults)
                    return self.rulesuccess

            if self.disablesnmp.getcurrvalue():
                self.fixDisableSNMP()

            if self.configuresnmp.getcurrvalue():
                self.fixConfigureSNMP()

        except AttributeError:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            self.detailedresults = self.detailedresults + "\n" + str(err) + \
                " - " + str(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 fixmac(self):
        '''@author: Breen Malmberg'''

        success = True

        try:

            defaults = '/usr/bin/defaults '
            operation = 'write '
            filepath = '/System/Library/LaunchDaemons/org.net-snmp.snmpd.plist '
            key = 'DISABLED'
            val = ' -bool true'

            cmd = defaults + operation + filepath + key + val

            self.cmdhelper.executeCommand(cmd)
            errout = self.cmdhelper.getErrorString()
            if errout:
                success = False
                self.detailedresults += '\ncould not set Disabled key to true in org.net-snmp.snmpd.plist'

        except Exception:
            raise
        return success

    def fixDisableSNMP(self):
        '''Disable the SNMP service and uninstall the package for it
        
        @author bemalmbe


        '''

        try:

            if not self.reportDisableSNMP():

                self.svchelper.disableService('snmpd', _="_")

                self.pkghelper.remove('net-snmpd')

        except AttributeError:
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            raise

    def fixConfigureSNMP(self):
        '''Securely configure the SNMP service. This option should be used instead
        of disabling SNMP only if there is a mission-critical need for the
        SNMP service to operate in the environment.
        
        @author bemalmbe


        '''

# set auth type to SHA, security model version to 3, and security level to
# authNoPriv set permissions for the SNMP conf file to 640
# change owner and group of the SNMP conf file to root and root
# admin must set up security on version 3 themselves because it is
# account-based security and they must set up their own account(s)

        try:

            myid = '0144001'

            self.kvosnmp.setEventID(myid)

            self.kvosnmp.fix()
            self.kvosnmp.commit()

            for location in self.snmpdconflocations:
                if os.path.exists(location):
                    os.chmod(location, 0o640)
                    os.chown(location, 0, 0)

        except (KeyError, OSError):
            self.detailedresults = traceback.format_exc()
            self.logger.log(LogPriority.DEBUG, self.detailedresults)
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            raise
Ejemplo n.º 11
0
class DisableCloudServices(RuleKVEditor):
    '''This method runs all the report methods for RuleKVEditors defined in the
    dictionary
    
    @author: ekkehard j. koch
    @change: 07/23/2014 added ubuntu methods and applicability; fixed typos in
            doc strings; added class doc string; implemented pkghelper and
            iterate methods - bemalmbe


    '''

###############################################################################

    def __init__(self, config, environ, logdispatcher, statechglogger):
        RuleKVEditor.__init__(self, config, environ, logdispatcher,
                              statechglogger)

        self.rulenumber = 159
        self.rulename = 'DisableCloudServices'
        self.formatDetailedResults("initialize")
        self.mandatory = True
        self.rootrequired = True
        self.logger = self.logdispatch
        self.guidance = []
        self.applicable = {'type': 'white',
                           'os': {'Mac OS X': ['10.15', 'r', '10.15.10'],
                                  'Ubuntu': ['12.04', '+']}}
        self.ch = CommandHelper(self.logdispatch)

        # init CIs
        datatype = 'bool'
        key = 'DISABLECLOUDSERVICES'
        instructions = "To prevent cloud services from being disabled, " + \
            "set the value of DisableCloudServices to False."
        default = True
        self.DisableCloudServices = self.initCi(datatype, key, instructions,
                                                default)
        if self.environ.getosfamily() == 'darwin':
            self.addKVEditor("iCloudSaveNewDocumentsToDisk",
                             "defaults",
                             "NSGlobalDomain",
                             "",
                             {"NSDocumentSaveNewDocumentsToCloud":
                              ["0", "-bool no"]},
                             "present",
                             "",
                             "Save new documents to disk not to iCloud.",
                             None,
                             False,
                             {"NSDocumentSaveNewDocumentsToCloud":
                              ["1", "-bool yes"]})
        else:
            self.debianpkglist = ['unity-webapps-common',
                                  'unity-lens-shopping']
        self.sethelptext()
    def report(self):
        '''choose which report method to run based on OS archetype'''
        self.detailedresults = ""
        if self.environ.getosfamily() == 'darwin':
            RuleKVEditor.report(self, False)
        elif re.search('Ubuntu', self.environ.getostype()):
            retval = self.reportUbuntu()
            return retval
###############################################################################

    def reportUbuntu(self):
        '''if debian, check for unity-lens-shopping and unity-webapps-common
        cloud service packages


        '''

        # defaults
        self.compliant = True
        self.detailedresults = ""

        try:

            self.ph = Pkghelper(self.logdispatch, self.environ)

            for package in self.debianpkglist:
                if self.ph.check(package):
                    self.compliant = False

        except (KeyboardInterrupt, SystemExit):
            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 fix(self):
        '''choose which fix method to run, based on OS archetype'''
        self.detailedresults = ""
        if self.DisableCloudServices.getcurrvalue():
            if self.environ.getosfamily() == 'darwin':
                RuleKVEditor.fix(self, False)
            elif re.search('Ubuntu', self.environ.getostype()):
                self.fixUbuntu()
###############################################################################

    def fixUbuntu(self):
        '''if debian, disable unity-lens-shopping and unity-webapps-common
        cloud service packages, if they are installed


        '''

        # defaults
        self.iditerator = 0

        try:

            for package in self.debianpkglist:
                if self.ph.check(package):
                    self.ph.remove(package)

                    cmd = self.ph.getInstall() + package

                    event = {'eventtype': 'commandstring',
                             'command': cmd}
                    self.iditerator += 1
                    myid = iterate(self.iditerator, self.rulenumber)

                    self.statechglogger.recordchgevent(myid, event)

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception as err:
            self.rulesuccess = False
            self.detailedresults += "\n" + str(err) + 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
Ejemplo n.º 12
0
class SecurePOPIMAP(Rule):
    '''classdocs'''

    def __init__(self, config, environ, logger, statechglogger):
        '''
        Constructor
        '''
        Rule.__init__(self, config, environ, logger, statechglogger)
        self.config = config
        self.environ = environ
        self.logger = logger
        self.statechglogger = statechglogger
        self.rulenumber = 141
        self.rulename = 'SecurePOPIMAP'
        self.mandatory = True
        self.sethelptext()
        self.rootrequired = True
        self.applicable = {'type': 'black',
                           'family': ['darwin']}
        self.guidance = ['NSA(3.17)', 'cce-4384-4', '3887-7', '4530-2', '4547-6', '4552-6', '4371-1', '4410-7']

        data1 = 'bool'
        key1 = 'DISABLEPOPIMAP'
        instructions1 = 'To prevent POP/IMAP services from being disabled entirely, set the value of DisablePOPIMAP to False.'
        default1 = True
        self.disableci = self.initCi(data1, key1, instructions1, default1)

        data2 = 'bool'
        key2 = 'SECUREPOPIMAP'
        instructions2 = 'To securely configure POP/IMAP services, set the value of SecurePOPIMAP to True.'
        default2 = False
        self.secureci = self.initCi(data2, key2, instructions2, default2)

        data3 = 'string'
        key3 = 'RequireProtocols'
        instructions3 = 'If this system will be operating as a mail server, fill in the required/used protocols below. Please use a space-delimited list. Valid entries are limited to: imap, imaps, pop3, pop3s'
        default3 = ''
        self.reqprotocols = self.initCi(data3, key3, instructions3, default3)

        self.localization()

    def localization(self):
        '''determine which type of OS we are running on and set up class variables accordingly


        :returns: void
        @author: Breen Malmberg

        '''

        self.initobjs()

        self.setcommon()

        if self.pkgh.manager not in ['apt-get', 'yum', 'zypper', 'dnf']:
            self.logger.log(LogPriority.DEBUG, "Could not identify OS type or OS not supported!")

        if self.pkgh.manager == 'apt-get':
            self.setdebian()
        if self.pkgh.manager == 'yum':
            self.setredhat()
        if self.pkgh.manager == 'dnf':
            self.setredhat()
        if self.pkgh.manager == 'zypper':
            self.setsuse()

        pass

    def initobjs(self):
        '''initialize objects needed/used by other methods within this class


        :returns: void
        @author: Breen Malmberg

        '''

        try:

            # if you add class variables here, be sure to also add
            # checks for them, in the checkinitobjs() method
            self.pkgh = Pkghelper(self.logger, self.environ)
            self.svch = ServiceHelper(self.environ, self.logger)
            self.cmdh = CommandHelper(self.logger)
            self.debian = False
            self.suse = False
            self.redhat = False
            self.pkgdict = {}
            self.confpathdict = {}
            self.servicename = ''
            self.osdetected = False

        except Exception:
            raise

    def setcommon(self):
        '''set variables which are common to all platforms


        :returns: void
        @author: Breen Malmberg

        '''

        self.detailedresults = ""

        self.reqprots = ""

        self.protocollist = ['imap', 'imaps', 'pop3', 'pop3s']

    def setdebian(self):
        '''set debian specific variables


        :returns: void
        @author: Breen Malmberg

        '''

        self.debian = True
        self.osdetected = True
        self.pkgdict = {'dovecot-core': False,
                        'dovecot-pop3d': False,
                        'dovecot-imapd': False}

        # the following dictionary is of the format:
        # {configfilepath1: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2},
        # configfilepath2: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2}
        # }
        self.confpathdict = {'/etc/dovecot/dovecot.conf': {'protocols =': 'protocols = ' + str(self.reqprots) + '\n',
                                       'disable_plaintext_auth =': 'disable_plaintext_auth = yes\n',
                                       'login_process_per_connection =': 'login_process_per_connection = yes\n',
                                       'mail_drop_priv_before_exec =': 'mail_drop_priv_before_exec = yes\n',
                                       'login_trusted_networks =': '#login_trusted_networks =\n'}}
        self.servicename = 'dovecot'

    def setredhat(self):
        '''set redhat sepcific variables


        :returns: void
        @author: Breen Malmberg

        '''

        self.redhat = True
        self.osdetected = True
        self.pkgdict = {'dovecot': False}

        # the following dictionary is of the format:
        # {configfilepath1: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2},
        # configfilepath2: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2}
        # }
        self.confpathdict = {'/etc/dovecot/dovecot.conf': {'protocols =': 'protocols = ' + str(self.reqprots) + '\n',
                                       'disable_plaintext_auth =': 'disable_plaintext_auth = yes\n',
                                       'login_process_per_connection =': 'login_process_per_connection = yes\n',
                                       'mail_drop_priv_before_exec =': 'mail_drop_priv_before_exec = yes\n',
                                       'login_trusted_networks =': '#login_trusted_networks =\n'}}
        self.servicename = 'dovecot'

    def setsuse(self):
        '''set suse specific variables


        :returns: void
        @author: Breen Malmberg

        '''

        self.suse = True
        self.osdetected = True
        self.pkgdict = {'dovecot': False}

        # the following dictionary is of the format:
        # {configfilepath1: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2},
        # configfilepath2: {partialmatch1: fullreplacement1,
        #                    partialmatch2: fullreplacement2}
        # }
        self.confpathdict = {'/etc/dovecot/dovecot.conf': {'protocols =': 'protocols = ' + str(self.reqprots) + '\n',
                                       'disable_plaintext_auth =': 'disable_plaintext_auth = yes\n',
                                       'login_process_per_connection =': 'login_process_per_connection = yes\n',
                                       'mail_drop_priv_before_exec =': 'mail_drop_priv_before_exec = yes\n',
                                       'login_trusted_networks =': '#login_trusted_networks =\n'}}
        self.servicename = 'dovecot'

    def getFileContents(self, filepath):
        '''

        :param filepath: 

        '''

        filecontents = []

        try:

            if not isinstance(filepath, str):
                self.logger.log(LogPriority.DEBUG, "Parameter filepath must be of type: str")
            if not filepath:
                self.logger.log(LogPriority.DEBUG, "Parameter filepath must not be blank")

            if not os.path.exists(filepath):
                self.logger.log(LogPriority.DEBUG, "Specified filepath not found")
            else:
                f = open(filepath, 'r')
                filecontents = f.readlines()
                f.close()

            if not filecontents:
                self.logger.log(LogPriority.DEBUG, "Specified file had no contents")

        except Exception:
            raise
        return filecontents

    def searchContents(self, regex, contents):
        '''

        :param regex: 
        :param contents: 

        '''

        retval = False

        try:

            if not isinstance(regex, str):
                self.logger.log(LogPriority.DEBUG, "Parameter regex must be of type: str")
                retval = False
                return retval
            if not isinstance(contents, list):
                self.logger.log(LogPriority.DEBUG, "Parameter contents must be of type: list")
                retval = False
                return retval

            if not regex:
                self.logger.log(LogPriority.DEBUG, "regex must not be blank")
                retval = False
                return retval
            if not contents:
                self.logger.log(LogPriority.DEBUG, "contents must not be blank")
                retval = False
                return retval

            for line in contents:
                if re.search(regex, line):
                    retval = True

        except Exception:
            raise
        return retval

    def fixContents(self, fixdict, filepath, contents):
        '''

        :param fixdict: 
        :param filepath: 
        :param contents: 

        '''

        retval = True

        if not isinstance(fixdict, dict):
            self.logger.log(LogPriority.DEBUG, "Parameter fixdict must be of type: dict")
            retval = False
            return retval
        if not isinstance(filepath, str):
            self.logger.log(LogPriority.DEBUG, "Parameter filepath must be of type: str")
            retval = False
            return retval
        if not isinstance(contents, list):
            self.logger.log(LogPriority.DEBUG, "Parameter contents must be of type: list")
            retval = False
            return retval

        if not fixdict:
            self.logger.log(LogPriority.DEBUG, "Parameter fixdict must not be empty")
            retval = False
            return retval
        if not filepath:
            self.logger.log(LogPriority.DEBUG, "Parameter filepath must not be blank")
            retval = False
            return retval
        if not contents:
            self.logger.log(LogPriority.DEBUG, "Parameter contents must not be empty")
            retval = False
            return retval

        contentdict = {}
        for item in fixdict:
            contentdict[item] = False

        tempfilepath = filepath + '.stonixtmp'

        for line in contents:
            for partialmatch in fixdict:
                if re.search(partialmatch, line):
                    contents = [c.replace(line, fixdict[partialmatch]) for c in contents]
                    contentdict[partialmatch] = True

        for item in contentdict:
            if not contentdict[item]:
                contents.append('\n' + fixdict[item])

        tf = open(tempfilepath, 'w')
        tf.writelines(contents)
        tf.close()

        event = {'eventtype': 'conf',
                 'filepath': filepath}
        myid = iterate(self.iditerator, self.rulenumber)

        self.statechglogger.recordchgevent(myid, event)
        self.statechglogger.recordfilechange(filepath, tempfilepath, myid)

        os.rename(tempfilepath, filepath)

    def report(self):
        '''return true if all check actions report compliant
        return false if one or more check actions reports not compliant


        :returns: self.compliant

        :rtype: bool
@author: Breen Malmberg

        '''

        self.compliant = True
        self.detailedresults = ''
        self.logger.log(LogPriority.DEBUG, "Entering SecurePOPIMAP.report()...")

        try:

            self.reqprots = self.reqprotocols.getcurrvalue()

            if self.suse:
                self.setsuse()
            if self.debian:
                self.setdebian()
            if self.redhat:
                self.setredhat()

            self.logger.log(LogPriority.DEBUG, "Checking init objects...")
            if not self.checkinitobjs():
                self.logger.log(LogPriority.DEBUG, 'One or more class properties were not initialized or set correctly.')
                self.rulesuccess = False
                self.compliant = False
                self.formatDetailedResults("report", self.compliant, self.detailedresults)
                self.logdispatch.log(LogPriority.INFO, self.detailedresults)
                return self.compliant
            self.logger.log(LogPriority.DEBUG, "Finished checking init objects. all were OK")

            # disable stuff
            if self.disableci.getcurrvalue():
                self.logger.log(LogPriority.DEBUG, "The disable POP/IMAP option is set. Checking if POP/IMAP is disabled...")
                self.logger.log(LogPriority.DEBUG, "Checking for running service...")
                if not self.checksvc():
                    self.compliant = False
                    self.detailedresults += "\nRule is not compliant because: The " + str(self.servicename) + " service is either running or enabled."
                self.logger.log(LogPriority.DEBUG, "Service check finished.")

                self.logger.log(LogPriority.DEBUG, "Checking packages...")
                if not self.checkpkgs(False):
                    self.compliant = False
                    self.detailedresults += "\nRule is not compliant because one or more of the packages is still installed."
                self.logger.log(LogPriority.DEBUG, "Package check finished.")

            # secure stuff
            elif self.secureci.getcurrvalue():
                self.logger.log(LogPriority.DEBUG, "The secure POP/IMAP option is set. Checking if POP/IMAP is secured...")
                if not self.reqprots:
                    self.detailedresults += '\nRequired protocols were not specified. Cannot securely configure POP/IMAP without them.'
                    self.compliant = False
                slist = self.reqprots.split()
                if slist:
                    for prot in slist:
                        if prot.strip() != '' and prot.strip() not in self.protocollist:
                            self.detailedresults += "\nRule is not compliant because: The specified protocol: " + str(prot) + " is not a valid protocol."
                            self.compliant = False
                else:
                    self.detailedresults += '\nUnable to read protocol list. Please use a space-delimited list when specifying your required protocols.'
                self.logger.log(LogPriority.DEBUG, "The secure POP/IMAP option is set. Checking if POP/IMAP is secured...")
                if self.checkpkgs(True):
                    self.logger.log(LogPriority.DEBUG, "Required packages are installed.")
                    self.logger.log(LogPriority.DEBUG, " Checking file configuration...")
                    if not self.checkconfig():
                        self.compliant = False
                    self.logger.log(LogPriority.DEBUG, "File configuration check finished.")
                else:
                    self.logger.log(LogPriority.DEBUG, "One or more required packages are not installed.")
                    self.compliant = False
                    self.detailedresults += "\nRule is not compliant because one or more of the required packages are not installed."

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.detailedresults += traceback.format_exc()
            self.rulesuccess = False
            self.logger.log(LogPriority.ERROR, self.detailedresults)
        self.formatDetailedResults("report", self.compliant, self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return self.compliant

    def checkinitobjs(self):
        '''validate each class property and object to be used in this class before it is used
        return True if each object is properly assigned/initialized
        return False if not


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True

        try:

            if not self.pkgh:
                retval = False
                self.logger.log(LogPriority.DEBUG, "The package helper object was not initialized correctly")
            if not self.svch:
                retval = False
                self.logger.log(LogPriority.DEBUG, "The service helper object was not initialized correctly")
            if not self.cmdh:
                retval = False
                self.logger.log(LogPriority.DEBUG, "The command helper object was not initialized correctly")
            if not self.osdetected:
                retval = False
                self.logger.log(LogPriority.DEBUG, "Unable to determine OS type or package manager")
            if not self.servicename:
                retval = False
                self.logger.log(LogPriority.DEBUG, "servicename variable was not set")
            if not self.pkgdict:
                retval = False
                self.logger.log(LogPriority.DEBUG, "pgkdict variable was not set")
            if not self.confpathdict:
                retval = False
                self.logger.log(LogPriority.DEBUG, "confpathdict variable was not set")

        except AttributeError:
            retval = False
            self.logger.log(LogPriority.DEBUG, "One or more of the class variables are undefined")
            return retval
        return retval

    def checksvc(self):
        '''check to see if the dovecot service is enabled or running
        return False if it is either running or enabled
        if the service is neither running nor enabled, return True


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True
        enabled = False
        running = False

        try:

            if self.svch.auditService(self.servicename, _="_"):
                enabled = True
                self.detailedresults += '\nThe ' + str(self.servicename) + ' service is still enabled'
            if enabled:
                self.detailedresults += "\nThere are service(s) which need to be disabled"
            if self.svch.isRunning(self.servicename, _="_"):
                running = False
                self.detailedresults += '\nThe ' + str(self.servicename) + ' service is still running'
            if running:
                self.detailedresults += "\nThere are service(s) which need to be stopped"

            if enabled | running:
                retval = False

        except Exception:
            raise
        return retval

    def checkpkgs(self, desired):
        '''check compliance of packages portion of rule
        
        if desired, check if all required packages are installed:
            True if yes, False if no
        
        if not desired, check if any packages are installed:
            True if no, False if yes

        :param desired: 
        :returns: retval
        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True

        try:

            if not desired:
                for pkg in self.pkgdict:
                    if self.pkgh.check(pkg):
                        self.pkgdict[pkg] = True
                        retval = False
            else:
                for pkg in self.pkgdict:
                    if not self.pkgh.check(pkg):
                        self.pkgdict[pkg] = False
                        retval = False

        except Exception:
            raise
        return retval

    def checkconfig(self):
        '''verify configuration state of file(s)


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True
        contents = []

        try:

            for path in self.confpathdict:
                contents = self.getFileContents(path)
                if contents:
                    for confitem in self.confpathdict[path]:
                        if not self.searchContents(str(self.confpathdict[path][confitem]), contents):
                            retval = False
                            self.detailedresults += "\nRequired configuration option: " + str(self.confpathdict[path][confitem]) + " was not found in file: " + str(path)

                else:
                    self.logger.log(LogPriority.DEBUG, "Unable to check contents of file: " + str(path))

                if retval:
                    self.detailedresults += "\nAll required configuration options have been found in file: " + str(path)

            if retval:
                self.detailedresults += "\nAll required configuration options have been found in all required configuration files"

        except Exception:
            raise
        return retval

    def fix(self):
        '''run each fix action and get the success results of each one
        return True if all fix actions succeeded
        return False if not


        :returns: fixsuccess

        :rtype: bool
@author: Breen Malmberg

        '''

        fixsuccess = True
        self.detailedresults = ''
        self.iditerator = 0

        try:

            if self.disableci.getcurrvalue():
                self.detailedresults += '\nYou have selected the DisablePOPIMAP option. It will now be disabled/removed from this system.'
                if not self.turnoffsvc():
                    fixsuccess = False
                if not self.removePackages():
                    fixsuccess = False
            elif self.secureci.getcurrvalue():
                self.detailedresults += '\nYou have selected the SecurePOPIMAP option. It will now be installed (if it is not already installed) and then securely configured.'
                if not self.installPackages():
                    fixsuccess = False
                if not self.configurefiles():
                    fixsuccess = False

        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            self.detailedresults += traceback.format_exc()
            self.rulesuccess = False
            self.logger.log(LogPriority.ERROR, self.detailedresults)
        self.formatDetailedResults("fix", fixsuccess, self.detailedresults)
        self.logdispatch.log(LogPriority.INFO, self.detailedresults)
        return fixsuccess

    def turnoffsvc(self):
        '''disable dovecot service if it is enabled
        return True if dovecot service was successfully disabled or is not enabled
        return False if otherwise


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        self.logger.log(LogPriority.DEBUG, "Attempting to disable service: " + str(self.servicename))

        retval = True

        try:

            self.svch.disableService(self.servicename, _="_")

            if self.svch.auditService(self.servicename, _="_"):
                retval = False
                self.logger.log(LogPriority.DEBUG, "Service is still enabled after executing disableservice!")

            if self.svch.isRunning(self.servicename, _="_"):
                retval = False
                self.logger.log(LogPriority.DEBUG, "Service is still running after executing disableservice!")

            if retval:
                self.logger.log(LogPriority.DEBUG, "Successfully disabled service: " + str(self.servicename))
            else:
                self.logger.log(LogPriority.DEBUG, "Failed to disable service: " + str(self.servicename))

        except Exception:
            raise
        return retval

    def removePackages(self):
        '''Remove all packages in self.pkgdict, which are currently installed
        return True if all installed packages were successfully removed
        return False if not


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True

        try:

            for pkg in self.pkgdict:
                if self.pkgdict[pkg]:
                    if not self.pkgh.remove(pkg):
                        retval = False
                        self.detailedresults += '\nFailed to remove package: ' + str(pkg)
                    else:
                        self.pkgdict[pkg] = False

            if not retval:
                self.logger.log(LogPriority.DEBUG, "Failed to remove packages")
            else:
                self.logger.log(LogPriority.DEBUG, "Successfully removed all packages")

        except Exception:
            raise
        return retval

    def configurefiles(self):
        '''set the correct configuration options within the dovecot configuration file(s)


        :returns: void
        @author: Breen Malmberg

        '''

        try:

            for path in self.confpathdict:
                contents = self.getFileContents(path)
                self.fixContents(self.confpathdict[path], path, contents)

        except Exception:
            raise

    def installPackages(self):
        '''install all necessary dovecot packages


        :returns: retval

        :rtype: bool
@author: Breen Malmberg

        '''

        retval = True

        self.logger.log(LogPriority.DEBUG, "Attempting to install all necessary packages...")

        try:

            for pkg in self.pkgdict:
                if not self.pkgdict[pkg]:
                    if not self.pkgh.install(pkg):
                        retval = False
                        self.detailedresults += '\nFailed to install package ' + str(pkg)
                        self.logger.log(LogPriority.DEBUG, "Failed to install package: " + str(pkg))

            if not retval:
                self.logger.log(LogPriority.DEBUG, "Failed to install one or more required packages. Please check your connection to the network and ensure that your package repositories are correctly configured.")
            else:
                self.logger.log(LogPriority.DEBUG, "Successfully installed all required packages")

        except Exception:
            raise
        return retval